+ items={filteredUser}
+ columns={columns}
+ pagingController={pagingController}
+ setPagingController={setPagingController}
+ totalCount={filteredUser.length}
+ isAutoPaging={true}
+ />
+ {/* Add select all and view selected buttons */}
+
+
+
+
+
+ {/* Print and Download Section */}
+
+
+
+ options={filteredPrinters}
+ value={selectedPrinter ?? null}
+ onChange={(event, value) => {
+ setSelectedPrinter(value ?? undefined);
+ }}
+ getOptionLabel={(option) => option.name || option.label || option.code || String(option.id)}
+ renderInput={(params) => (
+
+ )}
+ />
+ {
+ const value = parseInt(e.target.value) || 1;
+ setPrintQty(Math.max(1, value));
+ }}
+ inputProps={{ min: 1 }}
+ sx={{ width: 120 }}
+ />
+ }
+ onClick={handlePrint}
+ disabled={checkboxIds.length === 0 || filteredPrinters.length === 0}
+ color="primary"
+ >
+ 列印
+
+ }
+ onClick={handleViewSelectedQrCodes}
+ disabled={checkboxIds.length === 0}
+ color="primary"
+ >
+ 下載QR碼
+
+
+
+
+ {/* PDF Preview Modal - Simple preview only */}
+
+
+ {/* Header with close button only */}
+
+
+
+
+
+
+ {/* PDF Preview */}
+
+ {previewUrl && (
+
+ )}
+
+
+
+ >
+ );
+};
+
+export default QrCodeHandleSearch;
\ No newline at end of file
diff --git a/src/components/qrCodeHandles/qrCodeHandleSearchLoading.tsx b/src/components/qrCodeHandles/qrCodeHandleSearchLoading.tsx
new file mode 100644
index 0000000..fa580af
--- /dev/null
+++ b/src/components/qrCodeHandles/qrCodeHandleSearchLoading.tsx
@@ -0,0 +1,40 @@
+import Card from "@mui/material/Card";
+import CardContent from "@mui/material/CardContent";
+import Skeleton from "@mui/material/Skeleton";
+import Stack from "@mui/material/Stack";
+import React from "react";
+
+// Can make this nicer
+export const qrCodeHandleSearchLoading: React.FC = () => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default qrCodeHandleSearchLoading;
diff --git a/src/components/qrCodeHandles/qrCodeHandleSearchWrapper.tsx b/src/components/qrCodeHandles/qrCodeHandleSearchWrapper.tsx
new file mode 100644
index 0000000..e884c01
--- /dev/null
+++ b/src/components/qrCodeHandles/qrCodeHandleSearchWrapper.tsx
@@ -0,0 +1,21 @@
+import React from "react";
+import QrCodeHandleSearch from "./qrCodeHandleSearch";
+import QrCodeHandleSearchLoading from "./qrCodeHandleSearchLoading";
+import { fetchUser } from "@/app/api/user";
+import { fetchPrinterCombo } from "@/app/api/settings/printer";
+
+interface SubComponents {
+ Loading: typeof QrCodeHandleSearchLoading;
+}
+
+const QrCodeHandleSearchWrapper: React.FC & SubComponents = async () => {
+ const [users, printerCombo] = await Promise.all([
+ fetchUser(),
+ fetchPrinterCombo(),
+ ]);
+ return ;
+};
+
+QrCodeHandleSearchWrapper.Loading = QrCodeHandleSearchLoading;
+
+export default QrCodeHandleSearchWrapper;
\ No newline at end of file
diff --git a/src/components/qrCodeHandles/qrCodeHandleTabs.tsx b/src/components/qrCodeHandles/qrCodeHandleTabs.tsx
new file mode 100644
index 0000000..1e56940
--- /dev/null
+++ b/src/components/qrCodeHandles/qrCodeHandleTabs.tsx
@@ -0,0 +1,66 @@
+"use client";
+
+import { useState, ReactNode } from "react";
+import { Box, Tabs, Tab } from "@mui/material";
+import { useTranslation } from "react-i18next";
+
+interface TabPanelProps {
+ children?: ReactNode;
+ index: number;
+ value: number;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && {children}}
+
+ );
+}
+
+interface QrCodeHandleTabsProps {
+ userTabContent: ReactNode;
+ equipmentTabContent: ReactNode;
+}
+
+const QrCodeHandleTabs: React.FC = ({
+ userTabContent,
+ equipmentTabContent,
+}) => {
+ const { t } = useTranslation("common");
+ const { t: tUser } = useTranslation("user");
+ const [currentTab, setCurrentTab] = useState(0);
+
+ const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
+ setCurrentTab(newValue);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ {userTabContent}
+
+
+
+ {equipmentTabContent}
+
+
+ );
+};
+
+export default QrCodeHandleTabs;
\ No newline at end of file
diff --git a/src/main/java/com/ffii/fpsms/modules/user/req/UpdateUserReq.java b/src/main/java/com/ffii/fpsms/modules/user/req/UpdateUserReq.java
new file mode 100644
index 0000000..b28b04f
--- /dev/null
+++ b/src/main/java/com/ffii/fpsms/modules/user/req/UpdateUserReq.java
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/main/java/com/ffii/fpsms/modules/user/web/UserController.java b/src/main/java/com/ffii/fpsms/modules/user/web/UserController.java
new file mode 100644
index 0000000..b28b04f
--- /dev/null
+++ b/src/main/java/com/ffii/fpsms/modules/user/web/UserController.java
@@ -0,0 +1,3 @@
+
+
+