From b322bd23b6174939a06eede8242714e7f3c2ee5a Mon Sep 17 00:00:00 2001 From: Muhsina13 Date: Tue, 19 May 2026 15:00:06 +0530 Subject: [PATCH 1/2] unrestricted checkout --- screens/AttendanceAction.jsx | 17 +++++++++++++++-- screens/QrScan.jsx | 15 +++++++++------ services/api/attendance.service.js | 14 +++++++++++++- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/screens/AttendanceAction.jsx b/screens/AttendanceAction.jsx index 6ceab66..9b5f718 100644 --- a/screens/AttendanceAction.jsx +++ b/screens/AttendanceAction.jsx @@ -78,6 +78,7 @@ function AttendanceAction() { const [distanceInfo, setDistanceInfo] = useState(null); const [actionLoading, setActionLoading] = useState(false); const [restrictLocation, setRestrictLocation] = useState("0"); + const [unrestrictedCheckout, setUnrestrictedCheckout] = useState("0"); const [restrictionLoaded, setRestrictionLoaded] = useState(false); const [onBreak, setOnBreak] = useState(false); const [liveBreakTime, setLiveBreakTime] = useState("00:00:00"); @@ -125,8 +126,10 @@ function AttendanceAction() { useEffect(() => { const loadRestriction = async () => { const r = await AsyncStorage.getItem("restrict_location"); + const u = await AsyncStorage.getItem("unrestricted_checkout_location"); if (!isMountedRef.current) return; setRestrictLocation(r === "1" ? "1" : "0"); + setUnrestrictedCheckout(u === "1" ? "1" : "0"); setRestrictionLoaded(true); }; loadRestriction(); @@ -745,6 +748,7 @@ function AttendanceAction() { ); } + const allowCheckoutAnywhere = checkin && unrestrictedCheckout === "1"; return ( { try { diff --git a/screens/QrScan.jsx b/screens/QrScan.jsx index 8540580..9bd0f70 100644 --- a/screens/QrScan.jsx +++ b/screens/QrScan.jsx @@ -49,7 +49,8 @@ function QrScan() { "Employee_Code", "Full_Name", "Photo", - "Restrict Location", // :point_left: NEW FIELD + "Restrict Location", + "Unrestricted Checkout Location", "User_id", "API", "App_key", @@ -60,8 +61,8 @@ function QrScan() { value = value .replace(/[\u0000-\u001F\u00A0]+/g, " ") .replace( - /[%#;]+(?:\s+)?(Company|Employee_Code|Full_Name|Photo|Restrict Location|User_id|API|App_key)(?:\s*[:=])/g, - (_, key) => `${key}:` + /[%#;]+(?:\s+)?(Company|Employee_Code|Full_Name|Photo|Restrict Location|Unrestricted Checkout Location|User_id|API|App_key)(?:\s*[:=])/g, + (_, key) => `${key}:`, ) .replace(/[^\S\r\n]+/g, " ") .trim(); @@ -70,7 +71,7 @@ function QrScan() { const keyAlt = KEYS.join("|"); const pairRE = new RegExp( `\\b(${keyAlt})\\s*[:=]\\s*([\\s\\S]*?)(?=\\s*(?:${keyAlt})\\s*[:=]|$)`, - "gi" + "gi", ); let m; while ((m = pairRE.exec(value))) { @@ -106,6 +107,7 @@ function QrScan() { app_key: appKey, photo: photoFlag, restrict_location: qrData["Restrict Location"]?.trim() ?? "0", // :point_left: NEW + unrestricted_checkout_location: qrData["Unrestricted Checkout Location"]?.trim() ?? "0", }; // :eight: Validate required fields if ( @@ -122,6 +124,7 @@ function QrScan() { ["baseUrl", cleanedData.baseUrl], ["photo", String(cleanedData.photo)], ["restrict_location", cleanedData.restrict_location], // :point_left: NEW + ["unrestricted_checkout_location", cleanedData.unrestricted_checkout_location], ]); // Redux dispatch (NO restrict_location) dispatch(setUsername(cleanedData.api_key)); @@ -151,7 +154,7 @@ function QrScan() { if (result?.canceled) return; if (result.assets[0]?.uri) { const scannedResults = await Camera.scanFromURLAsync( - result.assets[0].uri + result.assets[0].uri, ); const { data } = scannedResults[0]; await handleQRCodeData(data); @@ -234,4 +237,4 @@ function QrScan() { ); } -export default QrScan; \ No newline at end of file +export default QrScan; diff --git a/services/api/attendance.service.js b/services/api/attendance.service.js index ca44ec0..caa283a 100644 --- a/services/api/attendance.service.js +++ b/services/api/attendance.service.js @@ -198,11 +198,23 @@ export const userCheckIn = async ({ employeeCode, type, locationData }) => { const restrictLocation = ( await AsyncStorage.getItem("restrict_location") )?.trim(); + + const unrestrictedCheckout = ( + await AsyncStorage.getItem("unrestricted_checkout_location") + )?.trim(); + let nearest = null; let radius = null; // 📍 Location restriction is enabled - if (restrictLocation && restrictLocation.toString() === "1") { + const shouldSkipLocationRestriction = + type === "OUT" && unrestrictedCheckout === "1"; + + if ( + !shouldSkipLocationRestriction && + restrictLocation && + restrictLocation.toString() === "1" + ) { nearest = await getOfficeLocation(employeeCode); // Returns closest office + distance if (!nearest) { From 5be4bfd86a0af1b51c798e28dd4c1ca2476567c7 Mon Sep 17 00:00:00 2001 From: Muhsina13 Date: Tue, 19 May 2026 17:11:23 +0530 Subject: [PATCH 2/2] final --- screens/AttendanceAction.jsx | 5 +++-- screens/AttendanceCamera.jsx | 9 ++++++++- screens/QrScan.jsx | 13 +++++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/screens/AttendanceAction.jsx b/screens/AttendanceAction.jsx index 9b5f718..0bcc7d0 100644 --- a/screens/AttendanceAction.jsx +++ b/screens/AttendanceAction.jsx @@ -748,8 +748,9 @@ function AttendanceAction() { ); } - const allowCheckoutAnywhere = checkin && unrestrictedCheckout === "1"; - + const allowCheckoutAnywhere = + checkin === true && unrestrictedCheckout === "1"; + return ( ); } + return (