From 96964f4f00a4fc97b5ddc5f750c09747d72d4445 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Nov 2025 07:19:30 +0000 Subject: [PATCH 1/3] feat: add URL query params for page and status filter in repair admin - Initialize page and statusFilter from URL query parameters on mount - Update URL when page or statusFilter state changes - Support comma-separated status values in URL - Enables sharing specific page/filter state via URL - Preserves state on page refresh --- src/pages/repair/RepairAdmin.tsx | 34 ++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/pages/repair/RepairAdmin.tsx b/src/pages/repair/RepairAdmin.tsx index 56ea569..2124111 100644 --- a/src/pages/repair/RepairAdmin.tsx +++ b/src/pages/repair/RepairAdmin.tsx @@ -188,12 +188,27 @@ export const validateRepairRole = (roles: string[]) => { export default function App() { const [isLoading, setIsLoading] = useState(true) - const [page, setPage] = useState(1) + + // Initialize state from URL query params + const getInitialPage = () => { + const params = new URLSearchParams(window.location.search) + const pageParam = params.get('page') + return pageParam ? parseInt(pageParam, 10) : 1 + } + + const getInitialStatusFilter = () => { + const params = new URLSearchParams(window.location.search) + const statusParam = params.get('status') + if (statusParam) { + return statusParam.split(',').filter(Boolean) + } + return UserEventStatus.filter(v => v.status !== EventStatus.cancelled).map(v => v.status) + } + + const [page, setPage] = useState(getInitialPage()) const rowsPerPage = 10 const [totalCount, setTotalCount] = useState(0) - const [statusFilter, setStatusFilter] = useState( - UserEventStatus.filter(v => v.status !== EventStatus.cancelled).map(v => v.status), - ) + const [statusFilter, setStatusFilter] = useState(getInitialStatusFilter()) const { isOpen, onOpen, onOpenChange } = useDisclosure() const [userInfo, setUserInfo] = useState() const [currentMember, setCurrentMember] = useState() @@ -282,6 +297,17 @@ export default function App() { return Math.ceil(totalCount / rowsPerPage) }, [totalCount, rowsPerPage]) + // Update URL query params when page or statusFilter changes + useEffect(() => { + const params = new URLSearchParams() + params.set('page', page.toString()) + if (statusFilter.length > 0) { + params.set('status', statusFilter.join(',')) + } + const newUrl = `${window.location.pathname}?${params.toString()}` + window.history.replaceState({}, '', newUrl) + }, [page, statusFilter]) + useEffect(() => { setPage(1) list.reload() From 8720a56c7d392f3fc8469fdf382d4a405e367f8b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Nov 2025 07:24:01 +0000 Subject: [PATCH 2/3] feat: add eventid query parameter to auto-open event details - Add eventid URL parameter support to open specific event on page load - Automatically fetch and display event detail drawer when eventid is present - Show error message if event ID is invalid or doesn't exist - Update URL when opening/closing event detail drawer - Add error message UI with dismiss functionality - Maintain eventid in URL for shareable links to specific events --- src/pages/repair/RepairAdmin.tsx | 82 ++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/src/pages/repair/RepairAdmin.tsx b/src/pages/repair/RepairAdmin.tsx index 2124111..9044c08 100644 --- a/src/pages/repair/RepairAdmin.tsx +++ b/src/pages/repair/RepairAdmin.tsx @@ -213,6 +213,7 @@ export default function App() { const [userInfo, setUserInfo] = useState() const [currentMember, setCurrentMember] = useState() const [token, setToken] = useState() + const [errorMessage, setErrorMessage] = useState("") useEffect(() => { const check = async () => { @@ -244,6 +245,39 @@ export default function App() { check() }, []) + // Handle eventid query parameter to auto-open event detail + useEffect(() => { + const loadEventFromUrl = async () => { + if (!token) return // Wait for authentication + + const params = new URLSearchParams(window.location.search) + const eventId = params.get('eventid') + + if (eventId) { + try { + const { data, error } = await saturdayClient.GET("/events/{eventId}", { + params: { + path: { + eventId: eventId, + }, + }, + }) + + if (error || !data) { + setErrorMessage(`无法找到工单 #${eventId},该工单可能不存在或已被删除`) + } else { + setActiveEvent(data as PublicEvent) + onOpen() + } + } catch (err) { + setErrorMessage(`加载工单 #${eventId} 时出错`) + } + } + } + + loadEventFromUrl() + }, [token]) + const list = useAsyncList({ async load() { setIsLoading(true) @@ -299,10 +333,12 @@ export default function App() { // Update URL query params when page or statusFilter changes useEffect(() => { - const params = new URLSearchParams() + const params = new URLSearchParams(window.location.search) params.set('page', page.toString()) if (statusFilter.length > 0) { params.set('status', statusFilter.join(',')) + } else { + params.delete('status') } const newUrl = `${window.location.pathname}?${params.toString()}` window.history.replaceState({}, '', newUrl) @@ -367,6 +403,22 @@ export default function App() { const onOpenEventDetail = (event: PublicEvent) => { setActiveEvent(event) onOpen() + + // Update URL with eventid + const params = new URLSearchParams(window.location.search) + params.set('eventid', event.eventId) + const newUrl = `${window.location.pathname}?${params.toString()}` + window.history.replaceState({}, '', newUrl) + } + + const onCloseEventDetail = () => { + onOpenChange() + + // Remove eventid from URL + const params = new URLSearchParams(window.location.search) + params.delete('eventid') + const newUrl = `${window.location.pathname}?${params.toString()}` + window.history.replaceState({}, '', newUrl) } const MobileEventCard = ({ event }: { event: PublicEvent }) => ( @@ -566,13 +618,35 @@ export default function App() { } isOpen={isOpen} onOpenChange={onOpenChange} - onClose={() => { - onOpenChange() - }} + onClose={onCloseEventDetail} onDelete={() => {}} onEdit={() => {}} > + + {/* Error Message Display */} + {errorMessage && ( +
+
+
+ + + +
+

{errorMessage}

+
+ +
+
+
+ )} ) } From dda92f566443d6dab357f2b9080b9bd26fb69baa Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Nov 2025 07:28:52 +0000 Subject: [PATCH 3/3] fix: ensure eventid is removed from URL when drawer closes - Replace onCloseEventDetail with handleDrawerOpenChange - Handle all drawer close scenarios: button click, outside click, ESC key - Remove eventid from URL whenever drawer is closed via any method - Fixes issue where eventid remained in URL after closing drawer --- src/pages/repair/RepairAdmin.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/pages/repair/RepairAdmin.tsx b/src/pages/repair/RepairAdmin.tsx index 9044c08..0054e79 100644 --- a/src/pages/repair/RepairAdmin.tsx +++ b/src/pages/repair/RepairAdmin.tsx @@ -411,14 +411,16 @@ export default function App() { window.history.replaceState({}, '', newUrl) } - const onCloseEventDetail = () => { + const handleDrawerOpenChange = (isOpen: boolean) => { onOpenChange() - // Remove eventid from URL - const params = new URLSearchParams(window.location.search) - params.delete('eventid') - const newUrl = `${window.location.pathname}?${params.toString()}` - window.history.replaceState({}, '', newUrl) + // Remove eventid from URL when drawer is closed + if (!isOpen) { + const params = new URLSearchParams(window.location.search) + params.delete('eventid') + const newUrl = `${window.location.pathname}?${params.toString()}` + window.history.replaceState({}, '', newUrl) + } } const MobileEventCard = ({ event }: { event: PublicEvent }) => ( @@ -617,8 +619,8 @@ export default function App() { } } isOpen={isOpen} - onOpenChange={onOpenChange} - onClose={onCloseEventDetail} + onOpenChange={handleDrawerOpenChange} + onClose={() => handleDrawerOpenChange(false)} onDelete={() => {}} onEdit={() => {}} >