SessionTimeoutModal.tsx 3.5 KB

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