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