added otp and time restriction for kiosk

This commit is contained in:
unknown 2026-03-02 11:57:05 +05:30
parent d1381c3c9b
commit f689237774
13 changed files with 737 additions and 160 deletions

View File

@ -45,6 +45,13 @@ export const putupi = createAsyncThunk('putupi', async (putData) => {
return await axiosRetailInstanceData.put(`/upi`, putData); return await axiosRetailInstanceData.put(`/upi`, putData);
}); });
export const checkLastOrderTimeLimit = createAsyncThunk('kiosk/lastOrderTimeLimit', async (data) => {
const { MobileNo, CompId, AppId, BranchId } = data;
if (MobileNo) {
return await axiosRetailInstanceData.get(`/Selfbookingeligibility?mobileNo=${MobileNo}&CompId=${CompId}&AppId=${AppId}&BranchId=${BranchId}`);
}
});
export const delupi = createAsyncThunk('delupi', async (deleteData) => { export const delupi = createAsyncThunk('delupi', async (deleteData) => {
if ( if (
data?.CompId != null && data?.CompId != null &&

View File

@ -205,7 +205,7 @@ const SalesCountComponent = React.memo(
let AutoReceiveStock = preferencedata?.[0]?.SettingDtlDetails?.some( let AutoReceiveStock = preferencedata?.[0]?.SettingDtlDetails?.some(
(s) => (s) =>
s?.SettingIdName?.toLowerCase() === 'autoreceivestock' && s?.SettingIdName?.toLowerCase() === 'autoreceivestock' &&
s?.SettingValue === 'Y' s?.SettingValue === 'N'
); );
setAutoReceiveStock(!AutoReceiveStock); setAutoReceiveStock(!AutoReceiveStock);
if (AutoReceiveStock) { if (AutoReceiveStock) {

View File

@ -7,6 +7,7 @@ import { MdCurrencyRupee } from 'react-icons/md';
import PozoDineInIcon from '../KioskIcons/KioskDineIn'; import PozoDineInIcon from '../KioskIcons/KioskDineIn';
import TakeAway from '../KioskIcons/KioskTakeAway'; import TakeAway from '../KioskIcons/KioskTakeAway';
import { import {
changeKioskCustomerMobileNo,
changeKioskPageName, changeKioskPageName,
getKioskDarkColour, getKioskDarkColour,
globalCurrentKioskPageName, globalCurrentKioskPageName,
@ -54,6 +55,7 @@ const KioskFooter = (props) => {
const Oncancel = () => { const Oncancel = () => {
dispatch(changeKioskPageName('initialPage')); dispatch(changeKioskPageName('initialPage'));
dispatch(changeAllGlbStatustData()); dispatch(changeAllGlbStatustData());
dispatch(changeKioskCustomerMobileNo(null));
// clear all global val // clear all global val
}; };
@ -110,6 +112,7 @@ const KioskFooter = (props) => {
}; };
const handlePaymentCancel = () => { const handlePaymentCancel = () => {
setPaymentModalOpen(false); setPaymentModalOpen(false);
dispatch(changeKioskCustomerMobileNo(null));
}; };
return ( return (
<div> <div>

View File

@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { Popconfirm, Drawer } from 'antd'; import { Popconfirm, Drawer } from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons'; import { QuestionCircleOutlined } from '@ant-design/icons';
import { import {
changeKioskCustomerMobileNo,
changeKioskPageName, changeKioskPageName,
getKioskDarkColour, getKioskDarkColour,
globalCurrentKioskPageName, globalCurrentKioskPageName,
@ -75,6 +76,7 @@ const KioskFooter2 = (props) => {
const Oncancel = () => { const Oncancel = () => {
dispatch(changeKioskPageName('initialPage')); dispatch(changeKioskPageName('initialPage'));
dispatch(changeAllGlbStatustData()); dispatch(changeAllGlbStatustData());
dispatch(changeKioskCustomerMobileNo(null));
// clear all global val // clear all global val
}; };
const MobileNumberPage = async () => { const MobileNumberPage = async () => {
@ -105,6 +107,7 @@ const KioskFooter2 = (props) => {
}; };
const handlePaymentCancel = () => { const handlePaymentCancel = () => {
setPaymentModalOpen(false); setPaymentModalOpen(false);
dispatch(changeKioskCustomerMobileNo(null));
}; };
return ( return (

View File

@ -7,6 +7,7 @@ import TakeAway from '../KioskIcons/KioskTakeAway';
import { IoIosArrowForward } from 'react-icons/io'; import { IoIosArrowForward } from 'react-icons/io';
import { MdCurrencyRupee } from 'react-icons/md'; import { MdCurrencyRupee } from 'react-icons/md';
import { import {
changeKioskCustomerMobileNo,
changeKioskPageName, changeKioskPageName,
getKioskDarkColour, getKioskDarkColour,
globalCurrentKioskPageName, globalCurrentKioskPageName,
@ -81,6 +82,7 @@ const KioskFooter3 = (props) => {
const Oncancel = () => { const Oncancel = () => {
dispatch(changeKioskPageName('initialPage')); dispatch(changeKioskPageName('initialPage'));
dispatch(changeAllGlbStatustData()); dispatch(changeAllGlbStatustData());
dispatch(changeKioskCustomerMobileNo(null));
// clear all global val // clear all global val
}; };
@ -101,6 +103,7 @@ const KioskFooter3 = (props) => {
}; };
const handlePaymentCancel = () => { const handlePaymentCancel = () => {
setPaymentModalOpen(false); setPaymentModalOpen(false);
dispatch(changeKioskCustomerMobileNo(null));
}; };
return ( return (
<div className="KioskFooter3-master"> <div className="KioskFooter3-master">

View File

@ -2,6 +2,7 @@ import { Badge, Drawer, Popconfirm } from 'antd';
import '../../../Styles/Kiosk/Components/KioskHeader.scss'; import '../../../Styles/Kiosk/Components/KioskHeader.scss';
import { IoIosArrowBack } from 'react-icons/io'; import { IoIosArrowBack } from 'react-icons/io';
import { import {
changeKioskCustomerMobileNo,
changeKioskPageName, changeKioskPageName,
getKioskCompLogo, getKioskCompLogo,
getKioskLightColour, getKioskLightColour,
@ -16,10 +17,12 @@ import {
changeAllGlbStatustData, changeAllGlbStatustData,
getProductCategories, getProductCategories,
} from '../../../Features/BookingScreen/BookingData/KioskBookingData'; } from '../../../Features/BookingScreen/BookingData/KioskBookingData';
import { useState } from 'react'; import { useEffect, useState } from 'react';
import KisokOrderCart2 from '../OrderCart/OrderCart2'; import KisokOrderCart2 from '../OrderCart/OrderCart2';
import KisokOrderCart1 from '../OrderCart/OrderCart1'; import KisokOrderCart1 from '../OrderCart/OrderCart1';
import KisokOrderCart3 from '../OrderCart/OrderCart3'; import KisokOrderCart3 from '../OrderCart/OrderCart3';
import { MdFullscreen, MdFullscreenExit } from "react-icons/md";
const KioskHeader = (props) => { const KioskHeader = (props) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -37,7 +40,36 @@ const KioskHeader = (props) => {
}, 0); }, 0);
const cartTheme = props?.KioskThemeData?.KioskOrderCart?.[0]; const cartTheme = props?.KioskThemeData?.KioskOrderCart?.[0];
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [isFullscreen, setIsFullscreen] = useState(false);
console.log(cartTheme, "propsprops") console.log(cartTheme, "propsprops")
const toggleFullscreen = () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
setIsFullscreen(true);
} else {
document.exitFullscreen();
setIsFullscreen(false);
}
};
useEffect(() => {
// Function to check fullscreen state
const checkFullscreen = () => {
setIsFullscreen(!!document.fullscreenElement);
};
// Check on initial render
checkFullscreen();
// Listen for changes (enter / exit fullscreen)
document.addEventListener('fullscreenchange', checkFullscreen);
return () => {
document.removeEventListener('fullscreenchange', checkFullscreen);
};
}, []);
const BackToCategory = async () => { const BackToCategory = async () => {
await dispatch( await dispatch(
getProductCategories({ getProductCategories({
@ -51,6 +83,7 @@ const KioskHeader = (props) => {
const BackToCardBasedonPreCatWithClear = async () => { const BackToCardBasedonPreCatWithClear = async () => {
await dispatch(changeAllGlbStatustData()); await dispatch(changeAllGlbStatustData());
await dispatch(changeKioskPageName('initialPage')); await dispatch(changeKioskPageName('initialPage'));
dispatch(changeKioskCustomerMobileNo(null));
}; };
const BackToCardBasedonPreCat = async () => { const BackToCardBasedonPreCat = async () => {
if ( if (
@ -84,30 +117,37 @@ const KioskHeader = (props) => {
> >
<div className="header-icon-shopping"> <div className="header-icon-shopping">
<p>ORDER TOTAL</p> <p>ORDER TOTAL</p>
{KioskOrderDetails?.length > 0 && ( <div className='headerFullMin'>
<div className="shopicon"> {isFullscreen ? (
<Badge <MdFullscreenExit size={25} onClick={toggleFullscreen} className='FullMinIcon' />
count={KioskOrderDetails?.length} ) : (
style={{ marginTop: '7px' }} <MdFullscreen size={25} onClick={toggleFullscreen} className='FullMinIcon' />
> )}
<AiOutlineShoppingCart style={{ cursor: 'pointer' }} size={50} onClick={() => setOpen(true)} /> {KioskOrderDetails?.length > 0 && (
</Badge> <div className="shopicon">
<div> <Badge
<MdCurrencyRupee count={KioskOrderDetails?.length}
size={18} style={{ marginTop: '7px' }}
style={{ marginBottom: '-0px', marginRight: '-5px' }} >
/>{' '} <AiOutlineShoppingCart style={{ cursor: 'pointer' }} size={50} onClick={() => setOpen(true)} />
{TotalNetAmount?.toFixed(2)} </Badge>
<div>
<MdCurrencyRupee
size={18}
style={{ marginBottom: '-0px', marginRight: '-5px' }}
/>{' '}
{TotalNetAmount?.toFixed(2)}
</div>
</div> </div>
</div> )}
)} </div>
</div> </div>
<div className="kioskcategory-menu2"> <div className="kioskcategory-menu2">
<div id="menu" onClick={() => BackToCategory()}> <div id="menu" onClick={() => BackToCategory()}>
Menu Menu
</div> </div>
{CurrentPageName === 'categoryPage' && {CurrentPageName === 'categoryPage' &&
KioskOrderDetails?.length > 0 ? ( KioskOrderDetails?.length > 0 ? (
<Popconfirm <Popconfirm
description={ description={
<p <p

View File

@ -10,8 +10,11 @@ import {
import '../../../Styles/Kiosk/InitialPage/InitialPage1.scss'; import '../../../Styles/Kiosk/InitialPage/InitialPage1.scss';
import { changeBookingType } from '../../../Features/BookingScreen/BookingData/KioskBookingData'; import { changeBookingType } from '../../../Features/BookingScreen/BookingData/KioskBookingData';
import initialBg from '../../../Images/InitialPage1bgImg.png'; import initialBg from '../../../Images/InitialPage1bgImg.png';
import { useEffect, useRef } from 'react';
import { isMobile } from 'react-device-detect';
const InitialPage1 = (props) => { const InitialPage1 = (props) => {
const actionContainerRef = useRef(null);
const dispatch = useDispatch(); const dispatch = useDispatch();
const getKioskBranchNamedata = useSelector(getKioskBranchName); const getKioskBranchNamedata = useSelector(getKioskBranchName);
const getKioskCompLogodata = useSelector(getKioskCompLogo); const getKioskCompLogodata = useSelector(getKioskCompLogo);
@ -23,6 +26,38 @@ const InitialPage1 = (props) => {
await dispatch(changeBookingType(eventName)); await dispatch(changeBookingType(eventName));
}; };
useEffect(() => {
const toggleFullScreen = () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen?.().catch((err) => {
console.log('Fullscreen blocked:', err);
});
} else {
document.exitFullscreen?.();
}
};
const handleDoubleClick = (e) => {
// Ignore if double click is inside Dine/TakeAway section
if (
actionContainerRef.current &&
actionContainerRef.current.contains(e.target)
) {
return;
}
toggleFullScreen();
};
window.addEventListener('dblclick', handleDoubleClick);
return () => {
window.removeEventListener('dblclick', handleDoubleClick);
};
}, []);
console.log(isMobile, "isMobile");
return ( return (
<> <>
<div className="InitialPAge1-Container"> <div className="InitialPAge1-Container">
@ -60,7 +95,7 @@ const InitialPage1 = (props) => {
/> */} /> */}
</p> </p>
</div> </div>
<div> <div ref={actionContainerRef}>
{(SalesType === 'D' || SalesType === 'B') && ( {(SalesType === 'D' || SalesType === 'B') && (
<div <div
onClick={() => { onClick={() => {

View File

@ -81,10 +81,13 @@ import { ApplicationPreferences } from '../../../Features/BrachLogin/BranchLogin
import { ReprintDetails } from '../../../Features/BookingScreen/Customer/addCustomer.js'; import { ReprintDetails } from '../../../Features/BookingScreen/Customer/addCustomer.js';
import PaymentGatewayEmbedded from '../../BookingScreen/Components/UtillComponents/PaymentGatewayEmbedded.jsx'; import PaymentGatewayEmbedded from '../../BookingScreen/Components/UtillComponents/PaymentGatewayEmbedded.jsx';
import MobileMultiPdfPrintTrigger from '../../BookingScreen/Components/UtillComponents/MobileMultiPdfPrintTrigger.jsx'; import MobileMultiPdfPrintTrigger from '../../BookingScreen/Components/UtillComponents/MobileMultiPdfPrintTrigger.jsx';
import { checkLastOrderTimeLimit, sendupiotp } from '../../../Features/UpiDetails/UpiDetails.js';
import { isIndianMobile } from '../../../utils/calculations.js';
const CustomPaymentUrl = import.meta.env.ENV_CUSTOM_PAYMENT_URL; const CustomPaymentUrl = import.meta.env.ENV_CUSTOM_PAYMENT_URL;
const KioskPayment = (props) => { const KioskPayment = (props) => {
const paymentGatewayRef = React.useRef(null);
const dispatch = useDispatch(); const dispatch = useDispatch();
const SessionData = props?.sessionData; const SessionData = props?.sessionData;
const DeviceMacAddress = getSession('DeviceAddress'); const DeviceMacAddress = getSession('DeviceAddress');
@ -92,6 +95,7 @@ const KioskPayment = (props) => {
const [open, setOpen] = useState(props.modalOpen); const [open, setOpen] = useState(props.modalOpen);
const [width, setWidth] = useState(window.innerWidth); const [width, setWidth] = useState(window.innerWidth);
const [showCancelConfirm, setShowCancelConfirm] = useState(false);
const appPreferences = useSelector(ApplicationPreferences); const appPreferences = useSelector(ApplicationPreferences);
const CustomerMobileNumber = useSelector(globalKioskCustomerMobileNo); const CustomerMobileNumber = useSelector(globalKioskCustomerMobileNo);
const OrderId = useSelector(GlobalOrderId); const OrderId = useSelector(GlobalOrderId);
@ -147,9 +151,28 @@ const KioskPayment = (props) => {
setting?.SettingIdName?.toLowerCase() === 'mobilea4' && setting?.SettingIdName?.toLowerCase() === 'mobilea4' &&
setting?.SettingValue === 'Y' setting?.SettingValue === 'Y'
); );
const isOtpEnabled = SettingDataSelector?.[0]?.SettingDtlDetails?.find(
(setting) =>
setting?.SettingIdName?.toLowerCase() === 'kioskotp' &&
setting?.SettingValue === 'Y'
);
const isTimeLimitEnabled = SettingDataSelector?.[0]?.SettingDtlDetails?.find(
(setting) =>
(setting?.SettingIdName?.toLowerCase() === 'hours' || setting?.SettingIdName?.toLowerCase() === 'minutes') &&
setting?.SettingValue === 'Y'
);
const bookingTypePreference = appPreferences?.find( const bookingTypePreference = appPreferences?.find(
(preference) => preference?.PreferredCatName === 'Booking Type' (preference) => preference?.PreferredCatName === 'Booking Type'
)?.PreferenceCatDetails; )?.PreferenceCatDetails;
const [showPaymentMethods, setShowPaymentMethods] = useState(null);
const [resendTimer, setResendTimer] = useState(0)
const [canResend, setCanResend] = useState(true)
const [otpInput, setOtpInput] = useState(['', '', '', '']);
const [otpIndex, setOtpIndex] = useState(0);
const [otpSent, setOtpSent] = useState(false);
const [otpVerifed, setOtpVerified] = useState(false);
const [otpNumber, setOTPNumber] = useState(null);
const [paymentUrl, setpaymentUrl] = useState(null); const [paymentUrl, setpaymentUrl] = useState(null);
const [businessUPI, setBusinessUPI] = useState(false); const [businessUPI, setBusinessUPI] = useState(false);
console.log(PrintOrderDetails, 'PrintOrderDetails'); console.log(PrintOrderDetails, 'PrintOrderDetails');
@ -161,16 +184,20 @@ const KioskPayment = (props) => {
useEffect(() => { useEffect(() => {
TotalCalculation(); TotalCalculation();
}, [KioskOrderDetails]); }, [KioskOrderDetails]);
// useEffect(() => { useEffect(() => {
// let data = { if (SessionData.CompId && SessionData.BranchId && SessionData.AppId) {
// CompId: SessionData.CompId, if (DeviceMacAddress) {
// BranchId: SessionData.BranchId, let data = {
// AppId: SessionData.AppId, CompId: SessionData.CompId,
// DeviceMacAddress: DeviceMacAddress, BranchId: SessionData.BranchId,
// }; AppId: SessionData.AppId,
// dispatch(getKioskPrinterDetails(data)).unwrap(); DeviceMacAddress: DeviceMacAddress,
// dispatch(getPreferenceData({ CompId: SessionData.CompId, BranchId: SessionData.BranchId, AppId: SessionData.AppId })).unwrap(); };
// }, []); dispatch(getKioskPrinterDetails(data)).unwrap();
}
dispatch(getPreferenceData({ CompId: SessionData.CompId, BranchId: SessionData.BranchId, AppId: SessionData.AppId })).unwrap();
}
}, [SessionData.CompId, SessionData.BranchId, SessionData.AppId]);
useEffect(() => { useEffect(() => {
const getPrintData = async () => { const getPrintData = async () => {
@ -325,7 +352,7 @@ const KioskPayment = (props) => {
}, [width]); }, [width]);
useEffect(() => { useEffect(() => {
number?.length === 10 && dispatch(changeKioskCustomerMobileNo(number)); isIndianMobile(number) && dispatch(changeKioskCustomerMobileNo(number));
}, [number]); }, [number]);
const onChange = (e) => { const onChange = (e) => {
@ -348,14 +375,13 @@ const KioskPayment = (props) => {
const items = [ const items = [
{ {
key: '1', key: '1',
label: `${ label: `${paymentGatewayMethods?.[selectedOption]?.CardType == 'CRDC' ||
paymentGatewayMethods?.[selectedOption]?.CardType == 'CRDC' ||
paymentGatewayMethods?.[selectedOption]?.CardType == 'DBCRD' paymentGatewayMethods?.[selectedOption]?.CardType == 'DBCRD'
? 'Choose Your Card' ? 'Choose Your Card'
: paymentGatewayMethods?.[selectedOption]?.CardType == 'WLT' : paymentGatewayMethods?.[selectedOption]?.CardType == 'WLT'
? 'Choose Your Wallet' ? 'Choose Your Wallet'
: 'Choose Your Bank' : 'Choose Your Bank'
} `, } `,
children: ( children: (
<Radio.Group <Radio.Group
onChange={onChange} onChange={onChange}
@ -396,6 +422,33 @@ const KioskPayment = (props) => {
}); });
}; };
const handleOtpNumber = (num) => {
if (otpIndex > 3) return;
const newOtp = [...otpInput];
newOtp[otpIndex] = num.toString();
setOtpInput(newOtp);
if (otpIndex < 3) {
setOtpIndex(otpIndex + 1);
}
};
const handleOtpBackspace = () => {
if (otpIndex < 0) return;
const newOtp = [...otpInput];
if (newOtp[otpIndex]) {
newOtp[otpIndex] = '';
} else if (otpIndex > 0) {
newOtp[otpIndex - 1] = '';
setOtpIndex(otpIndex - 1);
}
setOtpInput(newOtp);
};
const handleBackspace = () => { const handleBackspace = () => {
setNumber((prevNumber) => prevNumber.slice(0, -1)); setNumber((prevNumber) => prevNumber.slice(0, -1));
}; };
@ -709,7 +762,27 @@ const KioskPayment = (props) => {
return null; return null;
} }
const checkLast30MinOrder = async (MobileNo) => {
const response = await dispatch(checkLastOrderTimeLimit({
MobileNo,
AppId: SessionData.AppId,
CompId: SessionData.CompId,
BranchId: SessionData.BranchId,
}))?.unwrap();
return response?.data;
};
const handlePaymentOption = async (option) => { const handlePaymentOption = async (option) => {
if (isTimeLimitEnabled) {
const withinTimeLimit = await checkLast30MinOrder(number);
if (withinTimeLimit?.IsEligible === false) {
setMessageData(withinTimeLimit?.response);
setMessageType('warning');
return;
}
}
setSelectedPaymentOption(option); setSelectedPaymentOption(option);
dispatch(changeSelectedKioskPaymentOption(option)); dispatch(changeSelectedKioskPaymentOption(option));
@ -865,9 +938,9 @@ const KioskPayment = (props) => {
changeOrderId( changeOrderId(
response?.data?.OrderDetails?.[0]?.SalesId response?.data?.OrderDetails?.[0]?.SalesId
? extractLastNumberOrderId( ? extractLastNumberOrderId(
response?.data?.OrderDetails?.[0]?.SalesId, response?.data?.OrderDetails?.[0]?.SalesId,
response?.data?.OrderDetails?.[0]?.FYStatus response?.data?.OrderDetails?.[0]?.FYStatus
) )
: null : null
) )
); );
@ -975,9 +1048,9 @@ const KioskPayment = (props) => {
changeOrderId( changeOrderId(
response?.data?.OrderDetails?.[0]?.SalesId response?.data?.OrderDetails?.[0]?.SalesId
? extractLastNumberOrderId( ? extractLastNumberOrderId(
response?.data?.OrderDetails?.[0]?.SalesId, response?.data?.OrderDetails?.[0]?.SalesId,
response?.data?.OrderDetails?.[0]?.FYStatus response?.data?.OrderDetails?.[0]?.FYStatus
) )
: null : null
) )
); );
@ -1157,11 +1230,11 @@ const KioskPayment = (props) => {
changeOrderId( changeOrderId(
putPaymentDeviceResponse?.data?.OrderDetails?.[0]?.SalesId putPaymentDeviceResponse?.data?.OrderDetails?.[0]?.SalesId
? extractLastNumberOrderId( ? extractLastNumberOrderId(
putPaymentDeviceResponse?.data?.OrderDetails?.[0] putPaymentDeviceResponse?.data?.OrderDetails?.[0]
?.SalesId, ?.SalesId,
putPaymentDeviceResponse?.data?.OrderDetails?.[0] putPaymentDeviceResponse?.data?.OrderDetails?.[0]
?.FYStatus ?.FYStatus
) )
: null : null
) )
); );
@ -1555,7 +1628,7 @@ const KioskPayment = (props) => {
const selectedStyle = const selectedStyle =
stylesMap[ stylesMap[
printerTemplateStyle == undefined ? 'Style 13' : printerTemplateStyle printerTemplateStyle == undefined ? 'Style 13' : printerTemplateStyle
]; ];
if (selectedStyle) { if (selectedStyle) {
await Promise.all( await Promise.all(
@ -1761,6 +1834,80 @@ const KioskPayment = (props) => {
clearAllStates(); clearAllStates();
}; };
const sendOTP = async () => {
const valid = isIndianMobile(number);
if (valid) {
if (isTimeLimitEnabled) {
const withinTimeLimit = await checkLast30MinOrder(number);
if (withinTimeLimit?.IsEligible === false) {
setMessageData(withinTimeLimit?.response);
setMessageType('warning');
return;
}
}
} else {
setMessageData('Please enter valid mobile No.');
setMessageType('warning');
return
}
try {
setOtpIndex(0);
setOtpSent(true);
let response = await dispatch(sendupiotp({
"MobileNo": number,
"CreatedBy": 0
}))?.unwrap()
if (response?.data?.statusCode == 1) {
setMessageData('OTP sent to your mobile number');
setMessageType('success');
setOTPNumber(response?.data?.OTP);
startResendTimer();
}
}
catch (error) {
console.log(error)
}
}
const startResendTimer = () => {
setCanResend(false);
setResendTimer(30);
const timer = setInterval(() => {
setResendTimer((prev) => {
if (prev <= 1) {
clearInterval(timer);
setCanResend(true);
return 0;
}
return prev - 1;
});
}, 1000);
}
const handleOtpChange = (e, index) => {
const value = e.target.value.replace(/\D/g, '');
const newOtp = [...otpInput];
newOtp[index] = value;
setOtpInput(newOtp);
};
const verifyOtp = () => {
const enteredOtp = otpInput.join('');
if (enteredOtp === otpNumber?.toString()) {
setMessageType('success');
setMessageData('OTP Verified Successfully');
setOtpSent(false);
setOtpInput(['', '', '', '']);
setShowPaymentMethods(true);
setOtpVerified(true);
} else {
setMessageType('error');
setMessageData('Invalid OTP');
}
};
return ( return (
<div> <div>
<Messages <Messages
@ -1854,11 +2001,11 @@ const KioskPayment = (props) => {
placeholder={ placeholder={
paymentGatewayMethods?.[selectedOption]?.CardType == paymentGatewayMethods?.[selectedOption]?.CardType ==
'CRDC' || 'CRDC' ||
paymentGatewayMethods?.[selectedOption]?.CardType == paymentGatewayMethods?.[selectedOption]?.CardType ==
'DBCRD' 'DBCRD'
? 'Search Your Card' ? 'Search Your Card'
: paymentGatewayMethods?.[selectedOption]?.CardType == : paymentGatewayMethods?.[selectedOption]?.CardType ==
'WLT' 'WLT'
? 'Search Your Wallet' ? 'Search Your Wallet'
: 'Search Your Bank' : 'Search Your Bank'
} }
@ -1889,73 +2036,170 @@ const KioskPayment = (props) => {
</div> </div>
) : ( ) : (
<div className="paymentModal-Master"> <div className="paymentModal-Master">
<h4 className="Titlepayment">PAYMENT</h4> <h4 className="Titlepayment">{isOtpEnabled && !showPaymentMethods
? "Verify Mobile Number"
: "PAYMENT"}</h4>
<div className="paymentModal_main"> <div className="paymentModal_main">
<div className="prompt"> {!otpSent && !otpVerifed && (<>
<p> <div className="prompt">
Get your order bill on your mobile <br /> <p style={{ fontFamily: 'Poppins', fontWeight: '600' }}>
via SMS / Whatsapp Get your order bill on your mobile <br />
</p> via SMS / Whatsapp
</div> </p>
</div>
<div
className={`KioskPayment-inputModal ${number ? 'green-border' : ''}`}
>
<input type="text" value={number} readOnly />
</div>
{/* input boxxes */}
<div
className="KioskPayment-dailpad-main"
style={{
pointerEvents: selectedPaymentOption && 'none',
opacity: selectedPaymentOption && '40%',
}}
>
<div <div
className="Kiosk-dailpadModal" className={`KioskPayment-inputModal ${number ? 'green-border' : ''}`}
style={{ backgroundColor: getKioskLightColourdata }}
> >
<div className="KioskPayment-dailpad-1"> <input type="text" value={number} readOnly />
<p onClick={() => setNumberFun(1)}>1</p> {number?.length === 10 && !isIndianMobile(number) && <div className='input-err'>Please Enter Valid Mobile Number</div>}
<p onClick={() => setNumberFun(2)}>2</p> </div>
<p onClick={() => setNumberFun(3)}>3</p>
</div>
<div className="KioskPayment-dailpad-2"> {/* input boxxes */}
<p onClick={() => setNumberFun(4)}>4</p> <div
<p onClick={() => setNumberFun(5)}>5</p> className="KioskPayment-dailpad-main"
<p onClick={() => setNumberFun(6)}>6</p> style={{
</div> pointerEvents: selectedPaymentOption && 'none',
<div className="KioskPayment-dailpad-3"> opacity: selectedPaymentOption && '40%',
<p onClick={() => setNumberFun(7)}>7</p> }}
<p onClick={() => setNumberFun(8)}>8</p> >
<p onClick={() => setNumberFun(9)}>9</p> <div
</div> className="Kiosk-dailpadModal"
<div className="KioskPayment-dailpad-4"> style={{ backgroundColor: getKioskLightColourdata }}
<p onClick={handleBackspace}> >
<HiOutlineBackspace <div className="KioskPayment-dailpad-1">
size={30} <p onClick={() => setNumberFun(1)}>1</p>
style={{ marginBottom: '-2px' }} <p onClick={() => setNumberFun(2)}>2</p>
/> <p onClick={() => setNumberFun(3)}>3</p>
</p> </div>
<p onClick={() => setNumberFun(0)}>0</p> <div className="KioskPayment-dailpad-2">
<p style={{ background: 'none' }}></p> <p onClick={() => setNumberFun(4)}>4</p>
<p onClick={() => setNumberFun(5)}>5</p>
<p onClick={() => setNumberFun(6)}>6</p>
</div>
<div className="KioskPayment-dailpad-3">
<p onClick={() => setNumberFun(7)}>7</p>
<p onClick={() => setNumberFun(8)}>8</p>
<p onClick={() => setNumberFun(9)}>9</p>
</div>
<div className="KioskPayment-dailpad-4">
<p onClick={handleBackspace}>
<HiOutlineBackspace
size={30}
style={{ marginBottom: '-2px' }}
/>
</p>
<p onClick={() => setNumberFun(0)}>0</p>
<p style={{ background: 'none' }}></p>
</div>
</div> </div>
</div> </div>
</div> {isOtpEnabled && (
<p className="choiseTitle">Select Payment Method</p> <>
{console.log('selectedOption', selectedPaymentOption)} <button className='KioskOPTBTn'
<div // disabled={number?.length === 10}
className="paymentChoise" onClick={() => sendOTP()}
style={{ >Get OTP</button>
pointerEvents: </>
(number?.length !== 10 || selectedPaymentOption) && )}
'none', </>)}
opacity: {(isOtpEnabled && otpSent) && (
(number?.length !== 10 || selectedPaymentOption) && '40%', <div className="otp-section">
}}
> {/* Mobile Number + Edit */}
{/* {upiAvailability && ( <div className="otp-mobile-row">
<span className="otp-mobile-number">{number}</span>
<button
className="otp-edit-btn"
onClick={() => {
setOtpSent(false);
setOtpInput(['', '', '', '']);
setShowPaymentMethods(false);
}}
>
Edit
</button>
</div>
{/* 4 Digit OTP Input */}
<div className="otp-input-container">
{otpInput.map((digit, index) => (
<input
key={index}
type="text"
value={digit}
className={`otp-box ${index === otpIndex ? 'active' : ''}`}
onClick={() => setOtpIndex(index)}
readOnly
/>
))}
</div>
<div className="KioskPayment-dailpad-main">
<div
className="Kiosk-dailpadModal"
style={{ backgroundColor: getKioskLightColourdata }}
>
<div className="KioskPayment-dailpad-1">
<p onClick={() => handleOtpNumber(1)}>1</p>
<p onClick={() => handleOtpNumber(2)}>2</p>
<p onClick={() => handleOtpNumber(3)}>3</p>
</div>
<div className="KioskPayment-dailpad-2">
<p onClick={() => handleOtpNumber(4)}>4</p>
<p onClick={() => handleOtpNumber(5)}>5</p>
<p onClick={() => handleOtpNumber(6)}>6</p>
</div>
<div className="KioskPayment-dailpad-3">
<p onClick={() => handleOtpNumber(7)}>7</p>
<p onClick={() => handleOtpNumber(8)}>8</p>
<p onClick={() => handleOtpNumber(9)}>9</p>
</div>
<div className="KioskPayment-dailpad-4">
<p onClick={handleOtpBackspace}>
<HiOutlineBackspace size={30} />
</p>
<p onClick={() => handleOtpNumber(0)}>0</p>
<p style={{ background: 'none' }}></p>
</div>
</div>
</div>
{/* Buttons */}
<div className="otp-buttons">
<button
className="verify-btn"
disabled={otpInput.join('').length !== 4}
onClick={verifyOtp}
>
Verify
</button>
<button
className="resend-btn"
disabled={!canResend}
onClick={sendOTP}
>
{canResend ? "Resend OTP" : `Resend in ${resendTimer}s`}
</button>
</div>
</div>
)}
{(!isOtpEnabled || (showPaymentMethods && otpVerifed)) && <>
<p className="choiseTitle">Select Payment Method</p>
{console.log('selectedOption', selectedPaymentOption)}
<div
className="paymentChoise"
style={{
pointerEvents:
(!isIndianMobile(number) || selectedPaymentOption) &&
'none',
opacity:
(!isIndianMobile(number) || selectedPaymentOption) && '40%',
}}
>
{/* {upiAvailability && (
<div <div
className="upi" className="upi"
onClick={() => handlePaymentOption('UPI')} onClick={() => handlePaymentOption('UPI')}
@ -1964,7 +2208,7 @@ const KioskPayment = (props) => {
<p>UPI</p> <p>UPI</p>
</div> </div>
)} */} )} */}
{/* {cardAvailability && ( {/* {cardAvailability && (
<div <div
className="upi" className="upi"
onClick={() => handlePaymentOption('Card')} onClick={() => handlePaymentOption('Card')}
@ -1973,32 +2217,33 @@ const KioskPayment = (props) => {
<p>CARD</p> <p>CARD</p>
</div> </div>
)} */} )} */}
{counterAvailability && ( {counterAvailability && (
<div <div
className="upi" className="upi"
onClick={() => handlePaymentOption('Counter')} onClick={() => handlePaymentOption('Counter')}
> >
<MdOutlinePayments size={50} opacity={0.5} /> <MdOutlinePayments size={50} opacity={0.5} />
<p style={{ fontSize: '12px', textAlign: 'center' }}> <p style={{ fontSize: '12px', textAlign: 'center' }}>
PAY AT THE COUNTER PAY AT THE COUNTER
</p> </p>
</div> </div>
)} )}
{paymentOptionDetailsBusinessUpi && ( {paymentOptionDetailsBusinessUpi && (
<div <div
className="upi" className="upi"
onClick={() => handlePaymentOption('BU')} onClick={() => handlePaymentOption('BU')}
> >
<img src={UPI} alt="" width={60} /> <img src={UPI} alt="" width={60} />
<p> UPI</p> <p> UPI</p>
</div> </div>
)} )}
{!paymentOptionDetailsBusinessUpi && !counterAvailability && ( {!paymentOptionDetailsBusinessUpi && !counterAvailability && (
<div className="payment-error-msg"> <div className="payment-error-msg">
Please Set Payment Options Contact Admin Please Set Payment Options Contact Admin
</div> </div>
)} )}
</div> </div>
</>}
</div> </div>
</div> </div>
) )
@ -2076,10 +2321,28 @@ const KioskPayment = (props) => {
paymentSucess={paymentSucess} paymentSucess={paymentSucess}
ClearAllGlobalStateDatas={ClearAllGlobalStateDatas} ClearAllGlobalStateDatas={ClearAllGlobalStateDatas}
// CustomerDisplay={CustomerDisplay} // CustomerDisplay={CustomerDisplay}
ref={paymentGatewayRef}
/> />
</> </>
} }
/> />
{showCancelConfirm && (
<Modal
open={showCancelConfirm}
title="Cancel Payment"
onOk={() => {
paymentGatewayRef.current?.clearPolling();
setBusinessUPI(false);
setShowCancelConfirm(false);
ClearAllGlobalStateDatas();
}}
onCancel={() => setShowCancelConfirm(false)}
okText="Yes"
cancelText="No"
>
Do you want to cancel the payment?
</Modal>
)}
</div> </div>
); );
}; };

View File

@ -27,6 +27,14 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
padding: 1rem 1rem; padding: 1rem 1rem;
flex-direction: column;
.input-err{
color: red;
font-size: 13px;
margin-top: 4px;
font-family: 'Poppins', sans-serif;
}
input { input {
width: 50vw; width: 50vw;
@ -309,7 +317,7 @@
} }
.paymentCardMain .ant-radio-group, .paymentCardMain .ant-radio-group,
.ant-radio-wrapper span.ant-radio + * { .ant-radio-wrapper span.ant-radio+* {
padding: 10px 10px; padding: 10px 10px;
} }
@ -317,10 +325,7 @@
padding: 54px 35px !important; padding: 54px 35px !important;
} }
.paymentCardMain .paymentCardMain .ant-collapse .ant-collapse-item:last-child>.ant-collapse-content {
.ant-collapse
.ant-collapse-item:last-child
> .ant-collapse-content {
overflow: scroll; overflow: scroll;
height: 26vh; height: 26vh;
} }
@ -337,6 +342,7 @@
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.paymentModal_main .KioskPayment-inputModal input, .paymentModal_main .KioskPayment-inputModal input,
.paymentModal_main .Kiosk-dailpadModal { .paymentModal_main .Kiosk-dailpadModal {
width: 65vw; width: 65vw;
@ -436,3 +442,122 @@
height: 80vh; height: 80vh;
} }
} }
.KioskOPTBTn {
width: 70%;
padding: 12px 16px;
font-size: 20px;
font-family: "Poppins";
font-weight: 400;
border: none;
outline: none;
background-color: #000000;
color: #fff;
border-radius: 10px;
cursor: pointer;
}
.otp-section {
margin-top: 20px;
text-align: center;
.otp-mobile-row {
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
margin-bottom: 20px;
.otp-mobile-number {
font-size: 20px;
font-weight: 600;
letter-spacing: 1px;
}
.otp-edit-btn {
background: none;
border: none;
color: #007bff;
font-size: 16px;
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
}
.otp-input-container {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 25px;
.otp-box {
width: 65px;
height: 65px;
font-size: 28px;
text-align: center;
border: 2px solid #ccc;
border-radius: 8px;
outline: none;
transition: 0.2s ease;
&:focus {
border-color: #28a745;
box-shadow: 0 0 6px rgba(40, 167, 69, 0.4);
}
}
.otp-box.active {
border: 2px solid #28a745;
}
}
.otp-buttons {
display: flex;
justify-content: center;
gap: 20px;
button {
min-width: 140px;
padding: 12px 18px;
font-size: 16px;
font-weight: 500;
border-radius: 8px;
cursor: pointer;
transition: 0.2s ease;
font-family: 'Poppins', sans-serif !important;
display: flex;
align-items: center;
justify-content: center;
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
.verify-btn {
background-color: #28a745;
border: none;
color: #fff;
&:hover:not(:disabled) {
background-color: #218838;
}
}
.resend-btn {
background-color: #ffc107;
border: none;
color: #000;
&:hover:not(:disabled) {
background-color: #e0a800;
}
}
}
}

View File

@ -22,7 +22,7 @@ import { ApplicationPreferences } from '../../Features/BrachLogin/BranchLogin.js
import './PreferenceList.scss'; import './PreferenceList.scss';
const PreferenceList = () => { const PreferenceList = () => {
const { SadminuserAccess } = useAuth(); const { SadminuserAccess, featureaddDetails } = useAuth();
const dispatch = useDispatch(); const dispatch = useDispatch();
const formRef = useRef(); const formRef = useRef();
@ -57,16 +57,17 @@ const PreferenceList = () => {
const settingsList = tableValue[0]?.SettingDtlDetails ?? preferenceConfigs; const settingsList = tableValue[0]?.SettingDtlDetails ?? preferenceConfigs;
const allSettingsMap = {}; const allSettingsMap = {};
settingsList?.forEach(({ SettingIdName, SettingValue, SettingCount }) => { settingsList?.forEach(({ SettingIdName, SettingValue, SettingCount, SettingTime }) => {
allSettingsMap[SettingIdName?.toLowerCase()] = { value: SettingValue, count: SettingCount }; allSettingsMap[SettingIdName?.toLowerCase()] = { value: SettingValue, count: SettingCount, time: SettingTime?.split(' ')?.[0] };
}); });
console.log(settingsList, 'settingsList'); console.log(featureaddDetails, 'featureaddDetails');
const buildInitialValues = () => ({ const buildInitialValues = () => ({
dashboard: allSettingsMap['dashboard']?.value === 'Y', dashboard: allSettingsMap['dashboard']?.value === 'Y',
shortcutkeys: allSettingsMap['shortcutkeys']?.value === 'Y', shortcutkeys: allSettingsMap['shortcutkeys']?.value === 'Y',
autoreceivestock: allSettingsMap['autoreceivestock']?.value === 'Y', autoreceivestock: allSettingsMap['autoreceivestock']?.value === 'Y',
kioskotp: allSettingsMap['kioskotp']?.value === 'Y',
decimal: allSettingsMap['decimal']?.value === 'Y', decimal: allSettingsMap['decimal']?.value === 'Y',
enabledModules: [ enabledModules: [
...(allSettingsMap['dinein']?.value === 'Y' ? ['dinein'] : []), ...(allSettingsMap['dinein']?.value === 'Y' ? ['dinein'] : []),
@ -86,7 +87,17 @@ const PreferenceList = () => {
preorderpricechange: allSettingsMap['preorderpricechange']?.value === 'Y', preorderpricechange: allSettingsMap['preorderpricechange']?.value === 'Y',
quantityrestriction: allSettingsMap['overalllimit']?.value === 'Y' || allSettingsMap['itemwiselimit']?.value === 'Y', quantityrestriction: allSettingsMap['overalllimit']?.value === 'Y' || allSettingsMap['itemwiselimit']?.value === 'Y',
quantityrestrictiontype: allSettingsMap['overalllimit']?.value === 'Y' ? 'overall' : allSettingsMap['itemwiselimit']?.value === 'Y' ? 'itemwise' : 'overall', quantityrestrictiontype: allSettingsMap['overalllimit']?.value === 'Y' ? 'overall' : allSettingsMap['itemwiselimit']?.value === 'Y' ? 'itemwise' : 'overall',
kiosktimelimit: allSettingsMap['hours']?.value === 'Y' || allSettingsMap['minutes']?.value === 'Y',
kiosktimelimittype: allSettingsMap['hours']?.value === 'Y' ? 'hours' : allSettingsMap['minutes']?.value === 'Y' ? 'minutes' : 'minutes',
maxquantity: allSettingsMap['overalllimit']?.value === 'Y' ? allSettingsMap['overalllimit']?.count || 1 : allSettingsMap['itemwiselimit']?.value === 'Y' ? allSettingsMap['itemwiselimit']?.count || 1 : 1, maxquantity: allSettingsMap['overalllimit']?.value === 'Y' ? allSettingsMap['overalllimit']?.count || 1 : allSettingsMap['itemwiselimit']?.value === 'Y' ? allSettingsMap['itemwiselimit']?.count || 1 : 1,
maxtime:
allSettingsMap['hours']?.value === 'Y'
? (allSettingsMap['hours']?.time
? parseFloat(allSettingsMap['hours']?.time / 60)
: 0.5)
: allSettingsMap['minutes']?.value === 'Y'
? parseFloat(allSettingsMap['minutes']?.time || 30)
: 30,
billOption: ['whatsapp', 'sms', 'email'].some( billOption: ['whatsapp', 'sms', 'email'].some(
(k) => allSettingsMap[k]?.value === 'Y' (k) => allSettingsMap[k]?.value === 'Y'
) )
@ -158,6 +169,7 @@ const PreferenceList = () => {
if (settingsList) { if (settingsList) {
const built = buildInitialValues(); const built = buildInitialValues();
setInitialValues(built); setInitialValues(built);
console.log(built, 'built');
formRef.current?.setFieldsValue(built); formRef.current?.setFieldsValue(built);
} }
}, [settingsList]); }, [settingsList]);
@ -295,6 +307,7 @@ const PreferenceList = () => {
dashboard: values.dashboard, dashboard: values.dashboard,
shortcutkeys: values.shortcutkeys, shortcutkeys: values.shortcutkeys,
autoreceivestock: values.autoreceivestock, autoreceivestock: values.autoreceivestock,
kioskotp: values.kioskotp,
decimal: values.decimal, decimal: values.decimal,
searchfocus: values.searchfocus, searchfocus: values.searchfocus,
addproductcard: values.addproductcard, addproductcard: values.addproductcard,
@ -317,6 +330,8 @@ const PreferenceList = () => {
editbill: values.editbill, editbill: values.editbill,
overalllimit: values.quantityrestriction && values.quantityrestrictiontype === 'overall', overalllimit: values.quantityrestriction && values.quantityrestrictiontype === 'overall',
itemwiselimit: values.quantityrestriction && values.quantityrestrictiontype === 'itemwise', itemwiselimit: values.quantityrestriction && values.quantityrestrictiontype === 'itemwise',
hours: values.kiosktimelimit && values.kiosktimelimittype === 'hours',
minutes: values.kiosktimelimit && values.kiosktimelimittype === 'minutes',
}; };
const arrayValues = { const arrayValues = {
@ -349,7 +364,13 @@ const PreferenceList = () => {
SettingId: setting.SettingId, SettingId: setting.SettingId,
Comments: setting.Comments || 'Enter Comment', Comments: setting.Comments || 'Enter Comment',
SettingValue: isChecked ? 'Y' : 'N', SettingValue: isChecked ? 'Y' : 'N',
SettingCount: ((key === 'overalllimit' || key === 'itemwiselimit') && isChecked) ? parseFloat(values.maxquantity) || null : null SettingCount: ((key === 'overalllimit' || key === 'itemwiselimit') && isChecked) ? parseFloat(values.maxquantity) || null : null,
SettingTime:
((key === "hours" && isChecked)
? ((parseFloat(values.maxtime) * 60)?.toFixed(2) + ' ' + 'Minutes' || null)
: (key === "minutes" && isChecked)
? (parseFloat(values.maxtime)?.toFixed(2) + ' ' + 'Minutes' || null)
: null),
}; };
}); });
@ -459,6 +480,7 @@ const PreferenceList = () => {
</div> </div>
<Form <Form
key={JSON.stringify(initialValues)}
ref={formRef} ref={formRef}
layout="vertical" layout="vertical"
onFinish={handleSubmit} onFinish={handleSubmit}
@ -511,6 +533,65 @@ const PreferenceList = () => {
</Checkbox.Group> </Checkbox.Group>
</Form.Item> </Form.Item>
)} )}
{featureaddDetails?.find(
(item) => item?.FeatureAddonName?.toLowerCase() === 'kiosk sales'
) && renderCheckbox('kioskotp', 'Enable OTP verification for Kiosk Orders?')}
{featureaddDetails?.find(
(item) => item?.FeatureAddonName?.toLowerCase() === 'kiosk sales'
) && (allSettingsMap['hours'] !== undefined || allSettingsMap['minutes'] !== undefined) && <>
<Form.Item name="kiosktimelimit" label="Restrict orders for the same customer within a time limit?" valuePropName="checked">
<Checkbox>Yes</Checkbox>
</Form.Item>
<Form.Item noStyle shouldUpdate={(prev, curr) => prev.kiosktimelimit !== curr.kiosktimelimit}>
{({ getFieldValue }) => getFieldValue('kiosktimelimit') && (
<>
<Form.Item name="kiosktimelimittype" label="How would you like to apply the time restriction?">
<Radio.Group onChange={() => formRef.current?.setFieldsValue({ maxtime: undefined })}>
<Radio value="minutes">Minutes</Radio>
<Radio value="hours">Hours</Radio>
</Radio.Group>
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prev, curr) =>
prev.kiosktimelimittype !== curr.kiosktimelimittype
}
>
{({ getFieldValue }) => {
const type = getFieldValue('kiosktimelimittype');
const isHours = type === 'hours';
return (
<Form.Item
name="maxtime"
label={`Maximum Time Limit (${isHours ? 'Hours' : 'Minutes'}):`}
rules={[
{ required: true, message: 'Please enter maximum time' },
{
type: 'number',
min: isHours ? 0.25 : 1,
message: isHours
? 'Minimum allowed is 0.25 hours'
: 'Minimum allowed is 1 minute',
},
]}
>
<InputNumber
min={isHours ? 0.25 : 1}
step={isHours ? 0.25 : 1}
precision={isHours ? 2 : 0}
style={{ width: '200px' }}
/>
</Form.Item>
);
}}
</Form.Item>
</>
)}
</Form.Item>
</>}
</div> </div>
<Divider /> <Divider />

View File

@ -191,7 +191,7 @@ const CreateTransfer = () => {
formProductRef?.current?.resetFields(); formProductRef?.current?.resetFields();
if (!scanner) { if (!scanner) {
setProductSearchText(''); setProductSearchText('');
} }
return success; return success;
@ -436,6 +436,7 @@ const CreateTransfer = () => {
ProdId: item.ProdId, ProdId: item.ProdId,
InwardDtlId: item.InwardDtlId, InwardDtlId: item.InwardDtlId,
RequestedQty: Number(item.ReceivedQty), RequestedQty: Number(item.ReceivedQty),
ProdVariantName: item.ProdVariantName,
})), })),
CreatedBy: UserId, CreatedBy: UserId,
}; };
@ -527,12 +528,12 @@ const CreateTransfer = () => {
/> />
</div> </div>
) : ( ) : (
<Tooltip title="BarCode / QR Code"> <Tooltip title="BarCode / QR Code">
<BsUpcScan <BsUpcScan
className={`product-scan-icon ${scanner ? 'active' : ''}`} className={`product-scan-icon ${scanner ? 'active' : ''}`}
onClick={handleScannerToggle} onClick={handleScannerToggle}
/> />
</Tooltip> </Tooltip>
)} )}
</div> </div>
</div> </div>

View File

@ -67,3 +67,17 @@
font-weight: 600; font-weight: 600;
flex-direction: row-reverse; flex-direction: row-reverse;
} }
.headerFullMin{
display: flex;
align-items: center;
gap: 10px;
}
.FullMinIcon{
background-color: #fff;
height: 40px;
width: 40px;
padding: 5px;
border-radius: 4px;
transition: all 0.3s ease-in-out;
cursor: pointer;
}

View File

@ -8,3 +8,5 @@ export const capitalizeFirstLetter = (text) => {
if (!text) return ''; if (!text) return '';
return text.charAt(0).toUpperCase() + text.slice(1); return text.charAt(0).toUpperCase() + text.slice(1);
}; };
export const isIndianMobile = (mobile) => /^\d{10}$/.test(mobile) && /^[6-9]/.test(mobile);