SessionTimeoutModal.tsx107 lines · main
1import * as Sentry from '@sentry/nextjs'
2import { SupportCategories } from '@supabase/shared-types/out/constants'
3import { useEffect } from 'react'
4import { toast } from 'sonner'
5import {
6 AlertDialog,
7 AlertDialogAction,
8 AlertDialogCancel,
9 AlertDialogContent,
10 AlertDialogDescription,
11 AlertDialogFooter,
12 AlertDialogHeader,
13 AlertDialogTitle,
14 Button,
15} from 'ui'
16import { CollapsibleAlert } from 'ui-patterns/collapsible-alert'
17
18import { SupportLink } from '../Support/SupportLink'
19import { InlineLink, InlineLinkClassName } from '@/components/ui/InlineLink'
20
21interface SessionTimeoutModalProps {
22 visible: boolean
23 onClose: () => void
24 redirectToSignIn: () => void
25 /** Optional context so the support form can pre-populate when opened from this dialog */
26 supportContext?: { projectRef?: string; orgSlug?: string }
27}
28
29export const SessionTimeoutModal = ({
30 visible,
31 onClose,
32 redirectToSignIn,
33 supportContext,
34}: SessionTimeoutModalProps) => {
35 useEffect(() => {
36 if (visible) {
37 Sentry.captureException(new Error('Session error detected'))
38 }
39 }, [visible])
40
41 const handleClearStorage = () => {
42 try {
43 localStorage.clear()
44 sessionStorage.clear()
45 } catch (e) {
46 toast.error('Failed to clear browser storage')
47 }
48 window.location.reload()
49 }
50
51 return (
52 <AlertDialog
53 open={visible}
54 onOpenChange={(open) => {
55 if (!open) onClose()
56 }}
57 >
58 <AlertDialogContent size="small">
59 <AlertDialogHeader>
60 <AlertDialogTitle>Session expired</AlertDialogTitle>
61 <AlertDialogDescription asChild>
62 <div className="space-y-4">
63 <p>Please sign in again to continue.</p>
64 <CollapsibleAlert trigger="Having trouble?">
65 <div className="space-y-3 text-foreground-light">
66 <p>
67 Try a different browser or disable extensions that block network requests. If
68 the problem persists:
69 </p>
70 <Button type="default" size="tiny" onClick={handleClearStorage}>
71 Clear site data and reload
72 </Button>
73 <p>
74 Still stuck?{' '}
75 <SupportLink
76 className={InlineLinkClassName}
77 queryParams={{
78 subject: 'Session expired',
79 category: SupportCategories.LOGIN_ISSUES,
80 ...(supportContext?.projectRef && {
81 projectRef: supportContext.projectRef,
82 }),
83 ...(supportContext?.orgSlug && { orgSlug: supportContext.orgSlug }),
84 }}
85 onClick={onClose}
86 >
87 Contact support
88 </SupportLink>{' '}
89 and include a{' '}
90 <InlineLink href="https://github.com/orgs/briven/discussions/36540">
91 HAR file
92 </InlineLink>{' '}
93 from your session to help us investigate.
94 </p>
95 </div>
96 </CollapsibleAlert>
97 </div>
98 </AlertDialogDescription>
99 </AlertDialogHeader>
100 <AlertDialogFooter>
101 <AlertDialogCancel>Close</AlertDialogCancel>
102 <AlertDialogAction onClick={redirectToSignIn}>Sign in again</AlertDialogAction>
103 </AlertDialogFooter>
104 </AlertDialogContent>
105 </AlertDialog>
106 )
107}