Merge pull request 'Web to Mobile Design' (#261) from PushMainVM into main

Reviewed-on: Pozomind/pozo-retail-app#261
This commit is contained in:
karthikalakshmi 2026-03-09 10:48:27 +05:30
commit 08336219e0
25 changed files with 10572 additions and 10571 deletions

View File

@ -1,4 +1,4 @@
import { useEffect, lazy, Suspense, useRef, useState } from 'react'; import { useEffect, lazy, Suspense, useRef, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import { App as CapacitorApp } from '@capacitor/app'; import { App as CapacitorApp } from '@capacitor/app';
import { Routes, Route } from 'react-router-dom'; import { Routes, Route } from 'react-router-dom';
@ -20,7 +20,6 @@ const IndividualBooking = lazy(
const commonSubDir = import.meta.env.ENV_COMMON_BASE_URL; const commonSubDir = import.meta.env.ENV_COMMON_BASE_URL;
const subDirectory = import.meta.env.ENV_BASE_URL; const subDirectory = import.meta.env.ENV_BASE_URL;
import '../ownLib/my-ui-lib.css'; import '../ownLib/my-ui-lib.css';
import CardSkeleton from './Components/Skeleton/CardSkeleton.jsx';
import CustomerMenuPage from './Pages/Reports/MenuQRCode/CustomerMenuPage.jsx'; import CustomerMenuPage from './Pages/Reports/MenuQRCode/CustomerMenuPage.jsx';
import WeightScaleApp from './Pages/BookingScreen/WeightscaleApp.jsx'; import WeightScaleApp from './Pages/BookingScreen/WeightscaleApp.jsx';
import useSubscriptionManager from './useSubscriptionManager.js'; import useSubscriptionManager from './useSubscriptionManager.js';
@ -52,7 +51,7 @@ const AppRoutes = () => {
} = useSubscriptionManager(sessionData, logout); } = useSubscriptionManager(sessionData, logout);
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const [devToolsOpen, setDevToolsOpen] = useState(false); const [devToolsOpen, setDevToolsOpen] = useState(false);
// Flag to prevent stack push when back button navigates // Flag to prevent stack push when back button navigates
const isBackNav = useRef(false); const isBackNav = useRef(false);
@ -189,47 +188,46 @@ const AppRoutes = () => {
} catch (err) {} } catch (err) {}
}; };
}, [navigate, location.pathname, location.search]); }, [navigate, location.pathname, location.search]);
// mohan // mohan
useEffect(() => { useEffect(() => {
if (isMobile || isIOS) { if (isMobile || isIOS) {
console.log("📱 Mobile/iOS device → skipping DevTools detection"); console.log('📱 Mobile/iOS device → skipping DevTools detection');
return; return;
}
const checkDevTools = setInterval(() => {
if (devtools.isOpen && !devToolsOpen) {
setDevToolsOpen(true);
document.body.innerHTML =
"<h1 style='color: red; text-align: center;'>Close Inspect to continue using the application.</h1>";
} else if (!devtools.isOpen && devToolsOpen) {
setDevToolsOpen(false);
setTimeout(() => {
window.location.reload();
}, 100);
clearInterval(checkDevTools);
}
if (!devtools.isOpen) {
let before = performance.now();
let after = performance.now();
let executionDelay = after - before;
if (executionDelay > 100) {
setDevToolsOpen(true);
document.body.innerHTML =
"<h1 style='color: red; text-align: center;'>Close Inspect to continue using the application.</h1>";
} else {
setDevToolsOpen(false);
} }
const checkDevTools = setInterval(() => { }
if (devtools.isOpen && !devToolsOpen) { }, 1000);
setDevToolsOpen(true);
document.body.innerHTML = return () => clearInterval(checkDevTools);
"<h1 style='color: red; text-align: center;'>Close Inspect to continue using the application.</h1>"; }, [devToolsOpen]);
}
else if (!devtools.isOpen && devToolsOpen) {
setDevToolsOpen(false);
setTimeout(() => {
window.location.reload();
}, 100);
clearInterval(checkDevTools);
}
if (!devtools.isOpen) {
let before = performance.now();
let after = performance.now();
let executionDelay = after - before;
if (executionDelay > 100) {
setDevToolsOpen(true);
document.body.innerHTML =
"<h1 style='color: red; text-align: center;'>Close Inspect to continue using the application.</h1>";
} else {
setDevToolsOpen(false);
}
}
}, 1000);
return () => clearInterval(checkDevTools);
}, [devToolsOpen]);
if (extendModel) { if (extendModel) {
return ( return (
<ExtendSubscriptionModal <ExtendSubscriptionModal
@ -240,7 +238,7 @@ const AppRoutes = () => {
); );
} }
return ( return (
<Suspense fallback={<CardSkeleton />}> <Suspense fallback={null}>
<Routes> <Routes>
<Route <Route
path={`${subDirectory}selfBooking/:SelfBookingId`} path={`${subDirectory}selfBooking/:SelfBookingId`}

View File

@ -8,7 +8,7 @@
scrollbar-width: none; scrollbar-width: none;
@media (max-width: 500px) { @media (max-width: 500px) {
overflow: scroll; overflow: auto;
} }
&.pozo-menu-vertical { &.pozo-menu-vertical {
@ -38,18 +38,18 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 7px 8px; padding: 6px 8px;
cursor: pointer; cursor: pointer;
transition: transition:
background 0.2s, background 0.2s,
color 0.2s; color 0.2s;
border-radius: 8px; border-radius: 6px;
margin: 1px 3px; margin: 1px 3px;
font-size: 13px; font-size: 13px;
font-weight: 500; font-weight: 500;
color: #ffffff; color: #ffffff;
position: relative; position: relative;
min-height: 36px; min-height: 34px;
font-family: "Poppins", sans-serif !important; font-family: "Poppins", sans-serif !important;
&:hover:not(.selected):not(.active-path) { &:hover:not(.selected):not(.active-path) {
@ -183,8 +183,8 @@
max-width: 300px; max-width: 300px;
max-height: 54vh; max-height: 54vh;
overflow-y: auto; overflow-y: auto;
animation: dropdownFadeIn 0.2s ease;
scrollbar-width: thin; scrollbar-width: thin;
animation: dropdownFadeIn 0.2s ease;
z-index: 1050 !important; z-index: 1050 !important;
// Ensure no transform interference // Ensure no transform interference

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, lazy, Suspense } from 'react'; import React, { useState, useEffect, lazy } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { Button, Popover } from 'antd'; import { Button, Popover } from 'antd';
import { AiOutlineClose } from 'react-icons/ai'; import { AiOutlineClose } from 'react-icons/ai';
@ -16,7 +16,6 @@ import { isMobile } from 'react-device-detect';
import { getTemplateData } from '../../../../../Features/ThemeChange/ThemeChange.js'; import { getTemplateData } from '../../../../../Features/ThemeChange/ThemeChange.js';
import PozoCartIcon from '../../../../../Pages/BookingScreen/Components/UtillComponents/PozoCartIcon.jsx'; import PozoCartIcon from '../../../../../Pages/BookingScreen/Components/UtillComponents/PozoCartIcon.jsx';
import TooltipWrapper from '../../../../../Components/Tooltip/Tooltip'; import TooltipWrapper from '../../../../../Components/Tooltip/Tooltip';
import BillingTableSkeleton from '../../../../../Components/Skeleton/BillingTableSkeleton.jsx';
// jsx File // jsx File
const BSBillingTable1 = lazy( const BSBillingTable1 = lazy(
() => import('../BSBillingTable1/BSBillingTable1.jsx') () => import('../BSBillingTable1/BSBillingTable1.jsx')
@ -129,132 +128,126 @@ export default function BSBTOverall1() {
}, [width]); }, [width]);
return ( return (
<Suspense fallback={<BillingTableSkeleton />}> <>
<> <div
<div className={
className={ templateData?.BookingLayout?.[0] === 'Layout6'
templateData?.BookingLayout?.[0] === 'Layout6' ? 'BSBTOverall1-Default layout6-height'
? 'BSBTOverall1-Default layout6-height' : 'BSBTOverall1-Default'
: 'BSBTOverall1-Default' }
} style={{ height: containerHeight }}
style={{ height: containerHeight }} >
> {width > 768 && <BSBillingTable1 />}
{width > 768 && <BSBillingTable1 />} {(addcustomer || hold) && (
{(addcustomer || hold) && ( <FeaturesFunctionalities
<FeaturesFunctionalities handleAddCustomerCancel={handleAddCustomerCancel}
handleAddCustomerCancel={handleAddCustomerCancel} addcustomer={addcustomer}
addcustomer={addcustomer} handleHoldCancel={handleHoldCancel}
handleHoldCancel={handleHoldCancel} modalOpen={hold}
modalOpen={hold} />
/> )}
<div className="BSBTOverall1-div">
{width <= 768 && (
<div
className={`BSBillingTable1-summeryTable ${responsiveBill ? 'open' : 'closed'}`}
style={{
transition: 'max-height 0.3s ease-in-out',
overflow: 'scroll',
maxHeight: responsiveBill ? '210px' : '0px',
}}
>
{tableData && <BSBillingTable1 />}
</div>
)} )}
<div className="BSBTOverall1-div"> <div className="BSBTOverall1-Default-summary">
{width <= 768 && ( {summeryopen == true && (
<div <div className="BSBillingTable1-summary">
className={`BSBillingTable1-summeryTable ${responsiveBill ? 'open' : 'closed'}`} <button
style={{ className="BSBillingTable1-summary-close"
transition: 'max-height 0.3s ease-in-out', onClick={() => {
overflow: 'scroll', setSummeryopen(false);
maxHeight: responsiveBill ? '210px' : '0px', }}
}} >
> X
{tableData && <BSBillingTable1 />} </button>
</div> </div>
)} )}
<div className="BSBTOverall1-Default-summary">
{summeryopen == true && ( <Popover
<div className="BSBillingTable1-summary"> content={
<button open && (
className="BSBillingTable1-summary-close" <>
onClick={() => { <a onClick={hide}>
setSummeryopen(false); <AiOutlineClose color="black" />
</a>
<BSSummery />
</>
)
}
trigger="click"
open={open}
onOpenChange={handleOpenChange}
>
<Button className="icon-button" onClick={handleOpenChange}>
SUMMARY <IoIosArrowUp />
</Button>
</Popover>
<div className="CustomerAddSrch">
<div style={{ height: '2.1rem' }}>
{tableOptions.find(
(item) => item.OptionName === 'AddCustomer'
) && (
<div
style={{
display: 'flex',
alignItems: 'center',
columnGap: '0.5rem',
}} }}
> >
X <BSCustomerSelect />
</button>
</div>
)}
<Popover <TooltipWrapper title={'Add Customer'} isMobile={isMobile}>
content={ {' '}
open && ( <PozoAddCustomerIcon
<> className="BSBillingNav-icon-table-icon"
<a onClick={hide}> onClick={handleAddCustomer}
<AiOutlineClose color="black" /> style={{
</a> fontSize: '25px',
<BSSummery /> color: selOption || GetCustId ? '#52c41a' : '#1292EE',
</> cursor: Custdisable ? 'not-allowed' : 'pointer',
) }}
} />
trigger="click" </TooltipWrapper>
open={open} </div>
onOpenChange={handleOpenChange} )}
>
<Button className="icon-button" onClick={handleOpenChange}>
SUMMARY <IoIosArrowUp />
</Button>
</Popover>
<div className="CustomerAddSrch">
<div style={{ height: '2.1rem' }}>
{tableOptions.find(
(item) => item.OptionName === 'AddCustomer'
) && (
<div
style={{
display: 'flex',
alignItems: 'center',
columnGap: '0.5rem',
}}
>
<BSCustomerSelect />
<TooltipWrapper
title={'Add Customer'}
isMobile={isMobile}
>
{' '}
<PozoAddCustomerIcon
className="BSBillingNav-icon-table-icon"
onClick={handleAddCustomer}
style={{
fontSize: '25px',
color:
selOption || GetCustId ? '#52c41a' : '#1292EE',
cursor: Custdisable ? 'not-allowed' : 'pointer',
}}
/>
</TooltipWrapper>
</div>
)}
</div>
</div> </div>
{tableData && (
<div
onClick={handleResponsiveBill}
className="Btn-responsiveBill"
style={{ color: responsiveBill ? '#52c41a' : '#1292ee' }}
>
{width <= 768 && (
<div
style={{
width: '28px',
display: 'flex',
alignItems: 'center',
height: '26px',
}}
>
<PozoCartIcon />
</div>
)}
</div>
)}
</div>
<div>
<BST1Payment />
</div> </div>
{tableData && (
<div
onClick={handleResponsiveBill}
className="Btn-responsiveBill"
style={{ color: responsiveBill ? '#52c41a' : '#1292ee' }}
>
{width <= 768 && (
<div
style={{
width: '28px',
display: 'flex',
alignItems: 'center',
height: '26px',
}}
>
<PozoCartIcon />
</div>
)}
</div>
)}
</div>
<div>
<BST1Payment />
</div> </div>
</div> </div>
</> </div>
</Suspense> </>
); );
} }

View File

@ -3,8 +3,7 @@ import React, {
useEffect, useEffect,
useState, useState,
useRef, useRef,
lazy, lazy,
Suspense,
} from 'react'; } from 'react';
import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -214,8 +213,7 @@ import CardPopover from '../StandardTable/Utils/CardPopover.jsx';
import UpiPopover from '../StandardTable/Utils/UpiPopOver.jsx'; import UpiPopover from '../StandardTable/Utils/UpiPopOver.jsx';
import MobileMultiPdfPrintTrigger from '../../UtillComponents/MobileMultiPdfPrintTrigger.jsx'; import MobileMultiPdfPrintTrigger from '../../UtillComponents/MobileMultiPdfPrintTrigger.jsx';
import { useDateStore } from '../../../../../Features/BookingScreen/BookingData/DateStore.js'; import { useDateStore } from '../../../../../Features/BookingScreen/BookingData/DateStore.js';
import BillingTableSkeleton from '../../../../../Components/Skeleton/BillingTableSkeleton.jsx'; import CustomerMobileNumberModal from '../../BookingFunctionality/CustomerOTP.jsx';
import CustomerMobileNumberModal from '../../BookingFunctionality/CustomerOTP.jsx';
const PaymentGatewayEmbedded = lazy( const PaymentGatewayEmbedded = lazy(
() => import('../../UtillComponents/PaymentGatewayEmbedded.jsx') () => import('../../UtillComponents/PaymentGatewayEmbedded.jsx')
); );
@ -3631,8 +3629,7 @@ const BSBillingTable3Pay = () => {
(arr) => Array.isArray(arr) && arr.some((err) => err) (arr) => Array.isArray(arr) && arr.some((err) => err)
); );
}; };
return ( return (
<Suspense fallback={<BillingTableSkeleton />}>
<> <>
<div className="BSBilling3PayMaster"> <div className="BSBilling3PayMaster">
{screenwidth <= 768 && ( {screenwidth <= 768 && (
@ -4969,8 +4966,7 @@ const BSBillingTable3Pay = () => {
HandleCloseModal={() => setCustomerOtpmodalopen(false)} HandleCloseModal={() => setCustomerOtpmodalopen(false)}
/> />
)} )}
</> </>
</Suspense>
); );
}; };

