From e722af9426c5d29b38247c4e06dedee268b52ceb Mon Sep 17 00:00:00 2001 From: Lars Mitsem Selbekk Date: Wed, 12 Jun 2024 02:17:31 +0200 Subject: [PATCH] feat(scanner): immediately refresh match on scan Improve the time from scanning until the match visually updating by immediately refreshing from the API on succesful scan. Would be even faster to optimistically update the local cache of the date, but that's harder and not really necessary. Also rate limited the API transfer call to 4x per second as the API did not handle races well, leading to some cases of multiple customerItems active at the same time for one item, which caused a "not active" error in the scanner as number active == 1 is an assert in the API. --- src/components/matches/MatchDetail.tsx | 12 ++++++++++-- src/components/matches/Scanner/ScannerModal.tsx | 13 +++++++++++-- src/components/matches/UserMatchDetail.tsx | 3 +++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/components/matches/MatchDetail.tsx b/src/components/matches/MatchDetail.tsx index cd70963..582eaac 100644 --- a/src/components/matches/MatchDetail.tsx +++ b/src/components/matches/MatchDetail.tsx @@ -17,7 +17,11 @@ const MatchDetail = ({ matchId }: { matchId: string }) => { ); const userId = accessToken?.details; - const { data: matches, error: matchesError } = useSWR( + const { + data: matches, + error: matchesError, + mutate: updateMatches, + } = useSWR( `${BL_CONFIG.collection.match}/me`, apiFetcher, { refreshInterval: 5000 }, @@ -64,7 +68,11 @@ const MatchDetail = ({ matchId }: { matchId: string }) => { )} {match._variant === MatchVariant.UserMatch && ( - + updateMatches()} + /> )} diff --git a/src/components/matches/Scanner/ScannerModal.tsx b/src/components/matches/Scanner/ScannerModal.tsx index fc834d7..e0f2bf0 100644 --- a/src/components/matches/Scanner/ScannerModal.tsx +++ b/src/components/matches/Scanner/ScannerModal.tsx @@ -36,12 +36,14 @@ type Feedback = { const ScannerModal = ({ open, handleClose, + handleItemTransferred, itemStatuses, expectedItems, fulfilledItems, }: { open: boolean; handleClose: () => void; + handleItemTransferred?: (() => void) | undefined; itemStatuses: ItemStatus[]; expectedItems: string[]; fulfilledItems: string[]; @@ -91,6 +93,7 @@ const ScannerModal = ({ severity: feedback ? "info" : "success", visible: true, }); + handleItemTransferred?.(); } catch (error) { setFeedback({ text: String(error), @@ -136,9 +139,15 @@ const ScannerModal = ({ constraints={{ facingMode: "environment" }} formats={["qr_code", "code_128", "ean_8", "ean_13"]} components={{ torch: true }} - onScan={(detectedCodes) => { + onScan={async (detectedCodes) => { for (const code of detectedCodes) { - handleRegistration(code.rawValue); + await handleRegistration(code.rawValue).catch((error) => + console.error("Failed to handle scan", error), + ); + // Arbitrary delay to somewhat avoid races the backend isn't smart enough to handle + await new Promise((resolve) => { + window.setTimeout(resolve, 250); + }); } }} /> diff --git a/src/components/matches/UserMatchDetail.tsx b/src/components/matches/UserMatchDetail.tsx index b7c7235..044d77a 100644 --- a/src/components/matches/UserMatchDetail.tsx +++ b/src/components/matches/UserMatchDetail.tsx @@ -21,9 +21,11 @@ import { UserMatchWithDetails } from "@/utils/types"; const UserMatchDetail = ({ match, currentUserId, + handleItemTransferred, }: { match: UserMatchWithDetails; currentUserId: string; + handleItemTransferred?: (() => void) | undefined; }) => { const [scanModalOpen, setScanModalOpen] = useState(false); const [redirectCountdownStarted, setRedirectCountdownStarted] = @@ -136,6 +138,7 @@ const UserMatchDetail = ({ { setScanModalOpen(false); setRedirectCountdownStarted(isFulfilled);