From b53637611023195aee0c3522829a16e9ddbbdbb1 Mon Sep 17 00:00:00 2001
From: Taesung Hwang <44419552+taesungh@users.noreply.github.com>
Date: Sun, 28 Jan 2024 07:49:21 -0800
Subject: [PATCH] Implement temporary badge scanner search feature (#380)
- Add **Scan Badge** button to header actions
- Load modal with badge scanner to update participants search filter
---
.../components/ParticipantsTable.tsx | 169 ++++++++++--------
.../components/SearchScannerModal.tsx | 45 +++++
2 files changed, 144 insertions(+), 70 deletions(-)
create mode 100644 apps/site/src/app/admin/participants/components/SearchScannerModal.tsx
diff --git a/apps/site/src/app/admin/participants/components/ParticipantsTable.tsx b/apps/site/src/app/admin/participants/components/ParticipantsTable.tsx
index f8294f72..b84e42b1 100644
--- a/apps/site/src/app/admin/participants/components/ParticipantsTable.tsx
+++ b/apps/site/src/app/admin/participants/components/ParticipantsTable.tsx
@@ -17,6 +17,7 @@ import CheckinDayIcon from "./CheckinDayIcon";
import ParticipantAction from "./ParticipantAction";
import ParticipantsFilters from "./ParticipantsFilters";
import RoleBadge from "./RoleBadge";
+import SearchScannerModal from "./SearchScannerModal";
const FRIDAY = new Date("2024-01-26T12:00:00");
const SATURDAY = new Date("2024-01-27T12:00:00");
@@ -149,6 +150,7 @@ function ParticipantsTable({
sorting: {},
selection: {},
});
+
const allRoles = new Set(participants.map((p) => p.role));
const roleOptions = Array.from(allRoles).map((r) => ({ value: r, label: r }));
const allStatuses = new Set(participants.map((p) => p.status));
@@ -247,77 +249,104 @@ function ParticipantsTable({
);
+ const [showScanner, setShowScanner] = useState(false);
+
+ const openScanner = () => {
+ setShowScanner(true);
+ };
+
+ const cancelScanner = () => {
+ setShowScanner(false);
+ };
+
+ const useScannerValue = (value: string) => {
+ actions.setFiltering(value);
+ setShowScanner(false);
+ };
+
return (
-
Participants
- }
- columnDefinitions={columnDefinitions}
- visibleColumns={preferences.visibleContent}
- items={items}
- loading={loading}
- loadingText="Loading participants"
- variant="full-page"
- stickyColumns={{ first: 1, last: 0 }}
- trackBy="_id"
- empty={emptyMessage}
- filter={
-
- }
- pagination={
- `Go to page ${pageNumber}`,
- previousPageLabel: "Previous page",
- }}
- />
- }
- preferences={
- ({
- id,
- label: header,
- })),
- },
- ],
- }}
- cancelLabel="Cancel"
- confirmLabel="Confirm"
- title="Preferences"
- preferences={preferences}
- onConfirm={({ detail }) =>
- setPreferences(
- detail as { pageSize: number; visibleContent: Array },
- )
- }
- />
- }
- />
+ <>
+
+ Scan Badge}
+ >
+ Participants
+
+ }
+ columnDefinitions={columnDefinitions}
+ visibleColumns={preferences.visibleContent}
+ items={items}
+ loading={loading}
+ loadingText="Loading participants"
+ variant="full-page"
+ stickyColumns={{ first: 1, last: 0 }}
+ trackBy="_id"
+ empty={emptyMessage}
+ filter={
+
+ }
+ pagination={
+ `Go to page ${pageNumber}`,
+ previousPageLabel: "Previous page",
+ }}
+ />
+ }
+ preferences={
+ ({
+ id,
+ label: header,
+ })),
+ },
+ ],
+ }}
+ cancelLabel="Cancel"
+ confirmLabel="Confirm"
+ title="Preferences"
+ preferences={preferences}
+ onConfirm={({ detail }) =>
+ setPreferences(
+ detail as { pageSize: number; visibleContent: Array },
+ )
+ }
+ />
+ }
+ />
+ >
);
}
diff --git a/apps/site/src/app/admin/participants/components/SearchScannerModal.tsx b/apps/site/src/app/admin/participants/components/SearchScannerModal.tsx
new file mode 100644
index 00000000..9fa1a357
--- /dev/null
+++ b/apps/site/src/app/admin/participants/components/SearchScannerModal.tsx
@@ -0,0 +1,45 @@
+import { useCallback } from "react";
+
+import Box from "@cloudscape-design/components/box";
+import Button from "@cloudscape-design/components/button";
+import Modal from "@cloudscape-design/components/modal";
+
+import BadgeScanner from "@/lib/admin/BadgeScanner";
+
+export interface SearchScannerProps {
+ onDismiss: () => void;
+ onConfirm: (value: string) => void;
+ show: boolean;
+}
+
+function SearchScannerModal({
+ onDismiss,
+ onConfirm,
+ show,
+}: SearchScannerProps) {
+ const onScanSuccess = useCallback(
+ (decodedText: string) => {
+ onConfirm(decodedText);
+ },
+ [onConfirm],
+ );
+
+ return (
+
+
+
+ }
+ header="Scan badge"
+ >
+ {show && null} />}
+
+ );
+}
+
+export default SearchScannerModal;