Skip to content

Commit 8f2428c

Browse files
committed
Update navbar links and add account settings route
- Changed the "Change Password" link to point to "/account/password". - Added new links for "Auth Token" and "Account Settings" in the navbar. - Introduced secured routes for account settings in the router.
1 parent c240321 commit 8f2428c

File tree

3 files changed

+166
-3
lines changed

3 files changed

+166
-3
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import { Layout, Menu } from "antd";
2+
import { Route, Switch, useLocation, useHistory } from "react-router-dom";
3+
import {
4+
CheckOutlined,
5+
LockOutlined,
6+
MailOutlined,
7+
SafetyOutlined,
8+
SettingOutlined,
9+
} from "@ant-design/icons";
10+
import ChangePasswordView from "./change_password_view";
11+
import AuthTokenView from "./auth_token_view";
12+
import { useWkSelector } from "libs/react_hooks";
13+
import type { APIUserTheme } from "types/api_types";
14+
import { getSystemColorTheme } from "theme";
15+
import { updateSelectedThemeOfUser } from "admin/rest_api";
16+
import Store from "viewer/store";
17+
import { setActiveUserAction } from "viewer/model/actions/user_actions";
18+
import { setThemeAction } from "viewer/model/actions/ui_actions";
19+
20+
const { Sider, Content } = Layout;
21+
22+
function EmailSettings() {
23+
return (
24+
<div>
25+
<h2>Email Settings</h2>
26+
<p>Email settings page content will be added here.</p>
27+
</div>
28+
);
29+
}
30+
31+
function PasskeysSettings() {
32+
return (
33+
<div>
34+
<h2>Passkeys</h2>
35+
<p>Passkeys settings page content will be added here.</p>
36+
</div>
37+
);
38+
}
39+
40+
function AppearanceSettings() {
41+
const activeUser = useWkSelector((state) => state.activeUser);
42+
const { selectedTheme } = activeUser || { selectedTheme: "auto" };
43+
44+
const setSelectedTheme = async (newTheme: APIUserTheme) => {
45+
if (!activeUser) return;
46+
47+
if (newTheme === "auto") newTheme = getSystemColorTheme();
48+
49+
if (selectedTheme !== newTheme) {
50+
const newUser = await updateSelectedThemeOfUser(activeUser.id, newTheme);
51+
Store.dispatch(setThemeAction(newTheme));
52+
Store.dispatch(setActiveUserAction(newUser));
53+
}
54+
};
55+
56+
return (
57+
<div>
58+
<h2>Appearance</h2>
59+
<div style={{ marginTop: 16 }}>
60+
<h3>Theme</h3>
61+
<Menu
62+
mode="inline"
63+
selectedKeys={[selectedTheme]}
64+
items={[
65+
{
66+
key: "auto",
67+
label: "System Default",
68+
icon: selectedTheme === "auto" ? <CheckOutlined /> : null,
69+
onClick: () => setSelectedTheme("auto"),
70+
},
71+
{
72+
key: "light",
73+
label: "Light",
74+
icon: selectedTheme === "light" ? <CheckOutlined /> : null,
75+
onClick: () => setSelectedTheme("light"),
76+
},
77+
{
78+
key: "dark",
79+
label: "Dark",
80+
icon: selectedTheme === "dark" ? <CheckOutlined /> : null,
81+
onClick: () => setSelectedTheme("dark"),
82+
},
83+
]}
84+
/>
85+
</div>
86+
</div>
87+
);
88+
}
89+
90+
function AccountSettingsView() {
91+
const location = useLocation();
92+
const history = useHistory();
93+
const selectedKey = location.pathname.split("/").pop() || "email";
94+
95+
const menuItems = [
96+
{
97+
key: "email",
98+
icon: <MailOutlined />,
99+
label: "Email",
100+
},
101+
{
102+
key: "password",
103+
icon: <LockOutlined />,
104+
label: "Password",
105+
},
106+
{
107+
key: "passkeys",
108+
icon: <SafetyOutlined />,
109+
label: "Passkeys",
110+
},
111+
{
112+
key: "token",
113+
icon: <SettingOutlined />,
114+
label: "Auth Token",
115+
},
116+
{
117+
key: "appearance",
118+
icon: <SettingOutlined />,
119+
label: "Appearance",
120+
},
121+
];
122+
123+
return (
124+
<Layout style={{ minHeight: "calc(100vh - 64px)" }}>
125+
<Sider width={200} theme="light">
126+
<Menu
127+
mode="inline"
128+
selectedKeys={[selectedKey]}
129+
style={{ height: "100%" }}
130+
items={menuItems}
131+
onClick={({ key }) => history.push(`/account/${key}`)}
132+
/>
133+
</Sider>
134+
<Content style={{ padding: "24px", minHeight: 280 }}>
135+
<Switch>
136+
<Route path="/account/email" component={EmailSettings} />
137+
<Route path="/account/password" component={ChangePasswordView} />
138+
<Route path="/account/passkeys" component={PasskeysSettings} />
139+
<Route path="/account/token" component={AuthTokenView} />
140+
<Route path="/account/appearance" component={AppearanceSettings} />
141+
<Route path="/account" component={EmailSettings} />
142+
</Switch>
143+
</Content>
144+
</Layout>
145+
);
146+
}
147+
148+
export default AccountSettingsView;

frontend/javascripts/navbar.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ function NotificationIcon({
488488
sendAnalyticsEvent("open_whats_new_view");
489489

490490
if (window.Olvy) {
491-
// Setting the target lazily, to finally let olvy load the whats new modal, as it should be shown now.
491+
// Setting the target lazily, to finally let olvy load the "what's new" modal, as it should be shown now.
492492
window.Olvy.config.target = "#unused-olvy-target";
493493
window.Olvy.show();
494494
}
@@ -675,9 +675,13 @@ function LoggedInAvatar({
675675
: null,
676676
{
677677
key: "resetpassword",
678-
label: <Link to="/auth/changePassword">Change Password</Link>,
678+
label: <Link to="/account/password">Change Password</Link>,
679+
},
680+
{ key: "token", label: <Link to="/account/token">Auth Token</Link> },
681+
{
682+
key: "account",
683+
label: <Link to="/account">Account Settings</Link>,
679684
},
680-
{ key: "token", label: <Link to="/auth/token">Auth Token</Link> },
681685
{
682686
key: "theme",
683687
label: "Theme",

frontend/javascripts/router.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import type { EmptyObject } from "types/globals";
7575
import { getDatasetIdOrNameFromReadableURLPart } from "viewer/model/accessors/dataset_accessor";
7676
import { Store } from "viewer/singletons";
7777
import { CommandPalette } from "viewer/view/components/command_palette";
78+
import AccountSettingsView from "admin/auth/account_settings_view";
7879

7980
const { Content } = Layout;
8081

@@ -814,6 +815,16 @@ class ReactRouter extends React.Component<Props> {
814815
{!features().isWkorgInstance && (
815816
<RouteWithErrorBoundary path="/onboarding" component={Onboarding} />
816817
)}
818+
<SecuredRouteWithErrorBoundary
819+
isAuthenticated={isAuthenticated}
820+
path="/account"
821+
render={() => <AccountSettingsView />}
822+
/>
823+
<SecuredRouteWithErrorBoundary
824+
isAuthenticated={isAuthenticated}
825+
path="/account/:tab"
826+
render={() => <AccountSettingsView />}
827+
/>
817828
<RouteWithErrorBoundary component={PageNotFoundView} />
818829
</Switch>
819830
</Content>

0 commit comments

Comments
 (0)