Skip to content

Commit 1aac8a9

Browse files
committed
refactor: improve settings links definition
1 parent eed469c commit 1aac8a9

4 files changed

Lines changed: 96 additions & 98 deletions

File tree

packages/app-builder/src/routes/_builder+/_layout.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { OrganizationObjectTagsContextProvider } from '@app-builder/services/org
2121
import { OrganizationTagsContextProvider } from '@app-builder/services/organization/organization-tags';
2222
import { OrganizationUsersContextProvider } from '@app-builder/services/organization/organization-users';
2323
import { useSegmentIdentification } from '@app-builder/services/segment';
24+
import { getSettingsAccess } from '@app-builder/services/settings-access';
2425
import { forbidden } from '@app-builder/utils/http/http-responses';
2526
import { getPreferencesCookie } from '@app-builder/utils/preferences-cookies/preferences-cookie-read.server';
2627
import { getRoute } from '@app-builder/utils/routes';
@@ -31,7 +32,6 @@ import { useTranslation } from 'react-i18next';
3132
import { ClientOnly } from 'remix-utils/client-only';
3233
import { match } from 'ts-pattern';
3334
import { Icon } from 'ui-icons';
34-
import { getSettings } from './settings+/_layout';
3535

3636
export async function loader({ request }: LoaderFunctionArgs) {
3737
const {
@@ -55,7 +55,9 @@ export async function loader({ request }: LoaderFunctionArgs) {
5555
inbox.listInboxes(),
5656
]);
5757

58-
const firstSettings = getSettings(user, inboxes)[0];
58+
const firstSetting = Object.values(getSettingsAccess(user, inboxes)).find(
59+
(s) => s.settings.length > 0,
60+
)?.settings[0];
5961
return {
6062
user,
6163
orgUsers,
@@ -66,8 +68,8 @@ export async function loader({ request }: LoaderFunctionArgs) {
6668
isAnalyticsAvailable: isAnalyticsAvailable(user, entitlements),
6769
analytics: entitlements.analytics,
6870
settings: {
69-
isAvailable: firstSettings !== undefined,
70-
...(firstSettings !== undefined && { to: firstSettings.to }),
71+
isAvailable: firstSetting !== undefined,
72+
...(firstSetting !== undefined && { to: firstSetting.to }),
7173
},
7274
isAutoAssignmentAvailable: isAutoAssignmentAvailable(entitlements),
7375
},
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { initServerServices } from '@app-builder/services/init.server';
2+
import { getSettingsAccess } from '@app-builder/services/settings-access';
23
import { getRoute } from '@app-builder/utils/routes';
34
import { type LoaderFunctionArgs, redirect } from '@remix-run/node';
45
import { type Namespace } from 'i18next';
56

6-
import { getSettings } from './_layout';
7-
87
export const handle = {
98
i18n: ['scenarios'] satisfies Namespace,
109
};
@@ -16,11 +15,11 @@ export async function loader({ request }: LoaderFunctionArgs) {
1615
});
1716

1817
const inboxes = await inbox.listInboxes();
19-
const settings = getSettings(user, inboxes);
20-
const firstSettings = settings[0];
18+
const settings = getSettingsAccess(user, inboxes);
19+
const firstSetting = Object.values(settings).find((s) => s.settings.length > 0)?.settings[0];
2120

22-
if (firstSettings) {
23-
return redirect(firstSettings.to);
21+
if (firstSetting) {
22+
return redirect(firstSetting.to);
2423
}
2524
return redirect(getRoute('/'));
2625
}

packages/app-builder/src/routes/_builder+/settings+/_layout.tsx

Lines changed: 11 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,15 @@ import {
55
BreadCrumbs,
66
} from '@app-builder/components/Breadcrumbs';
77
import { Nudge } from '@app-builder/components/Nudge';
8-
import { type CurrentUser, isAdmin } from '@app-builder/models';
9-
import { type Inbox } from '@app-builder/models/inbox';
10-
import {
11-
canAccessInboxesSettings,
12-
isAccessible,
13-
isReadApiKeyAvailable,
14-
isReadTagAvailable,
15-
isReadUserAvailable,
16-
} from '@app-builder/services/feature-access';
8+
import { isAccessible } from '@app-builder/services/feature-access';
179
import { initServerServices } from '@app-builder/services/init.server';
10+
import { getSettingsAccess } from '@app-builder/services/settings-access';
1811
import { getRoute } from '@app-builder/utils/routes';
1912
import { type LoaderFunctionArgs } from '@remix-run/node';
2013
import { NavLink, Outlet, useLoaderData } from '@remix-run/react';
2114
import clsx from 'clsx';
2215
import { type Namespace } from 'i18next';
2316
import { useTranslation } from 'react-i18next';
24-
import * as R from 'remeda';
2517
import { Icon } from 'ui-icons';
2618

2719
export const handle = {
@@ -40,81 +32,15 @@ export const handle = {
4032
],
4133
};
4234

43-
export function getSettings(user: CurrentUser, inboxes: Inbox[]) {
44-
const settings = [];
45-
if (isReadUserAvailable(user)) {
46-
settings.push({
47-
section: 'users' as const,
48-
title: 'users' as const,
49-
to: getRoute('/settings/users'),
50-
});
51-
}
52-
if (isAdmin(user)) {
53-
settings.push({
54-
section: 'scenarios' as const,
55-
title: 'scenarios' as const,
56-
to: getRoute('/settings/scenarios'),
57-
});
58-
}
59-
if (canAccessInboxesSettings(user, inboxes)) {
60-
settings.push({
61-
section: 'case_manager' as const,
62-
title: 'inboxes' as const,
63-
to: getRoute('/settings/inboxes'),
64-
});
65-
}
66-
if (isReadTagAvailable(user)) {
67-
settings.push({
68-
section: 'case_manager' as const,
69-
title: 'tags' as const,
70-
to: getRoute('/settings/tags'),
71-
});
72-
}
73-
if (isReadApiKeyAvailable(user)) {
74-
settings.push({
75-
section: 'api' as const,
76-
title: 'api' as const,
77-
to: getRoute('/settings/api-keys'),
78-
});
79-
}
80-
if (user.permissions.canManageWebhooks) {
81-
settings.push({
82-
section: 'api' as const,
83-
title: 'webhooks' as const,
84-
to: getRoute('/settings/webhooks'),
85-
});
86-
}
87-
if (isAdmin(user)) {
88-
settings.push(
89-
{
90-
section: 'case_manager' as const,
91-
title: 'ia_case_review' as const,
92-
to: getRoute('/settings/ia-case-review'),
93-
},
94-
{
95-
section: 'case_manager' as const,
96-
title: 'data_display' as const,
97-
to: getRoute('/settings/data-display'),
98-
},
99-
);
100-
}
101-
return settings;
102-
}
103-
10435
export async function loader({ request }: LoaderFunctionArgs) {
10536
const { authService } = initServerServices(request);
10637
const { user, entitlements, inbox } = await authService.isAuthenticated(request, {
10738
failureRedirect: getRoute('/sign-in'),
10839
});
10940

11041
const inboxes = await inbox.listInboxes();
111-
const settings = getSettings(user, inboxes);
11242

113-
const sections = R.pipe(
114-
settings,
115-
R.groupBy((s) => s.section),
116-
R.entries(),
117-
);
43+
const sections = getSettingsAccess(user, inboxes);
11844

11945
return { sections, entitlements };
12046
}
@@ -131,21 +57,18 @@ export default function Settings() {
13157
<div className="flex size-full flex-row overflow-hidden">
13258
<div className="border-e-grey-90 bg-grey-100 flex h-full w-fit min-w-[200px] flex-col overflow-y-auto border-e p-4">
13359
<div className="flex flex-col">
134-
{sections.map(([section, settings]) => {
60+
{Object.entries(sections).map(([section, { icon, settings }]) => {
61+
console.log('section');
62+
console.log(section);
63+
console.log('settings');
64+
console.log(settings);
13565
if (settings.length === 0) return null;
13666

137-
const icon =
138-
section === 'users'
139-
? 'users'
140-
: section === 'case_manager'
141-
? 'case-manager'
142-
: 'world';
143-
14467
return (
14568
<nav key={section} className="flex flex-col gap-4">
14669
<div className="flex flex-row items-center gap-2">
14770
<Icon icon={icon} className="size-5" />
148-
<p className="font-bold">{t(`settings:${section}`)}</p>
71+
<p className="font-bold">{t(`settings:${section}` as any)}</p>
14972
</div>
15073
<ul className="flex flex-col gap-1 pb-6">
15174
{settings.map((setting) =>
@@ -154,7 +77,7 @@ export default function Settings() {
15477
key={setting.title}
15578
className="text-s bg-grey-100 text-grey-80 inline-flex w-full gap-2 p-2 font-medium first-letter:capitalize"
15679
>
157-
{t(`settings:${setting.title}`)}
80+
{t(`settings:${setting.title}` as any)}
15881
{entitlements.webhooks !== 'allowed' ? (
15982
<Nudge content="" kind="restricted" className="size-5" />
16083
) : null}
@@ -172,7 +95,7 @@ export default function Settings() {
17295
}
17396
to={setting.to}
17497
>
175-
{t(`settings:${setting.title}`)}
98+
{t(`settings:${setting.title}` as any)}
17699
</NavLink>
177100
),
178101
)}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { type Inbox } from '@app-builder/models/inbox';
2+
import { type CurrentUser, isAdmin } from '@app-builder/models/user';
3+
import {
4+
canAccessInboxesSettings,
5+
isReadApiKeyAvailable,
6+
isReadTagAvailable,
7+
isReadUserAvailable,
8+
} from '@app-builder/services/feature-access';
9+
import { type IconName } from 'ui-icons';
10+
import { getRoute } from '../utils/routes';
11+
12+
export type SettingEntry = {
13+
title: string;
14+
to: string;
15+
};
16+
17+
export type Section = {
18+
icon: IconName;
19+
settings: SettingEntry[];
20+
};
21+
22+
export type Sections = {
23+
users: Section;
24+
scenarios: Section;
25+
case_manager: Section;
26+
ia_assist: Section;
27+
api: Section;
28+
};
29+
30+
export function getSettingsAccess(user: CurrentUser, inboxes: Inbox[]): Sections {
31+
const sections: Sections = {
32+
users: {
33+
icon: 'users',
34+
settings: [
35+
...(isReadUserAvailable(user) ? [{ title: 'users', to: getRoute('/settings/users') }] : []),
36+
],
37+
},
38+
scenarios: {
39+
icon: 'world',
40+
settings: [
41+
...(isAdmin(user) ? [{ title: 'scenarios', to: getRoute('/settings/scenarios') }] : []),
42+
],
43+
},
44+
case_manager: {
45+
icon: 'case-manager',
46+
settings: [
47+
...(canAccessInboxesSettings(user, inboxes)
48+
? [{ title: 'inboxes', to: getRoute('/settings/inboxes') }]
49+
: []),
50+
...(isReadTagAvailable(user) ? [{ title: 'tags', to: getRoute('/settings/tags') }] : []),
51+
...(isAdmin(user)
52+
? [
53+
{ title: 'ia_case_review', to: getRoute('/settings/ia-case-review') },
54+
{ title: 'data_display', to: getRoute('/settings/data-display') },
55+
]
56+
: []),
57+
],
58+
},
59+
ia_assist: { icon: 'ai-review', settings: [] },
60+
api: {
61+
icon: 'world',
62+
settings: [
63+
...(isReadApiKeyAvailable(user)
64+
? [{ title: 'api', to: getRoute('/settings/api-keys') }]
65+
: []),
66+
...(user.permissions.canManageWebhooks
67+
? [{ title: 'webhooks', to: getRoute('/settings/webhooks') }]
68+
: []),
69+
],
70+
},
71+
};
72+
73+
return sections;
74+
}

0 commit comments

Comments
 (0)