@@ -12,10 +12,7 @@ and configuration.
1212
1313// cSpell:ignore payg
1414
15- import type {
16- PreferencesSubTabKey ,
17- PreferencesSubTabType ,
18- } from "@cocalc/util/types/settings" ;
15+ import type { PreferencesSubTabKey } from "@cocalc/util/types/settings" ;
1916
2017import { Button , Flex , Menu , Space } from "antd" ;
2118import { useEffect , useState } from "react" ;
@@ -50,42 +47,25 @@ import {
5047 KUCALC_ON_PREMISES ,
5148} from "@cocalc/util/db-schema/site-defaults" ;
5249import { COLORS } from "@cocalc/util/theme" ;
53- import { VALID_PREFERENCES_SUB_TYPES } from "@cocalc/util/types/settings" ;
5450import { AccountPreferencesAI } from "./account-preferences-ai" ;
55- import {
56- AccountPreferencesAppearance ,
57- APPEARANCE_ICON_NAME ,
58- } from "./account-preferences-appearance" ;
59- import {
60- AccountPreferencesCommunication ,
61- COMMUNICATION_ICON_NAME ,
62- } from "./account-preferences-communication" ;
63- import {
64- AccountPreferencesEditor ,
65- EDITOR_ICON_NAME ,
66- } from "./account-preferences-editor" ;
67- import {
68- AccountPreferencesKeyboard ,
69- KEYBOARD_ICON_NAME ,
70- } from "./account-preferences-keyboard" ;
71- import {
72- AccountPreferencesOther ,
73- OTHER_ICON_NAME ,
74- } from "./account-preferences-other" ;
51+ import { AccountPreferencesAppearance } from "./account-preferences-appearance" ;
52+ import { AccountPreferencesCommunication } from "./account-preferences-communication" ;
53+ import { PREFERENCES_SUB_TABS } from "./account-preferences-config" ;
54+ import { AccountPreferencesEditor } from "./account-preferences-editor" ;
55+ import { AccountPreferencesKeyboard } from "./account-preferences-keyboard" ;
56+ import { AccountPreferencesOther } from "./account-preferences-other" ;
7557import {
7658 ACCOUNT_PREFERENCES_ICON_NAME ,
7759 ACCOUNT_PROFILE_ICON_NAME ,
7860 AccountPreferencesProfile ,
7961} from "./account-preferences-profile" ;
80- import {
81- AccountPreferencesSecurity ,
82- KEYS_ICON_NAME ,
83- } from "./account-preferences-security" ;
62+ import { AccountPreferencesSecurity } from "./account-preferences-security" ;
8463import { I18NSelector } from "./i18n-selector" ;
8564import { LicensesPage } from "./licenses/licenses-page" ;
8665import { PublicPaths } from "./public-paths/public-paths" ;
8766import { SettingsOverview } from "./settings-index" ;
8867import { UpgradesPage } from "./upgrades/upgrades-page" ;
68+ import { switchAccountPage } from "./util" ;
8969
9070export const ACCOUNT_SETTINGS_ICON_NAME : IconName = "settings" ;
9171
@@ -99,17 +79,6 @@ type MenuKey =
9979 | PreferencesSubTabKey
10080 | string ;
10181
102- // Utility function to safely create preferences sub-tab key
103- function createPreferencesSubTabKey (
104- subTab : string ,
105- ) : PreferencesSubTabKey | null {
106- if ( VALID_PREFERENCES_SUB_TYPES . includes ( subTab as PreferencesSubTabType ) ) {
107- const validSubTab = subTab as PreferencesSubTabType ;
108- return `preferences-${ validSubTab } ` ;
109- }
110- return null ;
111- }
112-
11382// give up on trying to load account info and redirect to landing page.
11483// Do NOT make too short, since loading account info might takes ~10 seconds, e,g., due
11584// to slow network or some backend failure that times and retires involving
@@ -138,49 +107,35 @@ export const AccountPage: React.FC = () => {
138107 const get_api_key = useTypedRedux ( "page" , "get_api_key" ) ;
139108
140109 function handle_select ( key : MenuKey ) : void {
141- switch ( key ) {
142- case "settings" :
143- // Handle settings overview page
144- redux . getActions ( "account" ) . setState ( {
145- active_page : "index" ,
146- active_sub_tab : undefined ,
147- } ) ;
148- redux . getActions ( "account" ) . push_state ( `/settings/index` ) ;
149- return ;
150- case "billing" :
110+ switchAccountPage ( key , redux . getActions ( "account" ) , {
111+ onBilling : ( ) => {
151112 redux . getActions ( "billing" ) . update_customer ( ) ;
152- break ;
153- case "support" :
154- break ;
155- case "signout" :
156- return ;
157- case "profile" :
158- // Handle profile as standalone page
159- redux . getActions ( "account" ) . setState ( {
160- active_page : "profile" ,
161- active_sub_tab : undefined ,
162- } ) ;
163- redux . getActions ( "account" ) . push_state ( `/profile` ) ;
164- return ;
165- }
113+ } ,
114+ onSignout : ( ) => {
115+ // Signout does not navigate
116+ } ,
117+ } ) ;
118+ }
166119
167- // Handle sub-tabs under preferences
168- if ( typeof key === "string" && key . startsWith ( "preferences-" ) ) {
169- const subTab = key . replace ( "preferences-" , "" ) ;
170- const subTabKey = createPreferencesSubTabKey ( subTab ) ;
171- if ( subTabKey ) {
172- redux . getActions ( "account" ) . setState ( {
173- active_sub_tab : subTabKey ,
174- active_page : "preferences" ,
175- } ) ;
176- // Update URL to settings/preferences/[sub-tab]
177- redux . getActions ( "account" ) . push_state ( `/preferences/${ subTab } ` ) ;
178- }
179- return ;
120+ function getPreferencesComponent ( tabId : string ) : React . ReactNode {
121+ switch ( tabId ) {
122+ case "preferences-appearance" :
123+ return < AccountPreferencesAppearance /> ;
124+ case "preferences-editor" :
125+ return < AccountPreferencesEditor /> ;
126+ case "preferences-keyboard" :
127+ return < AccountPreferencesKeyboard /> ;
128+ case "preferences-ai" :
129+ return < AccountPreferencesAI /> ;
130+ case "preferences-communication" :
131+ return < AccountPreferencesCommunication /> ;
132+ case "preferences-keys" :
133+ return < AccountPreferencesSecurity /> ;
134+ case "preferences-other" :
135+ return < AccountPreferencesOther /> ;
136+ default :
137+ return null ;
180138 }
181-
182- redux . getActions ( "account" ) . set_active_tab ( key ) ;
183- redux . getActions ( "account" ) . push_state ( `/${ key } ` ) ;
184139 }
185140
186141 function getTabs ( ) : any [ ] {
@@ -215,97 +170,25 @@ export const AccountPage: React.FC = () => {
215170 { intl . formatMessage ( labels . preferences ) }
216171 </ span >
217172 ) ,
218- children : [
219- {
220- key : "preferences-appearance" ,
221- label : (
173+ children : PREFERENCES_SUB_TABS . map ( ( tab ) => {
174+ const tabLabel = intl . formatMessage ( tab . label ) ;
175+ return {
176+ key : tab . id ,
177+ label : tab . useAIAvatar ? (
222178 < span >
223- < Icon name = { APPEARANCE_ICON_NAME } /> { " " }
224- { intl . formatMessage ( labels . appearance ) }
179+ < AIAvatar size = { 16 } style = { { top : "-5px" } } /> { tabLabel }
225180 </ span >
226- ) ,
227- children : active_page === "preferences" &&
228- active_sub_tab === "preferences-appearance" && (
229- < AccountPreferencesAppearance />
230- ) ,
231- } ,
232- {
233- key : "preferences-editor" ,
234- label : (
235- < span >
236- < Icon name = { EDITOR_ICON_NAME } /> { " " }
237- { intl . formatMessage ( labels . editor ) }
238- </ span >
239- ) ,
240- children : active_page === "preferences" &&
241- active_sub_tab === "preferences-editor" && (
242- < AccountPreferencesEditor />
243- ) ,
244- } ,
245- {
246- key : "preferences-keyboard" ,
247- label : (
248- < span >
249- < Icon name = { KEYBOARD_ICON_NAME } /> { " " }
250- { intl . formatMessage ( labels . keyboard ) }
251- </ span >
252- ) ,
253- children : active_page === "preferences" &&
254- active_sub_tab === "preferences-keyboard" && (
255- < AccountPreferencesKeyboard />
256- ) ,
257- } ,
258- {
259- key : "preferences-ai" ,
260- label : (
261- < span >
262- < AIAvatar size = { 16 } style = { { top : "-5px" } } /> { " " }
263- { intl . formatMessage ( labels . ai ) }
264- </ span >
265- ) ,
266- children : active_page === "preferences" &&
267- active_sub_tab === "preferences-ai" && < AccountPreferencesAI /> ,
268- } ,
269- {
270- key : "preferences-communication" ,
271- label : (
272- < span >
273- < Icon name = { COMMUNICATION_ICON_NAME } /> { " " }
274- { intl . formatMessage ( labels . communication ) }
275- </ span >
276- ) ,
277- children : active_page === "preferences" &&
278- active_sub_tab === "preferences-communication" && (
279- < AccountPreferencesCommunication />
280- ) ,
281- } ,
282- {
283- key : "preferences-keys" ,
284- label : (
285- < span >
286- < Icon name = { KEYS_ICON_NAME } /> { " " }
287- { intl . formatMessage ( labels . ssh_and_api_keys ) }
288- </ span >
289- ) ,
290- children : active_page === "preferences" &&
291- active_sub_tab === "preferences-keys" && (
292- < AccountPreferencesSecurity />
293- ) ,
294- } ,
295- {
296- key : "preferences-other" ,
297- label : (
181+ ) : (
298182 < span >
299- < Icon name = { OTHER_ICON_NAME } /> { " " }
300- { intl . formatMessage ( labels . other ) }
183+ < Icon name = { tab . icon as IconName } /> { tabLabel }
301184 </ span >
302185 ) ,
303- children : active_page === "preferences" &&
304- active_sub_tab === "preferences-other " && (
305- < AccountPreferencesOther />
306- ) ,
307- } ,
308- ] ,
186+ children :
187+ active_page === "preferences" && active_sub_tab === tab . id
188+ ? getPreferencesComponent ( tab . id )
189+ : null ,
190+ } ;
191+ } ) ,
309192 } ,
310193 ] ;
311194 // adds a few conditional tabs
@@ -621,8 +504,12 @@ export const AccountPage: React.FC = () => {
621504 role = "region"
622505 aria-label = {
623506 active_page === "preferences" && active_sub_tab
624- ? `${ titles [ active_sub_tab ] ?. props ?. children ?. [ 1 ] || active_sub_tab } settings`
625- : `${ titles [ active_page ] ?. props ?. children ?. [ 1 ] || active_page } settings`
507+ ? `${
508+ titles [ active_sub_tab ] ?. props ?. children ?. [ 1 ] || active_sub_tab
509+ } settings`
510+ : `${
511+ titles [ active_page ] ?. props ?. children ?. [ 1 ] || active_page
512+ } settings`
626513 }
627514 style = { {
628515 overflow : "auto" ,
0 commit comments