Merge pull request 'Add checkbox to configure token printing by booking type' (#282) from token_print_setup into main

Reviewed-on: Pozomind/pozo-retail-app#282
This commit is contained in:
mohan 2026-03-13 16:50:21 +05:30
commit 54857b7956
1 changed files with 326 additions and 271 deletions

View File

@ -30,7 +30,7 @@ const PrinterSelection = (props) => {
const [initialPrinters, setInitialPrinters] = useState([]);
const PrinterDetails = useSelector(GlobalPrinterMappingDtls);
const FeatureAddonData = useSelector(GlobalFeatAddOnData);
const [MyPrinter, setMyPrinter] = useState(true);
const [MyPrinter, setMyPrinter] = useState(true);
const [MyKioskPrinter, setMyKioskPrinter] = useState(false);
const { onClose } = props;
// const initialPrinters = [
@ -50,23 +50,23 @@ const PrinterSelection = (props) => {
getCounters();
}, []);
useEffect(() => {
const onFocus = () => {
const isTriggered = localStorage.getItem("trigger_from_app");
const onFocus = () => {
const isTriggered = localStorage.getItem("trigger_from_app");
if (isTriggered === "1") {
console.log("App trigger detected — refreshing printer data...");
getPrinters();
getCounters();
if (isTriggered === "1") {
console.log("App trigger detected — refreshing printer data...");
getPrinters();
getCounters();
// Clear flag so it doesn't run again
localStorage.removeItem("trigger_from_app");
}
};
// Clear flag so it doesn't run again
localStorage.removeItem("trigger_from_app");
}
};
window.addEventListener("focus", onFocus);
return () => window.removeEventListener("focus", onFocus);
window.addEventListener("focus", onFocus);
return () => window.removeEventListener("focus", onFocus);
}, []);
}, []);
const getPrinters = async () => {
const data = {
AppId: AppId,
@ -79,17 +79,17 @@ const PrinterSelection = (props) => {
const printerData = response?.data?.data || [];
const printMappingDtl = printerData?.[0]?.PrintMappingDtl || [];
setInitialPrinters(printMappingDtl);
// Map API data: preserve original MappingPrintType (K/U/null)
// For user mappings, use backend values; for others, create user mapping structure
const mappedPrinters = printMappingDtl.map((printer) => {
const isUserMapping = printer.MappingPrintType === 'U' && printer.UserId === UserId;
const physicalId = `${printer.ConnectionKey}${(printer.MacAddress !== 'N/A' && printer.MacAddress !== null) ? `_${printer.MacAddress}` : ''}`;
// Preserve null MappingPrintType - don't convert to 'U'
const mappingPrintType = printer.MappingPrintType !== null && printer.MappingPrintType !== undefined
? printer.MappingPrintType
const mappingPrintType = printer.MappingPrintType !== null && printer.MappingPrintType !== undefined
? printer.MappingPrintType
: null;
return {
ConnectionKey: printer.ConnectionKey,
PrinterName: printer.PrinterName,
@ -108,9 +108,12 @@ const PrinterSelection = (props) => {
MappingPrintType: mappingPrintType,
UserId: printer.UserId || UserId,
DeviceAddress: printer.DeviceAddress || null,
TakeAwayTokenFlg: printer.TakeAwayTokenFlg || "N",
DineInTokenFlg: printer.DineInTokenFlg || "N"
};
});
setPrinters(mappedPrinters);
} else {
setInitialPrinters([])
@ -128,7 +131,7 @@ const PrinterSelection = (props) => {
setcounters(counterdata);
}
const toggleSetPrint = (printerId) => {
const selectedPrinter = printers.find(p => p.PrintUniqId === printerId);
console.log(printerId, selectedPrinter, printers, 'printerId');
@ -136,9 +139,9 @@ const PrinterSelection = (props) => {
setPrinters((prev) => {
// Check if user mapping already exists for this physical printer
const existingUserMapping = prev.find(p =>
p.id === selectedPrinter.id &&
p.MappingPrintType === 'U' &&
const existingUserMapping = prev.find(p =>
p.id === selectedPrinter.id &&
p.MappingPrintType === 'U' &&
p.UserId === UserId
);
@ -184,10 +187,10 @@ const PrinterSelection = (props) => {
setPrinters((prev) =>
prev.map((p) => {
if (p.ConnectionKey === selectedPrinter.ConnectionKey &&
p.MacAddress === selectedPrinter.MacAddress &&
p.UserId === UserId &&
p.MappingPrintType === 'U') {
if (p.ConnectionKey === selectedPrinter.ConnectionKey &&
p.MacAddress === selectedPrinter.MacAddress &&
p.UserId === UserId &&
p.MappingPrintType === 'U') {
return {
...p,
CounterId: p.CounterId === counter.CounterId ? null : counter.CounterId,
@ -204,10 +207,10 @@ const PrinterSelection = (props) => {
setPrinters(prev =>
prev.map(p => {
if (p.ConnectionKey === selectedPrinter.ConnectionKey &&
p.MacAddress === selectedPrinter.MacAddress &&
p.UserId === UserId &&
p.MappingPrintType === 'U') {
if (p.ConnectionKey === selectedPrinter.ConnectionKey &&
p.MacAddress === selectedPrinter.MacAddress &&
p.UserId === UserId &&
p.MappingPrintType === 'U') {
return { ...p, MappingType: newType };
}
return p;
@ -220,28 +223,28 @@ const PrinterSelection = (props) => {
// Remove duplicates by PrintUniqId, keep only unique entries
const uniquePrinters = [];
const seenKeys = new Set();
printers.forEach(printer => {
if (!seenKeys.has(printer.PrintUniqId)) {
seenKeys.add(printer.PrintUniqId);
uniquePrinters.push(printer);
}
});
console.log(uniquePrinters, 'uniquePrinters');
// IMPORTANT: Send ALL user mappings (both Y and N) so backend can remove mappings
// Filter to only user mappings (MappingPrintType === 'U') for current user
const userMappings = uniquePrinters.filter(p =>
const userMappings = uniquePrinters.filter(p =>
p.MappingPrintType === 'U' && p.UserId === UserId
);
const PostPrintMappingdata = {
AppId: AppId,
CompId: CompId,
BranchId: BranchId,
UserId: UserId,
UpdatedBy: UserId,
CompId: CompId,
BranchId: BranchId,
UserId: UserId,
UpdatedBy: UserId,
// Send all user mappings (Y and N) so removal works
PrintMappingDtl: userMappings
}
@ -250,14 +253,14 @@ const PrinterSelection = (props) => {
if (response?.data?.statusCode === 1) {
setMessageType("success");
setMessageData("Printer settings saved successfully.");
const data = {
AppId: AppId,
CompId: CompId,
BranchId: BranchId,
UserId: UserId
}
await dispatch(getPrinterMappingDetails(data)).unwrap();
getCounters();
const data = {
AppId: AppId,
CompId: CompId,
BranchId: BranchId,
UserId: UserId
}
await dispatch(getPrinterMappingDetails(data)).unwrap();
getCounters();
} else {
setMessageType("error");
setMessageData(response?.data?.message || "Failed to save printer settings.");
@ -277,16 +280,39 @@ const PrinterSelection = (props) => {
setPrinters((prev) =>
prev.map((p) => {
if (p.ConnectionKey === selectedPrinter.ConnectionKey &&
p.MacAddress === selectedPrinter.MacAddress &&
p.UserId === UserId &&
p.MappingPrintType === 'U') {
if (p.ConnectionKey === selectedPrinter.ConnectionKey &&
p.MacAddress === selectedPrinter.MacAddress &&
p.UserId === UserId &&
p.MappingPrintType === 'U'
) {
return { ...p, CustomerCopy: value };
}
return p;
})
);
};
const updateTokenAvailable = (printerId, type, checked) => {
const selectedPrinter = printers.find(p => p.id === printerId);
if (!selectedPrinter) return;
setPrinters((prev) =>
prev.map((p) => {
if (
p.ConnectionKey === selectedPrinter.ConnectionKey &&
p.MacAddress === selectedPrinter.MacAddress
) {
if (type === "Takeaway") {
return { ...p, TakeAwayTokenFlg: checked ? "Y" : "N" };
}
if (type === "Dine") {
return { ...p, DineInTokenFlg: checked ? "Y" : "N" };
}
}
return p;
})
);
};
const openKioskPrinter = () => {
setMyKioskPrinter(true);
setMyPrinter(false);
@ -306,7 +332,7 @@ const PrinterSelection = (props) => {
}}
/>
<div>
<div
<div
className="PrinterSettingSwitchBTN"
>
<div
@ -314,252 +340,281 @@ const PrinterSelection = (props) => {
onClick={openMyPrinter}
>
{/* <HiOutlineSquares2X2 size={16} /> */}
My Printer
My Printer
</div>
{FeatureAddonData?.FeatureDtls?.find(
(item) =>
item?.FeatureAddonName?.toLowerCase() === 'kiosk sales'
) &&
(item) =>
item?.FeatureAddonName?.toLowerCase() === 'kiosk sales'
) &&
<div
className={MyKioskPrinter ? 'selected' : ''}
onClick={openKioskPrinter}
onClick={openKioskPrinter}
>
{/* <HiSquaresPlus size={16} /> */}
Kiosk Printer
Kiosk Printer
</div>
}
</div>
</div>
{MyPrinter && (
<div>
<DropDowns
options={(() => {
const uniquePrinters = [];
const seenPhysicalIds = new Set();
const userMappedPhysicalIds = new Set();
// First, collect physical printer IDs (ConnectionKey + MacAddress)
// that are actively mapped to current user (MappingPrintType === 'U' && UserId === UserId && ChkStatus === 'Y')
// Only exclude printers that are currently active, not removed ones
printers.forEach(p => {
if (p.MappingPrintType === 'U' && p.UserId === UserId && p.ChkStatus === 'Y') {
userMappedPhysicalIds.add(p.id);
}
});
// Build dropdown: show each physical printer once
// Exclude printers actively mapped to current user (ChkStatus === 'Y')
// Include: unmapped (null), kiosk (K), removed user mappings (ChkStatus === 'N'), and other users' mappings
printers.forEach(p => {
const physicalId = p.id; // ConnectionKey + MacAddress
// Skip if this physical printer is actively mapped to current user (ChkStatus === 'Y')
if (userMappedPhysicalIds.has(physicalId)) return;
// Show each physical printer only once
if (!seenPhysicalIds.has(physicalId)) {
seenPhysicalIds.add(physicalId);
uniquePrinters.push({
label: `${p.ConnectionKey}${p.PrinterName && p.PrinterName !== 'Unknown' ? ` (${p.PrinterName})` : ''}${(p.MacAddress !== 'N/A' && p.MacAddress !== null) ? ` (${p.MacAddress})` : ''}`,
value: p.PrintUniqId, // Use PrintUniqId (will create new user mapping in toggleSetPrint)
});
}
});
return uniquePrinters;
})()}
defaultValue={null}
valueData={selectedPrinterId}
placeholder="Select Printer"
onChangeFunction={(value) => {
const printer = printers.find(p => p.PrintUniqId === value);
if (printer) {
toggleSetPrint(printer.PrintUniqId);
}
setSelectedPrinterId(null);
}}
/>
</div>
{MyPrinter && (
<div>
<DropDowns
options={(() => {
const uniquePrinters = [];
const seenPhysicalIds = new Set();
const userMappedPhysicalIds = new Set();
// First, collect physical printer IDs (ConnectionKey + MacAddress)
// that are actively mapped to current user (MappingPrintType === 'U' && UserId === UserId && ChkStatus === 'Y')
// Only exclude printers that are currently active, not removed ones
printers.forEach(p => {
if (p.MappingPrintType === 'U' && p.UserId === UserId && p.ChkStatus === 'Y') {
userMappedPhysicalIds.add(p.id);
}
});
// Build dropdown: show each physical printer once
// Exclude printers actively mapped to current user (ChkStatus === 'Y')
// Include: unmapped (null), kiosk (K), removed user mappings (ChkStatus === 'N'), and other users' mappings
printers.forEach(p => {
const physicalId = p.id; // ConnectionKey + MacAddress
// Skip if this physical printer is actively mapped to current user (ChkStatus === 'Y')
if (userMappedPhysicalIds.has(physicalId)) return;
// Show each physical printer only once
if (!seenPhysicalIds.has(physicalId)) {
seenPhysicalIds.add(physicalId);
uniquePrinters.push({
label: `${p.ConnectionKey}${p.PrinterName && p.PrinterName !== 'Unknown' ? ` (${p.PrinterName})` : ''}${(p.MacAddress !== 'N/A' && p.MacAddress !== null) ? ` (${p.MacAddress})` : ''}`,
value: p.PrintUniqId, // Use PrintUniqId (will create new user mapping in toggleSetPrint)
});
}
});
return uniquePrinters;
})()}
defaultValue={null}
valueData={selectedPrinterId}
placeholder="Select Printer"
onChangeFunction={(value) => {
const printer = printers.find(p => p.PrintUniqId === value);
if (printer) {
toggleSetPrint(printer.PrintUniqId);
}
setSelectedPrinterId(null);
}}
/>
<div
style={{
display: "flex",
flexWrap: "wrap",
gap: "16px",
fontFamily: "poppins",
marginTop: "16px"
}}
>
{(() => {
const uniquePrinters = [];
const seenKeys = new Set();
printers
.filter(p => p.ChkStatus === 'Y' && p.MappingPrintType === 'U' && p.UserId === UserId)
.forEach(printer => {
if (!seenKeys.has(printer.id)) {
seenKeys.add(printer.id);
uniquePrinters.push(printer);
}
});
return uniquePrinters;
})().map((printer) => (
<div
key={printer.PrintUniqId}
style={{
display: "flex",
flexWrap: "wrap",
gap: "16px",
fontFamily: "poppins",
marginTop: "16px"
flex: "1 1 calc(50% - 16px)",
border: "1px solid #ddd",
borderRadius: "6px",
padding: "16px",
boxShadow: "0 1px 3px rgba(0,0,0,0.1)",
background: "#fff",
transition: "all 0.3s ease",
}}
>
{(() => {
const uniquePrinters = [];
const seenKeys = new Set();
printers
.filter(p => p.ChkStatus === 'Y' && p.MappingPrintType === 'U' && p.UserId === UserId)
.forEach(printer => {
if (!seenKeys.has(printer.id)) {
seenKeys.add(printer.id);
uniquePrinters.push(printer);
}
});
return uniquePrinters;
})().map((printer) => (
<div
key={printer.PrintUniqId}
style={{
flex: "1 1 calc(50% - 16px)",
border: "1px solid #ddd",
borderRadius: "6px",
padding: "16px",
boxShadow: "0 1px 3px rgba(0,0,0,0.1)",
background: "#fff",
transition: "all 0.3s ease",
{/* Printer Name */}
<div style={{ marginBottom: "12px", fontWeight: "bold" }}>
🖨 {printer.name || printer.id}
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '1.5rem' }}>
<div>
<label
style={{
display: "flex",
alignItems: "center",
gap: "8px",
marginBottom: "12px",
fontWeight: "500",
color: "#0f5132",
background: "#d1e7dd",
padding: "8px 12px",
borderRadius: "4px",
border: "1px solid #badbcc",
transition: "all 0.2s ease-in-out",
}}
>
{/* Printer Name */}
<div style={{ marginBottom: "12px", fontWeight: "bold" }}>
🖨 {printer.name || printer.id}
</div>
<input
type="checkbox"
checked={printer.ChkStatus === 'Y' && printer.MappingPrintType === 'U'}
onChange={() => toggleSetPrint(printer.PrintUniqId)}
/>
Set for Print
</label>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '1.5rem' }}>
<div>
<label
style={{
display: "flex",
alignItems: "center",
gap: "8px",
marginBottom: "12px",
fontWeight: "500",
color: "#0f5132",
background: "#d1e7dd",
padding: "8px 12px",
borderRadius: "4px",
border: "1px solid #badbcc",
transition: "all 0.2s ease-in-out",
}}
>
<input
type="checkbox"
checked={printer.ChkStatus === 'Y' && printer.MappingPrintType === 'U'}
onChange={() => toggleSetPrint(printer.PrintUniqId)}
/>
Set for Print
</label>
</div>
<div>
<Switch
size="small"
checked={printer.MappingType === 'G'}
disabled={canEditPrinter(printer)}
onChange={(checked) => {
const newValue = checked ? 'G' : 'I';
updatePrinterMappingType(printer.id, newValue);
}}
checkedChildren="Group"
unCheckedChildren="Individual"
style={{
transform: 'scale(1.2)',
transformOrigin: 'left center',
width: '85px',
}}
/>
</div>
<div>
<label style={{ display: "block", fontSize: "0.85rem", fontWeight: 500 }}>
Customer Copy
</label>
<input
type="number"
min="1"
placeholder="1"
value={printer.CustomerCopy}
onChange={(e) => updateCustomerCopy(printer.id, e.target.value)}
style={{
width: "70px",
padding: "6px 8px",
borderRadius: "4px",
border: "1px solid #ccc",
outline: "none",
}}
/>
</div>
<div>
<label style={{ display: "block", fontSize: "0.85rem", fontWeight: 500 }}>
Token Printer setup
</label>
<div>
<Switch
size="small"
checked={printer.MappingType === 'G'}
disabled={canEditPrinter(printer)}
onChange={(checked) => {
const newValue = checked ? 'G' : 'I';
updatePrinterMappingType(printer.id, newValue);
}}
checkedChildren="Group"
unCheckedChildren="Individual"
style={{
transform: 'scale(1.2)',
transformOrigin: 'left center',
width: '85px',
}}
/>
</div>
<div>
<label style={{ display: "block", fontSize: "0.85rem", fontWeight: 500 }}>
Customer Copy
</label>
<input
type="number"
min="1"
placeholder="1"
value={printer.CustomerCopy}
onChange={(e) => updateCustomerCopy(printer.id, e.target.value)}
style={{
width: "70px",
padding: "6px 8px",
borderRadius: "4px",
border: "1px solid #ccc",
outline: "none",
}}
/>
</div>
</div>
<label style={{ display: "inline-flex", alignItems: "center", marginRight: "12px" }}>
<input
style={{ marginRight: "6px" }}
type="checkbox"
checked={printer.TakeAwayTokenFlg == "Y"}
onChange={(e) =>
updateTokenAvailable(printer.id, "Takeaway", e.target.checked)
}
/>
Takeaway
</label>
<div
<label style={{ display: "inline-flex", alignItems: "center" }}>
<input
style={{ marginRight: "6px" }}
type="checkbox"
checked={printer.DineInTokenFlg == "Y"}
onChange={(e) =>
updateTokenAvailable(printer.id, "Dine", e.target.checked)
}
/>
Dine
</label>
</div>
</div>
<div
style={{
display: "flex",
flexWrap: "wrap",
gap: "12px",
width: "100%",
background: "#f8f9fa",
padding: "12px",
borderRadius: "6px",
border: "1px solid #ddd",
}}
>
{counters?.map((counter) => {
const isCounterUsedElsewhere = printers?.some(
(p) => p.id !== printer.id && p.CounterId === counter.CounterId
);
return (
<label
key={counter.CounterId}
style={{
width: "calc(50% - 6px)",
fontWeight: "normal",
display: "flex",
flexWrap: "wrap",
gap: "12px",
width: "100%",
background: "#f8f9fa",
padding: "12px",
borderRadius: "6px",
border: "1px solid #ddd",
alignItems: "center",
gap: "8px",
opacity: isCounterUsedElsewhere ? 0.4 : 1, // Optional: make it look visually disabled
}}
>
{counters?.map((counter) => {
const isCounterUsedElsewhere = printers?.some(
(p) => p.id !== printer.id && p.CounterId === counter.CounterId
);
return (
<label
key={counter.CounterId}
style={{
width: "calc(50% - 6px)",
fontWeight: "normal",
display: "flex",
alignItems: "center",
gap: "8px",
opacity: isCounterUsedElsewhere ? 0.4 : 1, // Optional: make it look visually disabled
}}
>
<input
type="checkbox"
checked={printer.CounterId === counter.CounterId}
onChange={() => toggleCounter(printer.id, counter)}
disabled={isCounterUsedElsewhere}
/>
{counter?.CounterName}
</label>
);
})}
</div>
</div>
))}
<input
type="checkbox"
checked={printer.CounterId === counter.CounterId}
onChange={() => toggleCounter(printer.id, counter)}
disabled={isCounterUsedElsewhere}
/>
{counter?.CounterName}
</label>
);
})}
</div>
</div>
))}
<div
style={{
width: "100%",
display: "flex",
justifyContent: "flex-end",
marginTop: 24,
}}
>
<Buttons
buttonText="Save"
color="901D77"
icon={<ArrowRightOutlined />}
htmlType={true}
handleSubmit={handleSave}
/>
</div>
</div>
)}
{MyKioskPrinter && (
<div>
{' '}
<KioskPrinterSelection
// onClose={() => setOpenModel(false)}
</div>
<div
style={{
width: "100%",
display: "flex",
justifyContent: "flex-end",
marginTop: 24,
}}
>
<Buttons
buttonText="Save"
color="901D77"
icon={<ArrowRightOutlined />}
htmlType={true}
handleSubmit={handleSave}
/>
</div>
)}
</div>
)}
{MyKioskPrinter && (
<div>
{' '}
<KioskPrinterSelection
// onClose={() => setOpenModel(false)}
/>
</div>
)}
</div>
);
};