mirror of
https://github.com/m1ngsama/FUJI.git
synced 2025-12-24 10:51:27 +00:00
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
This commit is contained in:
parent
96964f4f00
commit
8720a56c7d
1 changed files with 78 additions and 4 deletions
|
|
@ -213,6 +213,7 @@ export default function App() {
|
|||
const [userInfo, setUserInfo] = useState<UserInfoResponse>()
|
||||
const [currentMember, setCurrentMember] = useState<PublicMember>()
|
||||
const [token, setToken] = useState<string>()
|
||||
const [errorMessage, setErrorMessage] = useState<string>("")
|
||||
|
||||
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<PublicEvent>({
|
||||
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={() => {}}
|
||||
>
|
||||
</TicketDetailDrawer>
|
||||
|
||||
{/* Error Message Display */}
|
||||
{errorMessage && (
|
||||
<div className="fixed bottom-4 left-1/2 transform -translate-x-1/2 z-50 max-w-md w-full mx-4">
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4 shadow-lg">
|
||||
<div className="flex items-start gap-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 text-red-600 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<div className="flex-1">
|
||||
<p className="text-sm font-medium text-red-800">{errorMessage}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setErrorMessage("")}
|
||||
className="text-red-400 hover:text-red-600 flex-shrink-0"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue