me.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import { Card, CardContent, CardFooter } from 'ui'
  2. import { PageContainer } from 'ui-patterns/PageContainer'
  3. import {
  4. PageHeader,
  5. PageHeaderDescription,
  6. PageHeaderMeta,
  7. PageHeaderSummary,
  8. PageHeaderTitle,
  9. } from 'ui-patterns/PageHeader'
  10. import {
  11. PageSection,
  12. PageSectionContent,
  13. PageSectionDescription,
  14. PageSectionMeta,
  15. PageSectionSummary,
  16. PageSectionTitle,
  17. } from 'ui-patterns/PageSection'
  18. import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
  19. import { AccountConnections } from '@/components/interfaces/Account/Preferences/AccountConnections'
  20. import { AccountDeletion } from '@/components/interfaces/Account/Preferences/AccountDeletion'
  21. import { AccountIdentities } from '@/components/interfaces/Account/Preferences/AccountIdentities'
  22. import { AnalyticsSettings } from '@/components/interfaces/Account/Preferences/AnalyticsSettings'
  23. import { DashboardSettings } from '@/components/interfaces/Account/Preferences/DashboardSettings'
  24. import { HotkeySettings } from '@/components/interfaces/Account/Preferences/HotkeySettings'
  25. import { ProfileInformation } from '@/components/interfaces/Account/Preferences/ProfileInformation'
  26. import { ThemeSettings } from '@/components/interfaces/Account/Preferences/ThemeSettings'
  27. import { TimezoneSettings } from '@/components/interfaces/Account/Preferences/TimezoneSettings'
  28. import AccountLayout from '@/components/layouts/AccountLayout/AccountLayout'
  29. import { AppLayout } from '@/components/layouts/AppLayout/AppLayout'
  30. import { DefaultLayout } from '@/components/layouts/DefaultLayout'
  31. import { AlertError } from '@/components/ui/AlertError'
  32. import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
  33. import { IS_PLATFORM } from '@/lib/constants'
  34. import { useProfile } from '@/lib/profile'
  35. import type { NextPageWithLayout } from '@/types'
  36. const User: NextPageWithLayout = () => {
  37. return IS_PLATFORM ? <PlatformPreferences /> : <SelfHostedPreferences />
  38. }
  39. User.getLayout = (page) => (
  40. <AppLayout>
  41. <DefaultLayout headerTitle={IS_PLATFORM ? 'Account' : 'Preferences'}>
  42. <AccountLayout title="Preferences">{page}</AccountLayout>
  43. </DefaultLayout>
  44. </AppLayout>
  45. )
  46. export default User
  47. const PreferencesPageHeader = ({ description }: { description: string }) => (
  48. <PageHeader size="small">
  49. <PageHeaderMeta>
  50. <PageHeaderSummary>
  51. <PageHeaderTitle>Preferences</PageHeaderTitle>
  52. <PageHeaderDescription>{description}</PageHeaderDescription>
  53. </PageHeaderSummary>
  54. </PageHeaderMeta>
  55. </PageHeader>
  56. )
  57. const PlatformPreferences = () => {
  58. const { profileShowInformation, profileShowAnalyticsAndMarketing, profileShowAccountDeletion } =
  59. useIsFeatureEnabled([
  60. 'profile:show_information',
  61. 'profile:show_analytics_and_marketing',
  62. 'profile:show_account_deletion',
  63. ])
  64. const { error, isLoading, isError } = useProfile()
  65. return (
  66. <>
  67. <PreferencesPageHeader description="Manage your account profile, connections, and dashboard experience." />
  68. <PageContainer size="small">
  69. {isError && (
  70. <Card>
  71. <CardContent className="p-4">
  72. <AlertError error={error} subject="Failed to retrieve account information" />
  73. </CardContent>
  74. </Card>
  75. )}
  76. {!isError && (
  77. <>
  78. {isLoading ? (
  79. <ProfileLoadingSections showProfileInformation={profileShowInformation} />
  80. ) : (
  81. <>
  82. {profileShowInformation ? <ProfileInformation /> : null}
  83. <AccountIdentities />
  84. </>
  85. )}
  86. <AccountConnections />
  87. <ThemeSettings />
  88. <TimezoneSettings />
  89. <HotkeySettings />
  90. <DashboardSettings />
  91. {profileShowAnalyticsAndMarketing && <AnalyticsSettings />}
  92. {profileShowAccountDeletion && <AccountDeletion />}
  93. </>
  94. )}
  95. </PageContainer>
  96. </>
  97. )
  98. }
  99. const ProfileLoadingSections = ({
  100. showProfileInformation,
  101. }: {
  102. showProfileInformation: boolean
  103. }) => (
  104. <>
  105. {showProfileInformation && (
  106. <PageSection>
  107. <PageSectionMeta>
  108. <PageSectionSummary>
  109. <PageSectionTitle>Profile information</PageSectionTitle>
  110. </PageSectionSummary>
  111. </PageSectionMeta>
  112. <PageSectionContent>
  113. <Card>
  114. <CardContent>
  115. <ProfileFieldLoadingRow labelWidth="w-24" />
  116. </CardContent>
  117. <CardContent>
  118. <ProfileFieldLoadingRow labelWidth="w-20" />
  119. </CardContent>
  120. <CardContent>
  121. <ProfileFieldLoadingRow labelWidth="w-28" descriptionWidth="w-48" />
  122. </CardContent>
  123. <CardContent>
  124. <ProfileFieldLoadingRow labelWidth="w-20" descriptionWidth="w-40" />
  125. </CardContent>
  126. <CardFooter className="justify-end">
  127. <ShimmeringLoader className="h-8 w-16 rounded-md py-0" />
  128. </CardFooter>
  129. </Card>
  130. </PageSectionContent>
  131. </PageSection>
  132. )}
  133. <PageSection>
  134. <PageSectionMeta>
  135. <PageSectionSummary>
  136. <PageSectionTitle>Account identities</PageSectionTitle>
  137. <PageSectionDescription>
  138. Manage the providers linked to your Briven account and update their details.
  139. </PageSectionDescription>
  140. </PageSectionSummary>
  141. </PageSectionMeta>
  142. <PageSectionContent>
  143. <Card>
  144. <CardContent>
  145. <ShimmeringLoader />
  146. </CardContent>
  147. </Card>
  148. </PageSectionContent>
  149. </PageSection>
  150. </>
  151. )
  152. const ProfileFieldLoadingRow = ({
  153. labelWidth,
  154. descriptionWidth,
  155. }: {
  156. labelWidth: string
  157. descriptionWidth?: string
  158. }) => (
  159. <div className="flex flex-col-reverse gap-2 md:gap-6 md:flex-row-reverse md:justify-between">
  160. <div className="flex flex-col justify-center items-start md:items-end shrink-0 md:w-1/2 xl:w-2/5 md:min-w-100">
  161. <ShimmeringLoader className="h-8 w-full rounded-md py-0" />
  162. </div>
  163. <div className="flex flex-col min-w-0 grow">
  164. <ShimmeringLoader className={`${labelWidth} h-4 py-0`} />
  165. {descriptionWidth !== undefined && (
  166. <ShimmeringLoader className={`${descriptionWidth} mt-2 h-3 py-0`} />
  167. )}
  168. </div>
  169. </div>
  170. )
  171. const SelfHostedPreferences = () => {
  172. return (
  173. <>
  174. <PreferencesPageHeader description="Manage how the dashboard looks and behaves on this browser and device." />
  175. <PageContainer size="small">
  176. <ThemeSettings />
  177. <TimezoneSettings />
  178. <HotkeySettings />
  179. <DashboardSettings />
  180. </PageContainer>
  181. </>
  182. )
  183. }