View File

@ -15,13 +15,11 @@ import {
PreferenceData, PreferenceData,
} from '../../../../Features/BookingScreen/BookingData/BookingData'; } from '../../../../Features/BookingScreen/BookingData/BookingData';
import { ExtractDateFormate } from '../../../../Services/Others'; import { ExtractDateFormate } from '../../../../Services/Others';
import { RiArchiveLine } from 'react-icons/ri';
import { AiFillAlert } from 'react-icons/ai'; import { AiFillAlert } from 'react-icons/ai';
import { TbAlertTriangleFilled } from 'react-icons/tb';
import { IoEye } from 'react-icons/io5'; import { IoEye } from 'react-icons/io5';
import { DefaultModal } from '../../../../Components/Modal/DefaultModal'; import { DefaultModal } from '../../../../Components/Modal/DefaultModal';
import { Tables } from '../../../../Components/Tables/Table'; import { Tables } from '../../../../Components/Tables/Table';
import '../../../../Styles/OverAllStyle/OverAllStyle.scss'; import '../../../../Styles/OverAllStyle/OverAllStyle.scss';
const NoDataComponent = () => ( const NoDataComponent = () => (
<div style={{ textAlign: 'center', padding: 20 }}> <div style={{ textAlign: 'center', padding: 20 }}>
@ -351,25 +349,31 @@ const BSExpireProductsList = () => {
messageData={message.data} messageData={message.data}
onComplete={onComplete} onComplete={onComplete}
/> />
<div
style={{
display: 'flex',
justifyContent: 'space-between',
marginTop: '20px',
}}
>
<Segmented
value={selectedSegment}
onChange={onChangeSegment}
style={{ marginBottom: 16 }}
options={[
{
label: 'Low Stock',
value: 'lowStock',
icon: <Badge count={lowStockList?.length || 0} />,
},
{
label: 'Expired',
value: 'expired',
icon: <Badge count={expiredList?.length || 0} />,
},
]}
/>
<Segmented
value={selectedSegment}
onChange={onChangeSegment}
style={{ marginBottom: 16 }}
options={[
{
label: 'Low Stock',
value: 'lowStock',
icon: <Badge count={lowStockList?.length || 0} />,
},
{
label: 'Expired',
value: 'expired',
icon: <Badge count={expiredList?.length || 0} />,
},
]}
/>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Search <Search
placeholder={`Search ${selectedSegment === 'expired' ? 'Expired' : 'Low Stock'} Products`} placeholder={`Search ${selectedSegment === 'expired' ? 'Expired' : 'Low Stock'} Products`}
onSearchChange={(e) => onSearchChange={(e) =>
@ -381,7 +385,7 @@ const BSExpireProductsList = () => {
</div> </div>
<Table <Table
className='LowStockAlterModalTable' className="LowStockAlterModalTable"
rowKey="InwardDtlId" rowKey="InwardDtlId"
columns={ columns={
selectedSegment === 'expired' ? expiredColumns : lowStockColumns selectedSegment === 'expired' ? expiredColumns : lowStockColumns

View File

@ -328,7 +328,7 @@ const BSLayout2 = () => {
setListOfInvoices(false); setListOfInvoices(false);
}; };
return ( return (
<Suspense fallback={<CardSkeleton />}> <Suspense fallback={<CardSkeleton />}>
<> <>
<Messages <Messages
messageType={messageType} messageType={messageType}
@ -684,7 +684,7 @@ const BSLayout2 = () => {
<LayoutSubCategoryFetcher /> <LayoutSubCategoryFetcher />
</> </>
</Suspense> </Suspense>
); );
}; };

View File

@ -21,7 +21,11 @@ const RetailBookingClosing = (props) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const UserType = getSession('UserType'); const UserType = getSession('UserType');
const preferenceDatas = useSelector(PreferenceData); const preferenceDatas = useSelector(PreferenceData);
const allowDecimal = preferenceDatas?.[0]?.SettingDtlDetails?.find((setting) => setting?.SettingIdName?.toLowerCase() === "decimal" && setting?.SettingValue === 'Y'); const allowDecimal = preferenceDatas?.[0]?.SettingDtlDetails?.find(
(setting) =>
setting?.SettingIdName?.toLowerCase() === 'decimal' &&
setting?.SettingValue === 'Y'
);
const CompId = getSession('CompId'); const CompId = getSession('CompId');
const AppId = getSession('AppId'); const AppId = getSession('AppId');
const UserId = getSession('UserId'); const UserId = getSession('UserId');
@ -298,39 +302,42 @@ const RetailBookingClosing = (props) => {
title={'Booking Close'} title={'Booking Close'}
handleCancel={props.PaymentClose} handleCancel={props.PaymentClose}
footer={false} footer={false}
width={700} width={750}
children={ children={
<div className="PaymentClosingOverAll"> <div className="PaymentClosingOverAll">
<div style={{ display: 'flex', justifyContent: 'space-between' }}> <div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div className="PaymentClosingOverAll-sub"> <div className="PaymentClosingOverAll-sub">
<div> <div className="ClosepayBTN">
{' '} <p> Received Amount </p>
Received Amount ={' '} <div>= </div>
<span style={{ color: '#28AA3A', cursor: 'pointer' }}> <span style={{ color: '#28AA3A', cursor: 'pointer' }}>
{safeRound(PaymentClosingData?.ReceivedAmount)} {safeRound(PaymentClosingData?.ReceivedAmount)}
</span> </span>
</div> </div>
<div> <div className="ClosepayBTN">
Cash Amount ={' '} <p> Cash Amount</p>
<div>= </div>
<span style={{ color: '#28AA3A', cursor: 'pointer' }}> <span style={{ color: '#28AA3A', cursor: 'pointer' }}>
{safeRound(PaymentClosingData?.OverAllCashAmount)} {safeRound(PaymentClosingData?.OverAllCashAmount)}
</span> </span>
</div> </div>
<div> <div className="ClosepayBTN">
Card Amount ={' '} <p> Card Amount</p>
<div>=</div>
<span style={{ color: '#28AA3A', cursor: 'pointer' }}> <span style={{ color: '#28AA3A', cursor: 'pointer' }}>
{safeRound(PaymentClosingData?.OverAllCardAmount)} {safeRound(PaymentClosingData?.OverAllCardAmount)}
</span> </span>
</div> </div>
<div> <div className="ClosepayBTN">
UPI Amount ={' '} <p>UPI Amount</p>
<div>=</div>
<span style={{ color: '#28AA3A', cursor: 'pointer' }}> <span style={{ color: '#28AA3A', cursor: 'pointer' }}>
{safeRound(PaymentClosingData?.OverAllUpiAmount)} {safeRound(PaymentClosingData?.OverAllUpiAmount)}
</span> </span>
</div> </div>
<div className="ClosepayBTN">
<div> <p> Total Cash In Hand</p>
Total Cash In Hand ={' '} <div>=</div>
<span style={{ color: '#28AA3A' }}> <span style={{ color: '#28AA3A' }}>
{safeRound(TotalCashInHand)} {safeRound(TotalCashInHand)}
</span> </span>

View File

@ -68,10 +68,19 @@
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
font-family: "Poppins"; font-family: "Poppins";
width: 250px; width: 300px;
div { margin-top: 10px;
display: flex; }
align-items: center;
justify-content: space-between; .ClosepayBTN {
display: flex;
align-items: center;
justify-content: space-between;
p {
width: 150px;
}
span {
width: 50px;
text-align: right;
} }
} }

View File

@ -1,10 +1,18 @@
import React, { useState, useEffect, useRef, useCallback } from 'react'; import React, { useState, useEffect, useRef, useCallback } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { ImWarning } from "react-icons/im"; import { ImWarning } from 'react-icons/im';
import { Form, Table, Input, Select, AutoComplete, Button, Tooltip } from 'antd'; import {
import { BsUpcScan } from "react-icons/bs"; Form,
import { FaLink } from "react-icons/fa"; Table,
Input,
Select,
AutoComplete,
Button,
Tooltip,
} from 'antd';
import { BsUpcScan } from 'react-icons/bs';
import { FaLink } from 'react-icons/fa';
import { import {
DeleteFilled, DeleteFilled,
ArrowRightOutlined, ArrowRightOutlined,
@ -13,7 +21,12 @@ import {
import { Messages } from '../../Components/Notifications/Messages.jsx'; import { Messages } from '../../Components/Notifications/Messages.jsx';
import { InputField } from '../../Components/Forms/InputField.jsx'; import { InputField } from '../../Components/Forms/InputField.jsx';
import Buttons from '../../Components/Forms/Buttons.jsx'; import Buttons from '../../Components/Forms/Buttons.jsx';
import { getSession, pdfDiv, printDiv, validateSafeInput } from '../../Services/Others'; import {
getSession,
pdfDiv,
printDiv,
validateSafeInput,
} from '../../Services/Others';
import FormHeader from '../PageComponents/FormHeader.jsx'; import FormHeader from '../PageComponents/FormHeader.jsx';
import { DropDowns } from '../../Components/Forms/DropDown.jsx'; import { DropDowns } from '../../Components/Forms/DropDown.jsx';
import { CiBarcode } from 'react-icons/ci'; import { CiBarcode } from 'react-icons/ci';
@ -32,14 +45,17 @@ import {
getEmpAccess, getEmpAccess,
} from '../../Features/AppPage/CenterPage.js'; } from '../../Features/AppPage/CenterPage.js';
import { useAuth } from '../../AuthContext.jsx'; import { useAuth } from '../../AuthContext.jsx';
import { getAllCustomer, getPreferenceData } from '../../Features/BookingScreen/BookingData/BookingData.js'; import {
getAllCustomer,
getPreferenceData,
} from '../../Features/BookingScreen/BookingData/BookingData.js';
const subDirectory = import.meta.env.BASE_URL; const subDirectory = import.meta.env.BASE_URL;
import TooltipWrapper from '../../Components/Tooltip/Tooltip'; import TooltipWrapper from '../../Components/Tooltip/Tooltip';
import { FaEye, FaPrint } from 'react-icons/fa'; import { FaEye, FaPrint } from 'react-icons/fa';
import { MdOutlineMail } from 'react-icons/md'; import { MdOutlineMail } from 'react-icons/md';
import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx'; import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx';
import FloatLabel from '../../Components/Forms/FloatLabel/index.jsx'; import FloatLabel from '../../Components/Forms/FloatLabel/index.jsx';
import { debounce } from "lodash"; import { debounce } from 'lodash';
import { getPrintSelectionComponentData } from '../../Features/ThemeChange/ThemeChange.js'; import { getPrintSelectionComponentData } from '../../Features/ThemeChange/ThemeChange.js';
import { PrintStyleFunction } from '../paymentpdfPage/PrintStyleFunction.js'; import { PrintStyleFunction } from '../paymentpdfPage/PrintStyleFunction.js';
import { isMobile } from 'react-device-detect'; import { isMobile } from 'react-device-detect';
@ -71,7 +87,7 @@ const SalesQuotationForm = () => {
const [SelProduct, setSelProduct] = useState(null); const [SelProduct, setSelProduct] = useState(null);
const [selectedProductName, setSelectedProductName] = useState(null); const [selectedProductName, setSelectedProductName] = useState(null);
const [productSearchText, setProductSearchText] = useState(""); const [productSearchText, setProductSearchText] = useState('');
const [scanner, setScanner] = useState(false); const [scanner, setScanner] = useState(false);
console.log(SelTaxTypeName, 'SelTaxTypeName'); console.log(SelTaxTypeName, 'SelTaxTypeName');
@ -95,24 +111,22 @@ const SalesQuotationForm = () => {
const [addnewAccess, setaddnewAccess] = useState(true); const [addnewAccess, setaddnewAccess] = useState(true);
const [isbarcode, setisbarcode] = useState(false); const [isbarcode, setisbarcode] = useState(false);
const [isSubmitted, setIsSubmitted] = useState(false); const [isSubmitted, setIsSubmitted] = useState(false);
const [usrMailDataModel, setusrMailDataModel] = useState(false) const [usrMailDataModel, setusrMailDataModel] = useState(false);
const [EnteredMailId, setEnteredMailId] = useState(null); const [EnteredMailId, setEnteredMailId] = useState(null);
const [PrintTempData, setPrintTempData] = useState([]); const [PrintTempData, setPrintTempData] = useState([]);
console.log(TableData, 'TableData'); console.log(TableData, 'TableData');
const items = [ const items = [
{ {
name: 'Home', name: 'Home',
link: `${subDirectory}app-page/home`, link: `${subDirectory}app-page/home`,
}, },
{ {
name: 'Sales Quotation', name: 'Sales Quotation',
link: `${subDirectory}setting/sales-quotation`, link: `${subDirectory}setting/sales-quotation`,
}, },
]; ];
// const QuotationStylepdf = `<style> // const QuotationStylepdf = `<style>
// * { // * {
// box-sizing: border-box; // box-sizing: border-box;
@ -242,12 +256,12 @@ const SalesQuotationForm = () => {
// } // }
// .Quo-Print-Content{ // .Quo-Print-Content{
// display:flex; // display:flex;
// flex-direction:column; // flex-direction:column;
// height:95vh; // height:95vh;
// width:93vw; // width:93vw;
// border:0.5px solid rgb(170, 164, 164); // border:0.5px solid rgb(170, 164, 164);
// margin:2rem 1rem 1rem 1rem; // margin:2rem 1rem 1rem 1rem;
// gap:1.5rem; // gap:1.5rem;
// page-break-after: always; // page-break-after: always;
@ -266,7 +280,7 @@ const SalesQuotationForm = () => {
// .Quo-Print-Tabsum{ // .Quo-Print-Tabsum{
// display:flex; // display:flex;
// flex-direction:column; // flex-direction:column;
// justify-content:space-between; // justify-content:space-between;
// gap:1rem; // gap:1rem;
// height:60vh; // height:60vh;
// } // }
@ -371,7 +385,6 @@ const SalesQuotationForm = () => {
// font-size:20px; // font-size:20px;
// } // }
// } // }
// </style>`; // </style>`;
@ -559,15 +572,15 @@ const SalesQuotationForm = () => {
); );
if (matchedProduct) { if (matchedProduct) {
let productName = {}; let productName = {};
productName.label = `${matchedProduct?.ProdName} (${matchedProduct.Size} ${matchedProduct.UomName})${matchedProduct?.BrandName ? ` - ${matchedProduct?.BrandName}` : ''}` productName.label = `${matchedProduct?.ProdName} (${matchedProduct.Size} ${matchedProduct.UomName})${matchedProduct?.BrandName ? ` - ${matchedProduct?.BrandName}` : ''}`;
ProductDropDownChange(matchedProduct.ProdId, productName); ProductDropDownChange(matchedProduct.ProdId, productName);
if (matchedProduct?.ProdVariantPriceDetails?.length < 2) { if (matchedProduct?.ProdVariantPriceDetails?.length < 2) {
setSelectedProductName(""); setSelectedProductName('');
setSelProduct(null) setSelProduct(null);
} }
} else { } else {
setMessageType("error"); setMessageType('error');
setMessageData("The Scanned Product not Available in Product List") setMessageData('The Scanned Product not Available in Product List');
} }
}, 300), }, 300),
[ProductData] [ProductData]
@ -575,12 +588,16 @@ const SalesQuotationForm = () => {
const getPreference = async () => { const getPreference = async () => {
const data = { AppId: AppId, CompId: CompId, BranchId: BranchId }; const data = { AppId: AppId, CompId: CompId, BranchId: BranchId };
const { data: res } = await dispatch(getPreferenceData(data)).unwrap() const { data: res } = await dispatch(getPreferenceData(data)).unwrap();
const decimalSetting = res?.data?.[0]?.SettingDtlDetails?.find((setting) => setting?.SettingIdName?.toLowerCase() === "decimal" && setting?.SettingValue === 'Y'); const decimalSetting = res?.data?.[0]?.SettingDtlDetails?.find(
(setting) =>
setting?.SettingIdName?.toLowerCase() === 'decimal' &&
setting?.SettingValue === 'Y'
);
if (decimalSetting) { if (decimalSetting) {
setAllowDecimal(true) setAllowDecimal(true);
} }
} };
const changebarcode = useCallback(() => { const changebarcode = useCallback(() => {
setisbarcode((prev) => !prev); setisbarcode((prev) => !prev);
}, []); }, []);
@ -621,7 +638,6 @@ const SalesQuotationForm = () => {
// Print(); // Print();
// }, [PrintData]); // }, [PrintData]);
useEffect(() => { useEffect(() => {
let total = TableData?.reduce((accumulator, currentValue) => { let total = TableData?.reduce((accumulator, currentValue) => {
return accumulator + currentValue.NetAmt; return accumulator + currentValue.NetAmt;
@ -647,7 +663,7 @@ const SalesQuotationForm = () => {
}, 0); }, 0);
setTotalBillAmount(billtotal); setTotalBillAmount(billtotal);
}, [TableData]); }, [TableData]);
const getProduct = async () => { const getProduct = async () => {
let Product = await dispatch( let Product = await dispatch(
getPurProductData({ getPurProductData({
@ -659,7 +675,9 @@ const SalesQuotationForm = () => {
).unwrap(); ).unwrap();
if (Product?.data?.statusCode === 1) { if (Product?.data?.statusCode === 1) {
let Productonlydata = Product?.data?.data?.filter( let Productonlydata = Product?.data?.data?.filter(
(item) => item?.ProdTypeName === 'Product' && (item?.StockAvailable === "Y" ? item?.BalanceQty > 0 : true) (item) =>
item?.ProdTypeName === 'Product' &&
(item?.StockAvailable === 'Y' ? item?.BalanceQty > 0 : true)
); );
setProductData(Productonlydata); setProductData(Productonlydata);
@ -684,13 +702,14 @@ const SalesQuotationForm = () => {
const Data = { AppId, CompId, BranchId }; const Data = { AppId, CompId, BranchId };
const printtemp = await dispatch(getPrintSelectionComponentData(Data)).unwrap(); const printtemp = await dispatch(
getPrintSelectionComponentData(Data)
).unwrap();
const printTypeName = printtemp?.data?.data const printTypeName = printtemp?.data?.data
?.flatMap(template => template.ComponentDetails || []) ?.flatMap((template) => template.ComponentDetails || [])
?.find( ?.find(
comp => (comp) =>
comp.SetasDefault === "Y" && comp.SetasDefault === 'Y' && comp.PrintTypeName === 'Sales Quotation'
comp.PrintTypeName === "Sales Quotation"
); );
setPrintTempData(printTypeName); setPrintTempData(printTypeName);
}; };
@ -730,7 +749,7 @@ const SalesQuotationForm = () => {
TaxAmt: TaxAmt:
taxname?.ConfigName?.toLowerCase() === 'withtax' taxname?.ConfigName?.toLowerCase() === 'withtax'
? (item?.NetAmt * parseInt(item?.TaxPercentage)) / ? (item?.NetAmt * parseInt(item?.TaxPercentage)) /
(100 + parseInt(item?.TaxPercentage))?.toFixed(2) (100 + parseInt(item?.TaxPercentage))?.toFixed(2)
: 0, : 0,
}; };
}); });
@ -739,33 +758,33 @@ const SalesQuotationForm = () => {
}; };
const handleScanSearch = () => { const handleScanSearch = () => {
if (scanner === false) { if (scanner === false) {
setMessageType("success"); setMessageType('success');
setMessageData("Search by QrCode/BarCode Enabled") setMessageData('Search by QrCode/BarCode Enabled');
} else { } else {
setMessageType("success"); setMessageType('success');
setMessageData("Search by QrCode/BarCode Disabled") setMessageData('Search by QrCode/BarCode Disabled');
} }
setScanner(prev => !prev) setScanner((prev) => !prev);
setSelectedProductName(null); setSelectedProductName(null);
setselectedProductVariantData(null); setselectedProductVariantData(null);
setVariants(null) setVariants(null);
formRef?.current?.setFieldsValue({ formRef?.current?.setFieldsValue({
ProdId: null, ProdId: null,
VarProdId: null VarProdId: null,
}); });
} };
const handleProductSearch = (value) => { const handleProductSearch = (value) => {
if (scanner) { if (scanner) {
debouncedScannerSearch(value); debouncedScannerSearch(value);
} }
setProductSearchText(value) setProductSearchText(value);
setSelectedProductName(value); setSelectedProductName(value);
setselectedProductVariantData([]); setselectedProductVariantData([]);
setVariants([]) setVariants([]);
}; };
const ProductDropDownChange = async (ProdId, option) => { const ProductDropDownChange = async (ProdId, option) => {
setProductSearchText("") setProductSearchText('');
setSelectedProductName(option?.label ? option?.label : '') setSelectedProductName(option?.label ? option?.label : '');
formRef?.current?.resetFields(['VarProdId']); formRef?.current?.resetFields(['VarProdId']);
console.log(ProductData, 'ProdIdProdId'); console.log(ProductData, 'ProdIdProdId');
@ -866,9 +885,7 @@ const SalesQuotationForm = () => {
)?.[0]?.ProdVariantName; )?.[0]?.ProdVariantName;
const ProdName1 = TableData?.some( const ProdName1 = TableData?.some(
(e) => (e) => e.ProdId == SelProduct && e.ProdVariantName === ProdName2
e.ProdId == SelProduct &&
e.ProdVariantName === ProdName2
); );
if (ProdName1) { if (ProdName1) {
setMessageType('error'); setMessageType('error');
@ -886,9 +903,7 @@ const SalesQuotationForm = () => {
// let x = VariantData1?.filter((e) => e.InwardDtlId == value); // let x = VariantData1?.filter((e) => e.InwardDtlId == value);
// let u = ProductData?.find((e) => e.ProdId == selectedProductData); // let u = ProductData?.find((e) => e.ProdId == selectedProductData);
// console.log(first) // console.log(first)
let ProductData1 = ProductData?.find( let ProductData1 = ProductData?.find((e) => e.ProdId == SelProduct);
(e) => e.ProdId == SelProduct
);
console.log(ProductData1, 'ProductData1ProductData1'); console.log(ProductData1, 'ProductData1ProductData1');
let mrp; let mrp;
let sellprice; let sellprice;
@ -988,7 +1003,7 @@ const SalesQuotationForm = () => {
title: 'Product Name', title: 'Product Name',
dataIndex: 'ProdName', dataIndex: 'ProdName',
key: 'ProdName', key: 'ProdName',
width: "230px", width: '230px',
align: 'right', align: 'right',
render: (text, record, index) => ( render: (text, record, index) => (
<a style={{ color: 'black' }}> <a style={{ color: 'black' }}>
@ -1350,10 +1365,11 @@ const SalesQuotationForm = () => {
? sellprice * parseInt(qty) ? sellprice * parseInt(qty)
: 0; : 0;
const taxamt = SelTaxTypeName?.toLowerCase() === 'withtax' const taxamt =
? (Amount * parseInt(record?.TaxPercentage)) / SelTaxTypeName?.toLowerCase() === 'withtax'
(100 + parseInt(record?.TaxPercentage)) ? (Amount * parseInt(record?.TaxPercentage)) /
: 0; (100 + parseInt(record?.TaxPercentage))
: 0;
const newData = TableData.map((item, index1) => { const newData = TableData.map((item, index1) => {
if (index1 === index) { if (index1 === index) {
return { return {
@ -1373,22 +1389,12 @@ const SalesQuotationForm = () => {
[`Qty${index}`]: qty, [`Qty${index}`]: qty,
[`NetAmt${index}`]: Amount, [`NetAmt${index}`]: Amount,
// [`ReceivedQty${index}`]: qty,
// [`AcceptedQty${index}`]: acceptedQty,
// [`RejectedQty${index}`]: qty - acceptedQty,
// ReceivedQty: qty,
// AcceptedQty: acceptedQty,
// RejectedQty: qty - acceptedQty,
[`PurcDisc${index}`]: 0, [`PurcDisc${index}`]: 0,
[`DiscType${index}`]: 'P', [`DiscType${index}`]: 'P',
}); });
}; };
const handleDiscountTypeChange = (value, record, index) => { const handleDiscountTypeChange = (value, record, index) => {
// console.log(value,"valuevalue")
// const newData1 = [...TableData];
// const item = newData1[index];
// item.DiscountType = value;
// setTableData(newData1);
const tempamt = record.Qty * record.Price; const tempamt = record.Qty * record.Price;
const DisType = value; const DisType = value;
const amount = const amount =
@ -1398,7 +1404,7 @@ const SalesQuotationForm = () => {
const taxamt = const taxamt =
SelTaxTypeName?.toLowerCase() === 'withtax' SelTaxTypeName?.toLowerCase() === 'withtax'
? (amount * parseInt(record?.TaxPercentage)) / ? (amount * parseInt(record?.TaxPercentage)) /
(100 + parseInt(record?.TaxPercentage))?.toFixed(2) (100 + parseInt(record?.TaxPercentage))?.toFixed(2)
: 0; : 0;
// You can calculate acceptedQty based on your requirement // You can calculate acceptedQty based on your requirement
const newData = TableData.map((item, index1) => { const newData = TableData.map((item, index1) => {
@ -1441,7 +1447,7 @@ const SalesQuotationForm = () => {
const taxamt = const taxamt =
SelTaxTypeName?.toLowerCase() === 'withtax' SelTaxTypeName?.toLowerCase() === 'withtax'
? (amount * parseInt(record?.TaxPercentage)) / ? (amount * parseInt(record?.TaxPercentage)) /
(100 + parseInt(record?.TaxPercentage))?.toFixed(2) (100 + parseInt(record?.TaxPercentage))?.toFixed(2)
: 0; : 0;
// You can calculate acceptedQty based on your requirement // You can calculate acceptedQty based on your requirement
const newData = TableData.map((item, index1) => { const newData = TableData.map((item, index1) => {
@ -1475,7 +1481,7 @@ const SalesQuotationForm = () => {
const taxamount = const taxamount =
SelTaxTypeName?.toLowerCase() === 'withtax' SelTaxTypeName?.toLowerCase() === 'withtax'
? (amount * parseInt(record?.TaxPercentage)) / ? (amount * parseInt(record?.TaxPercentage)) /
(100 + parseInt(record?.TaxPercentage))?.toFixed(2) (100 + parseInt(record?.TaxPercentage))?.toFixed(2)
: 0; : 0;
form.setFields([{ name: [`PurcDisc${index}`], errors: [] }]); form.setFields([{ name: [`PurcDisc${index}`], errors: [] }]);
@ -1530,23 +1536,16 @@ const SalesQuotationForm = () => {
PostData['TaxAmount'] = parseFloat( PostData['TaxAmount'] = parseFloat(
(TotalCgst + TotalSgst + TotalIgst)?.toFixed(2) (TotalCgst + TotalSgst + TotalIgst)?.toFixed(2)
); );
(PostData['CompId'] = CompId), ((PostData['CompId'] = CompId),
(PostData['BranchId'] = BranchId), (PostData['BranchId'] = BranchId),
(PostData['AppId'] = AppId); (PostData['AppId'] = AppId));
let res = await dispatch(postPurcQuotation(PostData)).unwrap(); let res = await dispatch(postPurcQuotation(PostData)).unwrap();
if (res?.data?.statusCode === 1) { if (res?.data?.statusCode === 1) {
setMessageType('success'); setMessageType('success');
setMessageData(res?.data?.response); setMessageData(res?.data?.response);
const custId = formRef.current?.getFieldValue('CustId'); const custId = formRef.current?.getFieldValue('CustId');
const customer = AllCustomer?.find(c => c.UserId === custId); const customer = AllCustomer?.find((c) => c.UserId === custId);
console.log(customer, "customertrt"); console.log(customer, 'customertrt');
// const printDataWithCustomer = {
// ...res?.data?.data,
// customerName: customer?.CustName || '',
// customerAddress: customer?.CustAddress || '',
// customerMobile: customer?.CustMobile || '',
// };
setPrintData(res?.data?.data); setPrintData(res?.data?.data);
setIsSubmitted(true); setIsSubmitted(true);
@ -1597,33 +1596,6 @@ const SalesQuotationForm = () => {
} }
}; };
// const handleSearch = (input) => {
// // Only proceed if input is not empty and isbarcode is true
// if (!input || !isbarcode) {
// return;
// }
// if (debounceRef.current) {
// clearTimeout(debounceRef.current);
// }
// debounceRef.current = setTimeout(async () => {
// const product = ProductData.find(
// (p) => p.QRCode?.toLowerCase() === input.toLowerCase()
// );
// console.log(input, 'inputinput', product);
// if (product) {
// setEditingKey('');
// await ProductDropDownChange(product.ProdId);
// setTimeout(() => {
// setSelProduct(null);
// formRef.current?.setFieldsValue({ ProdId: null });
// }, 100);
// }
// }, 300);
// };
const onChangeprodFunction = (e) => { const onChangeprodFunction = (e) => {
console.log(e, 'yyyyyyyyyyyyyy'); console.log(e, 'yyyyyyyyyyyyyy');
@ -1651,20 +1623,11 @@ const SalesQuotationForm = () => {
} }
}; };
// Add these functions inside your component, before the return statement:
// const handleEmailClick = () => {
// const subject = encodeURIComponent('Sales Quotation');
// const body = encodeURIComponent('Please find attached the purchase quotation.');
// window.open(`mailto:?subject=${subject}&body=${body}`);
// };
// const handlePrint = () => {
// printDiv('Pur-Quot-Print', QuotationStyle);
// };
// ...existing code...
const handlePrint = async () => { const handlePrint = async () => {
const style = await PrintStyleFunction( const style = await PrintStyleFunction(
PrintTempData?.StyleName == undefined ? 'Style 13' : PrintTempData?.StyleName, PrintTempData?.StyleName == undefined
? 'Style 13'
: PrintTempData?.StyleName,
'Quotation' 'Quotation'
); );
@ -1690,25 +1653,25 @@ const SalesQuotationForm = () => {
const selectedStyle = const selectedStyle =
stylesMap[ stylesMap[
PrintTempData?.StyleName == undefined ? 'Style 13' : PrintTempData?.StyleName PrintTempData?.StyleName == undefined
? 'Style 13'
: PrintTempData?.StyleName
]; ];
if (isMobile) { if (isMobile) {
PurchaseQtMobilePrint({ PurchaseQtMobilePrint({
PrintTempData: PrintTempData, PrintTempData: PrintTempData,
PrintOrderDetails: PrintData, PrintOrderDetails: PrintData,
UserId: UserId, UserId: UserId,
dispatch, dispatch,
}); });
} } else if (selectedStyle) {
else if (selectedStyle) { await printDiv(`${selectedStyle}`, style);
await printDiv(`${selectedStyle}`, style);
} }
}; };
const handleEmailClick = async (mail, data) => { const handleEmailClick = async (mail, data) => {
let record = mail == "mail" ? data : PrintData?.[0] let record = mail == 'mail' ? data : PrintData?.[0];
if (record?.Email) { if (record?.Email) {
setTimeout(async () => { setTimeout(async () => {
@ -1726,46 +1689,45 @@ const SalesQuotationForm = () => {
if (res?.data?.status === 1) { if (res?.data?.status === 1) {
setMessageData(res?.data?.response); setMessageData(res?.data?.response);
setMessageType('success'); setMessageType('success');
} } else {
else {
setMessageData(res?.data?.response); setMessageData(res?.data?.response);
setMessageType('error'); setMessageType('error');
} }
// setMessageData("Email sent successfully"); // setMessageData("Email sent successfully");
// setMessageType('success'); // setMessageType('success');
} catch (error) { } catch (error) {
console.error('❌ Email send failed:', error); console.error('❌ Email send failed:', error);
// alert(' Email failed to send'); // alert(' Email failed to send');
setMessageData("Email failed to send"); setMessageData('Email failed to send');
setMessageType('error'); setMessageType('error');
} }
}, 300); }, 300);
} else {
setusrMailDataModel(true);
} }
else {
setusrMailDataModel(true)
}
}; };
const handleUserMailmodalCancel = () => { const handleUserMailmodalCancel = () => {
setusrMailDataModel(false) setusrMailDataModel(false);
setEnteredMailId(null) setEnteredMailId(null);
emailform.resetFields(); emailform.resetFields();
// setQuotationProductdata([]) // setQuotationProductdata([])
} };
const emailSubmit = (values) => { const emailSubmit = (values) => {
let data = { ...PrintData?.[0], ...{ CustMail: values.email }, ...{ Email: values.email } }; let data = {
handleEmailClick("mail", data); ...PrintData?.[0],
...{ CustMail: values.email },
...{ Email: values.email },
};
handleEmailClick('mail', data);
setEnteredMailId(null); setEnteredMailId(null);
emailform.resetFields(); emailform.resetFields();
emailform.setFieldsValue({ email: '' }); emailform.setFieldsValue({ email: '' });
setusrMailDataModel(false); setusrMailDataModel(false);
}; };
return ( return (
<div className="pageOverAll"> <div className="pageOverAll">
<div className="userPage"> <div className="userPage">
@ -1775,11 +1737,14 @@ const SalesQuotationForm = () => {
messageData={messageData} messageData={messageData}
onComplete={onComplete} onComplete={onComplete}
/> />
<div className="formName" style={{ <div
display: 'flex', className="formName"
justifyContent: 'space-between', style={{
marginTop: '5px', display: 'flex',
}}> justifyContent: 'space-between',
marginTop: '5px',
}}
>
<FormHeader title={'Sales Quotation'} /> <FormHeader title={'Sales Quotation'} />
<div <div
style={{ style={{
@ -1793,10 +1758,12 @@ const SalesQuotationForm = () => {
cursor: 'pointer', cursor: 'pointer',
fontFamily: 'Poppins', fontFamily: 'Poppins',
fontWeight: '400', fontWeight: '400',
whiteSpace: "nowrap", whiteSpace: 'nowrap',
fontSize: "15px" fontSize: '15px',
}} }}
onClick={() => navigate(`${subDirectory}setting/sales-quotation/list`)} onClick={() =>
navigate(`${subDirectory}setting/sales-quotation/list`)
}
> >
<FaEye /> <span>View Quotation</span> <FaEye /> <span>View Quotation</span>
</div> </div>
@ -1857,129 +1824,67 @@ const SalesQuotationForm = () => {
/> />
</Form.Item> </Form.Item>
<div className="ProductDropDownChange-Quotation"> <div className="ProductDropDownChange-Quotation">
<Form.Item <Form.Item name="ProdId">
name="ProdId"
>
<div className="product-scan sales-quotation"> <div className="product-scan sales-quotation">
<FloatLabel label={"Product Name"} value={selectedProductName}> <FloatLabel
label={'Product Name'}
value={selectedProductName}
>
<AutoComplete <AutoComplete
className="field-DropDown" className="field-DropDown"
value={selectedProductName} value={selectedProductName}
filterOption={(input, option) => { filterOption={(input, option) => {
const product = ProductData.find(p => p.ProdId === option.value); const product = ProductData.find(
const nameMatch = option.label?.toLowerCase()?.includes(productSearchText?.toLowerCase()); (p) => p.ProdId === option.value
const qrMatch = product?.QRCode?.toLowerCase() == productSearchText?.toLowerCase(); );
const nameMatch = option.label
?.toLowerCase()
?.includes(productSearchText?.toLowerCase());
const qrMatch =
product?.QRCode?.toLowerCase() ==
productSearchText?.toLowerCase();
return nameMatch || qrMatch; return nameMatch || qrMatch;
}} }}
options={!scanner ? ProductData?.map options={
((option) => ({ !scanner
value: option.ProdId, ? ProductData?.map((option) => ({
label: `${option.ProdName} (${option.Size} ${option.UomName})${option?.BrandName ? ` - ${option?.BrandName}` : ''}` value: option.ProdId,
})) : []} label: `${option.ProdName} (${option.Size} ${option.UomName})${option?.BrandName ? ` - ${option?.BrandName}` : ''}`,
}))
: []
}
onSelect={ProductDropDownChange} onSelect={ProductDropDownChange}
onChange={handleProductSearch} onChange={handleProductSearch}
onKeyDown={(e) => { onKeyDown={(e) => {
if (scanner && e.key === "Enter") { if (scanner && e.key === 'Enter') {
e.preventDefault(); e.preventDefault();
} }
}} }}
disabled={ProductData?.length === 0} disabled={ProductData?.length === 0}
> ></AutoComplete>
</AutoComplete>
</FloatLabel> </FloatLabel>
<Tooltip title={"BarCode/QrCode"} placement={"top"}> <Tooltip title={'BarCode/QrCode'} placement={'top'}>
<BsUpcScan strokeWidth={0.5} color="#000" style={{ fontSize: "16px", color: scanner ? "#52c41a" : "#888", fontWeight: "600" }} className="product-scan-Icon" onClick={handleScanSearch} /> <div className="BsUpcScanSQ">
<BsUpcScan
strokeWidth={0.5}
color="#000"
style={{
fontSize: '16px',
color: scanner ? '#52c41a' : '#888',
fontWeight: '600',
}}
className="product-scan-Icon"
onClick={handleScanSearch}
/>
</div>
</Tooltip> </Tooltip>
{ProductData?.length === 0 && <p style={{ color: "red" }}><ImWarning /> All Products have no Stock</p>} {ProductData?.length === 0 && (
<p style={{ color: 'red' }}>
<ImWarning /> All Products have no Stock
</p>
)}
</div> </div>
</Form.Item> </Form.Item>
{/* <Form.Item name="ProdId">
<AutoComplete
options={ProductData?.map((option) => ({
value:
option.ProdName +
' ' +
'(' +
option.Size +
option.UomName +
')',
label:
option.ProdName +
' ' +
'(' +
option.Size +
option.UomName +
')',
qrCode: option.QRCode,
}))}
style={{ width: '250px', height: '48px' }}
onSelect={(value, option) => {
if (isbarcode && option.qrCode) {
const productByQR = ProductData.find(
(p) => p.QRCode === option.qrCode
);
if (productByQR) {
ProductDropDownChange({
value:
productByQR.ProdName +
' ' +
'(' +
productByQR.Size +
productByQR.UomName +
')',
});
}
} else {
ProductDropDownChange(option);
}
}}
filterOption={(input, option) => {
if (isbarcode) {
return (
option.qrCode &&
option.qrCode
.toLowerCase()
.includes(input.toLowerCase())
);
} else {
return option.label
.toLowerCase()
.includes(input.toLowerCase());
}
}}
value={SelProduct}
>
<InputField
label="Product Name"
style={{}}
onChange={(e) =>
onChangeprodFunction(e?.target?.value)
}
onPressEnter={(e) =>
onChangeprodFunction(e?.target?.value)
}
isOnChange={SelProduct ? true : false}
suffix={
<TooltipWrapper
title="Search Product Name"
// isMobile={isMobile}
>
<CiBarcode
style={{
fontSize: '17px',
paddingRight: '1px',
}}
color={isbarcode ? 'green' : ' '}
onClick={changebarcode}
/>
<SearchOutlined
style={{ color: 'rgba(0,0,0,.45)' }}
/>
</TooltipWrapper>
}
/>
</AutoComplete>
</Form.Item> */}
</div> </div>
</div> </div>
@ -2025,7 +1930,10 @@ const SalesQuotationForm = () => {
</div> </div>
</div> </div>
</div> </div>
<div className="QuosubmitButton" style={{ display: 'flex', gap: '1rem' }}> <div
className="QuosubmitButton"
style={{ display: 'flex', gap: '1rem' }}
>
<Buttons <Buttons
buttonText="SUBMIT" buttonText="SUBMIT"
color="901D77" color="901D77"
@ -2055,50 +1963,31 @@ const SalesQuotationForm = () => {
</div> </div>
</> </>
)} )}
</div> </div>
</Form> </Form>
{TableData?.length > 0 && ( {TableData?.length > 0 && (
<div className="Quo-Summary-Quotation"> <div className="Quo-Summary-Quotation">
<div className='Quotation-summary'> Gross Total: {allowDecimal ? TotalBillAmount?.toFixed(2) : TotalBillAmount}</div> <div className="Quotation-summary">
<div className='Quotation-summary' > Total GST: {allowDecimal ? (TotalCgst + TotalSgst + TotalIgst)?.toFixed(2) : (TotalCgst + TotalSgst + TotalIgst)}</div> {' '}
Gross Total:{' '}
{allowDecimal ? TotalBillAmount?.toFixed(2) : TotalBillAmount}
</div>
<div className="Quotation-summary">
{' '}
Total GST:{' '}
{allowDecimal
? (TotalCgst + TotalSgst + TotalIgst)?.toFixed(2)
: TotalCgst + TotalSgst + TotalIgst}
</div>
{/* <div> Total SGST: {TotalSgst?.toFixed(2)}</div> {/* <div> Total SGST: {TotalSgst?.toFixed(2)}</div>
<div> Total IGST: {TotalIgst?.toFixed(2)}</div> */} <div> Total IGST: {TotalIgst?.toFixed(2)}</div> */}
<div className='Quotation-summary'> Total Amount: {allowDecimal ? Math.round(TotalAmount)?.toFixed(2) : Math.round(TotalAmount)}</div> <div className="Quotation-summary">
{/* <table style={{ width: '300px', border: '1px solid black' }}> {' '}
<tr> Total Amount:{' '}
<td style={{ textAlign: 'right' }}>Gross Total:</td> {allowDecimal
<td style={{ textAlign: 'right' }}> ? Math.round(TotalAmount)?.toFixed(2)
: Math.round(TotalAmount)}
</td> </div>
</tr>
<tr>
<td style={{ textAlign: 'right' }}>Total CGST:</td>
<td style={{ textAlign: 'right' }}>
{TotalCgst?.toFixed(2)}
</td>
</tr>
<tr>
<td style={{ textAlign: 'right' }}>Total SGST:</td>
<td style={{ textAlign: 'right' }}>
{TotalSgst?.toFixed(2)}
</td>
</tr>
<tr>
<td style={{ textAlign: 'right' }}>Total IGST:</td>
<td style={{ textAlign: 'right' }}>
{TotalIgst?.toFixed(2)}
</td>
</tr>
<tr>
<td style={{ textAlign: 'right' }}>
Total Amount(Round Off):
</td>
<td style={{ textAlign: 'right' }}>
{Math.round(TotalAmount)?.toFixed(2)}
</td>
</tr>
</table> */}
</div> </div>
)} )}
</div> </div>
@ -2109,20 +1998,17 @@ const SalesQuotationForm = () => {
handleCancel={handleUserMailmodalCancel} handleCancel={handleUserMailmodalCancel}
footer={false} footer={false}
children={ children={
<div> <div>
<Form form={emailform} layout="vertical" onFinish={emailSubmit}> <Form form={emailform} layout="vertical" onFinish={emailSubmit}>
<Form.Item <Form.Item
label="Mail ID" label="Mail ID"
name="email" name="email"
rules={[ rules={[
{ required: true, message: "Email is required" }, { required: true, message: 'Email is required' },
{ type: "email", message: "Enter a valid email address" }, { type: 'email', message: 'Enter a valid email address' },
]} ]}
> >
<Input <Input autoComplete="off" placeholder="Enter your email" />
autoComplete="off"
placeholder="Enter your email" />
</Form.Item> </Form.Item>
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">
@ -2134,11 +2020,14 @@ const SalesQuotationForm = () => {
/> />
<div style={{ display: 'none' }}> <div style={{ display: 'none' }}>
<PurchaseQuotationPrint PrintingData={PrintData} PrintTempData={PrintTempData} /> <PurchaseQuotationPrint
PrintingData={PrintData}
PrintTempData={PrintTempData}
/>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
); );
}; };
export default SalesQuotationForm; export default SalesQuotationForm;

View File

@ -44,7 +44,7 @@
.BSBilling4-tablediv-mobile { .BSBilling4-tablediv-mobile {
display: block; display: block;
height: 40vh; height: 40vh;
overflow-y: scroll; overflow-y: auto;
} }
.BSBilling4-tablediv-mobile::-webkit-scrollbar { .BSBilling4-tablediv-mobile::-webkit-scrollbar {
@ -316,6 +316,7 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-direction: column; flex-direction: column;
gap: 4px;
} }
@media (min-width: 280px) and (max-width: 499px) { @media (min-width: 280px) and (max-width: 499px) {
@ -340,11 +341,6 @@
row-gap: 0rem; row-gap: 0rem;
} }
.Table4-price-btn-master {
flex-direction: row;
align-items: center;
}
.Table4-cash { .Table4-cash {
width: 60px !important; width: 60px !important;
} }
@ -726,8 +722,10 @@
.BSBilling4-price-content { .BSBilling4-price-content {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
width: 100vw; width: 100vw;
@media (max-width: 768px) {
width: 100% !important;
}
} }
.Table4-price-icon-container { .Table4-price-icon-container {
@ -789,3 +787,38 @@
font-weight: bold; font-weight: bold;
padding: 2px; padding: 2px;
} }
.BS7hold-sum {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
column-gap: 1rem;
color: var(--DEFAULT_SELECTED_COLOR);
}
.RowforResposiveBill7 {
display: flex;
flex-direction: column;
width: 100%;
}
.RowResposiveBill7 {
display: flex;
align-items: flex-start;
gap: 4px;
width: 100%;
}
.bsbilltable7 {
padding: 10px;
}
@media (max-width: 768px) {
.BSTable3_payroll {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}
.bsbilltable7 {
padding: 0;
}
}

View File

@ -109,7 +109,8 @@
.Btn-payment-mode { .Btn-payment-mode {
background-color: var(--SELECTED_COLOR); background-color: var(--SELECTED_COLOR);
color: #ffffff; color: #ffffff;
outline: none;border: none; outline: none;
border: none;
font-size: 12px; font-size: 12px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -318,9 +319,9 @@
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
overflow: auto; overflow: auto;
scrollbar-width: none;
width: inherit; width: inherit;
height: 85vh; height: 85vh;
scrollbar-width: none;
border-radius: 10px; border-radius: 10px;
@media (max-width: 768px) { @media (max-width: 768px) {
width: 100% !important; width: 100% !important;
@ -333,9 +334,9 @@
.BSTable3 { .BSTable3 {
overflow-y: auto; overflow-y: auto;
scrollbar-width: none;
height: 100vh; height: 100vh;
background-color: #fff; background-color: #fff;
scrollbar-width: none;
} }
.Cust-tag { .Cust-tag {

View File

@ -95,9 +95,10 @@
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
max-width: 130px; max-width: 130px;
white-space: nowrap; display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis;
} }
.BSItemCard-itemPrice { .BSItemCard-itemPrice {

View File

@ -9,7 +9,7 @@
.receipt-reprint-header { .receipt-reprint-header {
display: flex; display: flex;
align-items: center; align-items: center;
// justify-content: space-between; flex-wrap: wrap;
gap: 10px; gap: 10px;
margin-bottom: 16px; margin-bottom: 16px;
} }

View File

@ -113,7 +113,8 @@ body {
@media (max-width: 768px) { @media (max-width: 768px) {
width: 100%; width: 100%;
margin: 0.5rem; margin: 0;
padding: 0.5rem;
min-height: 200px; min-height: 200px;
} }
@ -195,7 +196,7 @@ body {
} }
} }
.BSLayout2-Master .BSBTOverall1-Default { .BSLayout2-Master .BSBTOverall1-Default {
height: 81vh; height: 81vh;
} }
@ -229,7 +230,6 @@ body {
width: 100%; width: 100%;
} }
.NewLayoutBillContainer { .NewLayoutBillContainer {
display: flex; display: flex;
align-items: center; align-items: center;
@ -439,7 +439,7 @@ body {
font-weight: 600; font-weight: 600;
align-items: center; align-items: center;
gap: 2px; gap: 2px;
padding: 0 6px; padding: 0 6px;
@media (max-width: 500px) { @media (max-width: 500px) {
font-size: 10px; font-size: 10px;

View File

@ -46,6 +46,12 @@
overflow: auto; overflow: auto;
height: 75vh; height: 75vh;
padding-bottom: 3rem; padding-bottom: 3rem;
white-space: nowrap;
width: 100%;
.printer-button {
width: 120px !important;
}
.modal-header { .modal-header {
text-align: center; text-align: center;
@ -75,13 +81,15 @@
.setting-card { .setting-card {
width: 30%; width: 30%;
@media (max-width: 768px) {
width: unset;
}
button { button {
background: #fff; background: #fff;
border-radius: 8px; border-radius: 8px;
display: flex; display: flex;
align-items: center; align-items: center;
// flex-direction: column;
padding: 10px 20px; padding: 10px 20px;
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
@ -166,11 +174,10 @@
// Responsive design // Responsive design
@media (max-width: 600px) { @media (max-width: 600px) {
.printer-settings-content { .printer-settings-content {
padding: 20px; padding: 10px;
.settings-grid { .settings-grid {
grid-template-columns: 1fr; gap: 10px;
gap: 15px;
} }
.modal-actions { .modal-actions {

View File

@ -68,10 +68,10 @@
column-gap: 3rem; column-gap: 3rem;
padding-top: 1rem; padding-top: 1rem;
height: 78vh; height: 78vh;
overflow: scroll; overflow: auto;
scrollbar-width: thin;
row-gap: 1.5rem; row-gap: 1.5rem;
padding-bottom: 4rem; padding-bottom: 4rem;
scrollbar-width: thin;
@media (max-width: 768px) { @media (max-width: 768px) {
padding-bottom: 4rem; padding-bottom: 4rem;
@ -131,6 +131,7 @@
} }
.sales-quotation { .sales-quotation {
position: relative;
.ant-select { .ant-select {
width: 250px !important; width: 250px !important;
height: 48px !important; height: 48px !important;
@ -139,4 +140,9 @@
input { input {
padding: 6px 25px 6px 12px !important; padding: 6px 25px 6px 12px !important;
} }
.BsUpcScanSQ {
position: absolute;
right: 10px;
top: 15px;
}
} }

View File

@ -4,7 +4,6 @@
} }
.MasterLedger-Report { .MasterLedger-Report {
// width: 100vw;
padding: 0rem 0; padding: 0rem 0;
overflow: hidden; overflow: hidden;
background-color: #fff; background-color: #fff;
@ -16,13 +15,16 @@
width: max-content !important; width: max-content !important;
} }
} }
.custom-table th {
white-space: nowrap;
}
} }
.LedgerTable { .LedgerTable {
height: 73vh; height: 73vh;
scrollbar-width: thin;
width: 100%; width: 100%;
overflow: auto; overflow: auto;
scrollbar-width: thin;
tr:nth-child(even) { tr:nth-child(even) {
background-color: #e9e8e8 !important; background-color: #e9e8e8 !important;
@ -49,7 +51,6 @@
.Dropdown-DatePicker { .Dropdown-DatePicker {
display: flex; display: flex;
align-items: center; align-items: center;
// padding: 0.2rem 0px;
flex-direction: row; flex-direction: row;
column-gap: 2rem; column-gap: 2rem;
flex-wrap: wrap; flex-wrap: wrap;
@ -80,12 +81,10 @@
.LedgerDropDate { .LedgerDropDate {
display: flex; display: flex;
// align-items: center;
justify-content: space-between; justify-content: space-between;
width: 100%; width: 100%;
gap: 2rem; gap: 2rem;
flex-wrap: wrap; flex-wrap: wrap;
// overflow-x: scroll;
} }
.ItemWiseReport-printerIcon-disabled { .ItemWiseReport-printerIcon-disabled {
@ -118,7 +117,6 @@
display: flex; display: flex;
padding-left: 10px; padding-left: 10px;
border-style: groove; border-style: groove;
// align-items: center;
} }
.LR-DatePicker { .LR-DatePicker {
@ -142,8 +140,8 @@
width: 72px; width: 72px;
} }
.LedgerTable .ant-table-wrapper .ant-table-thead>tr>th, .LedgerTable .ant-table-wrapper .ant-table-thead > tr > th,
.ant-table-wrapper .ant-table-thead>tr>td { .ant-table-wrapper .ant-table-thead > tr > td {
color: #000000; color: #000000;
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
@ -174,7 +172,7 @@
} }
.MasterLedger-Report .ant-table-wrapper .ant-table-cell, .MasterLedger-Report .ant-table-wrapper .ant-table-cell,
.MasterLedger-Report .ant-table-wrapper .ant-table-thead>tr>th { .MasterLedger-Report .ant-table-wrapper .ant-table-thead > tr > th {
padding: 1px 13px; padding: 1px 13px;
width: 100px; width: 100px;
} }
@ -207,17 +205,15 @@
width: 200px !important; width: 200px !important;
} }
.LedgerTable { .LedgerTable {
height: 50vh; height: 50vh;
} }
.LedgerDropDate { .LedgerDropDate {
overflow-y: scroll; overflow-y: auto;
} }
.Ledger-datePicker { .Ledger-datePicker {
.ant-picker { .ant-picker {
width: 100px !important; width: 100px !important;
height: 50px !important; height: 50px !important;
@ -239,7 +235,7 @@
.AllRadioButton { .AllRadioButton {
width: 37vh; width: 37vh;
overflow-x: scroll; overflow-x: auto;
} }
} }
@ -265,7 +261,7 @@
border: 1px solid #909090; border: 1px solid #909090;
font-family: "Poppins", sans-serif; font-family: "Poppins", sans-serif;
>thead { > thead {
position: sticky; position: sticky;
top: -1px; top: -1px;
} }
@ -281,7 +277,6 @@
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
font-family: VAR(--HEADING_FONT_FAMILY); font-family: VAR(--HEADING_FONT_FAMILY);
// text-transform: uppercase;
text-transform: capitalize; text-transform: capitalize;
letter-spacing: 0.2px; letter-spacing: 0.2px;
} }
@ -290,7 +285,8 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 4px; gap: 4px;
overflow: scroll; overflow: auto;
scrollbar-width: thin;
padding-bottom: 2rem; padding-bottom: 2rem;
} }
@ -336,7 +332,7 @@
justify-content: flex-end; justify-content: flex-end;
gap: 1rem; gap: 1rem;
>div { > div {
border-radius: 6px; border-radius: 6px;
padding: 5px 10px; padding: 5px 10px;
color: #fff; color: #fff;
@ -344,21 +340,20 @@
cursor: pointer; cursor: pointer;
} }
>div:nth-child(1) { > div:nth-child(1) {
background-color: #28aa3a; background-color: #28aa3a;
} }
>div:nth-child(2) { > div:nth-child(2) {
background-color: #ff0000; background-color: #ff0000;
} }
} }
.custom-table { .custom-table {
Button:disabled, Button:disabled,
Button[disabled] { Button[disabled] {
width: unset !important; width: unset !important;
height: unset !important; height: unset !important;
border-radius: 50px !important; border-radius: 50px !important;
} }
} }