Skip to content

Commit

Permalink
fix: hide privacy and remove account subsections from settings
Browse files Browse the repository at this point in the history
Refs: SHELL-241 (#493)
  • Loading branch information
beawar authored Aug 30, 2024
1 parent 8211628 commit fb94e2e
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 83 deletions.
162 changes: 162 additions & 0 deletions src/boot/app/default-views.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* SPDX-FileCopyrightText: 2024 Zextras <https://www.zextras.com>
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React from 'react';

import { produce } from 'immer';

import { DefaultViewsRegister } from './default-views';
import { SEARCH_APP_ID, SETTINGS_APP_ID, SHELL_APP_ID } from '../../constants';
import { useAccountStore } from '../../store/account';
import { useAppStore } from '../../store/app';
import { useLoginConfigStore } from '../../store/login/store';
import { setup } from '../../tests/utils';
import type { AccountSettingsAttrs } from '../../types/account';
import type { AppRouteDescriptor, SettingsView } from '../../types/apps';

describe('DefaultViews', () => {
it('should register search module', () => {
setup(<DefaultViewsRegister />);
expect(useAppStore.getState().routes).toMatchObject<Record<string, AppRouteDescriptor>>({
[SEARCH_APP_ID]: {
id: SEARCH_APP_ID,
app: SEARCH_APP_ID,
route: SEARCH_APP_ID,
label: 'Search',
position: 1000,
visible: true,
primaryBar: 'SearchModOutline',
badge: { show: false },
appView: expect.any(Function)
}
});
});

it.each<AccountSettingsAttrs['zimbraFeatureOptionsEnabled']>(['TRUE', undefined])(
'should register settings module if zimbraFeatureOptionsEnabled is %s',
(value) => {
useAccountStore.setState(
produce((state) => {
state.settings.attrs.zimbraFeatureOptionsEnabled = value;
})
);
setup(<DefaultViewsRegister />);
expect(useAppStore.getState().routes).toMatchObject<Record<string, AppRouteDescriptor>>({
[SETTINGS_APP_ID]: {
id: SETTINGS_APP_ID,
app: SETTINGS_APP_ID,
route: SETTINGS_APP_ID,
label: 'Settings',
position: 1100,
visible: true,
primaryBar: 'SettingsModOutline',
badge: { show: false },
appView: expect.any(Function),
secondaryBar: expect.any(Function)
}
});
}
);

it('should not register settings module if zimbraFeatureOptionsEnabled is FALSE', () => {
useAccountStore.setState(
produce((state) => {
state.settings.attrs.zimbraFeatureOptionsEnabled = 'FALSE';
})
);
setup(<DefaultViewsRegister />);
expect(Object.keys(useAppStore.getState().routes)).not.toContain(SETTINGS_APP_ID);
});

it('should register settings general view', () => {
useAccountStore.setState(
produce((state) => {
state.settings.attrs.zimbraFeatureOptionsEnabled = 'TRUE';
})
);
setup(<DefaultViewsRegister />);
expect(useAppStore.getState().views.settings).toContainEqual<SettingsView>({
id: 'general',
route: 'general',
app: SHELL_APP_ID,
component: expect.anything(),
icon: 'SettingsModOutline',
label: 'General Settings',
position: 1,
subSections: [
{ label: 'Appearance', id: 'appearance' },
{ label: 'Language', id: 'language' },
{ label: 'Out of Office Settings', id: 'out_of_office' },
{ label: 'Search', id: 'search_prefs' },
{ label: "User's quota", id: 'user_quota' }
]
});
});

it('should register privacy settings subsection if it is carbonio CE ', () => {
useAccountStore.setState(
produce((state) => {
state.settings.attrs.zimbraFeatureOptionsEnabled = 'TRUE';
})
);
useLoginConfigStore.setState({ isCarbonioCE: true });

setup(<DefaultViewsRegister />);
expect(useAppStore.getState().views.settings).toContainEqual(
expect.objectContaining<Pick<SettingsView, 'id' | 'subSections'>>({
id: 'general',
subSections: [
{ label: 'Appearance', id: 'appearance' },
{ label: 'Language', id: 'language' },
{ label: 'Out of Office Settings', id: 'out_of_office' },
{ label: 'Search', id: 'search_prefs' },
{ label: "User's quota", id: 'user_quota' },
{ label: 'Privacy', id: 'privacy-settings' }
]
})
);
});

it('should not register privacy settings subsection if it is not carbonio CE ', () => {
useAccountStore.setState(
produce((state) => {
state.settings.attrs.zimbraFeatureOptionsEnabled = 'TRUE';
})
);
useLoginConfigStore.setState({ isCarbonioCE: false });

setup(<DefaultViewsRegister />);
expect(useAppStore.getState().views.settings).toContainEqual(
expect.objectContaining<Pick<SettingsView, 'id' | 'subSections'>>({
id: 'general',
subSections: [
{ label: 'Appearance', id: 'appearance' },
{ label: 'Language', id: 'language' },
{ label: 'Out of Office Settings', id: 'out_of_office' },
{ label: 'Search', id: 'search_prefs' },
{ label: "User's quota", id: 'user_quota' }
]
})
);
});

it('should register settings accounts view', () => {
useAccountStore.setState(
produce((state) => {
state.settings.attrs.zimbraFeatureOptionsEnabled = 'TRUE';
})
);
setup(<DefaultViewsRegister />);
expect(useAppStore.getState().views.settings).toContainEqual<SettingsView>({
id: 'accounts',
route: 'accounts',
app: SHELL_APP_ID,
component: expect.any(Function),
icon: 'PersonOutline',
label: 'Accounts',
position: 1
});
});
});
158 changes: 101 additions & 57 deletions src/boot/app/default-views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,76 +5,120 @@
*/
/* eslint-disable no-param-reassign */

import type { TFunction } from 'i18next';
import { size } from 'lodash';
import { useEffect, useMemo } from 'react';

import { useTranslation } from 'react-i18next';

import { SEARCH_APP_ID, SETTINGS_APP_ID, SHELL_APP_ID } from '../../constants';
import { SearchAppView } from '../../search/search-app-view';
import { WrappedAccountsSettings } from '../../settings/accounts-settings';
import GeneralSettings from '../../settings/general-settings';
import { settingsSubSections } from '../../settings/general-settings-sub-sections';
import { useSettingsSubSections } from '../../settings/general-settings-sub-sections';
import { SettingsAppView } from '../../settings/settings-app-view';
import { SettingsSidebar } from '../../settings/settings-sidebar';
import { useAccountStore } from '../../store/account';
import { useAppStore } from '../../store/app';
import type { AppRouteDescriptor, SettingsView } from '../../types/apps';

const settingsGeneralView = (t: TFunction): SettingsView => ({
id: 'general',
route: 'general',
app: SHELL_APP_ID,
component: GeneralSettings,
icon: 'SettingsModOutline',
label: t('settings.general.general', 'General Settings'),
position: 1,
subSections: settingsSubSections(t)
});
const useSearchModule = (): void => {
const [t] = useTranslation();

const searchRouteDescriptor = useMemo<AppRouteDescriptor>(
() => ({
id: SEARCH_APP_ID,
app: SEARCH_APP_ID,
route: SEARCH_APP_ID,
appView: SearchAppView,
badge: {
show: false
},
label: t('search.app', 'Search'),
position: 1000,
visible: true,
primaryBar: 'SearchModOutline'
}),
[t]
);
useEffect(() => {
useAppStore.getState().addRoute(searchRouteDescriptor);

return (): void => {
useAppStore.getState().removeRoute(searchRouteDescriptor.id);
};
}, [searchRouteDescriptor]);
};

const useSettingsModule = (): void => {
const [t] = useTranslation();
const settingsAttrs = useAccountStore((state) => state.settings.attrs);
const settingsSubSections = useSettingsSubSections();

const settingsAccountsView = (t: TFunction): SettingsView => ({
id: 'accounts',
route: 'accounts',
app: SHELL_APP_ID,
component: WrappedAccountsSettings,
icon: 'PersonOutline',
label: t('settings.accounts', 'Accounts'),
position: 1
});
const settingsGeneralView = useMemo<SettingsView>(
() => ({
id: 'general',
route: 'general',
app: SHELL_APP_ID,
component: GeneralSettings,
icon: 'SettingsModOutline',
label: t('settings.general.general', 'General Settings'),
position: 1,
subSections: settingsSubSections
}),
[settingsSubSections, t]
);

const searchRouteDescriptor = (t: TFunction): AppRouteDescriptor => ({
id: SEARCH_APP_ID,
app: SEARCH_APP_ID,
route: SEARCH_APP_ID,
appView: SearchAppView,
badge: {
show: false
},
label: t('search.app', 'Search'),
position: 1000,
visible: true,
primaryBar: 'SearchModOutline'
});
const settingsAccountView = useMemo<SettingsView>(
() => ({
id: 'accounts',
route: 'accounts',
app: SHELL_APP_ID,
component: WrappedAccountsSettings,
icon: 'PersonOutline',
label: t('settings.accounts', 'Accounts'),
position: 1
}),
[t]
);

const settingsRouteDescriptor = useMemo<AppRouteDescriptor>(
() => ({
id: SETTINGS_APP_ID,
app: SETTINGS_APP_ID,
route: SETTINGS_APP_ID,
appView: SettingsAppView,
badge: {
show: false
},
label: t('settings.app', 'Settings'),
position: 1100,
visible: true,
primaryBar: 'SettingsModOutline',
secondaryBar: SettingsSidebar
}),
[t]
);

useEffect(() => {
if (
Object.keys(settingsAttrs).length > 0 &&
settingsAttrs.zimbraFeatureOptionsEnabled !== 'FALSE'
) {
useAppStore.getState().addRoute(settingsRouteDescriptor);
useAppStore.getState().addSettingsView(settingsGeneralView);
useAppStore.getState().addSettingsView(settingsAccountView);
}

return (): void => {
useAppStore.getState().removeRoute(settingsRouteDescriptor.id);
useAppStore.getState().removeSettingsView(settingsGeneralView.id);
useAppStore.getState().removeSettingsView(settingsAccountView.id);
};
}, [settingsAccountView, settingsAttrs, settingsGeneralView, settingsRouteDescriptor, t]);
};

const settingsRouteDescriptor = (t: TFunction): AppRouteDescriptor => ({
id: SETTINGS_APP_ID,
app: SETTINGS_APP_ID,
route: SETTINGS_APP_ID,
appView: SettingsAppView,
badge: {
show: false
},
label: t('settings.app', 'Settings'),
position: 1100,
visible: true,
primaryBar: 'SettingsModOutline',
secondaryBar: SettingsSidebar
});
export const DefaultViewsRegister = (): null => {
useSearchModule();
useSettingsModule();

export const registerDefaultViews = (t: TFunction): void => {
const { attrs } = useAccountStore.getState().settings;
if (size(attrs) > 0 && attrs.zimbraFeatureOptionsEnabled !== 'FALSE') {
useAppStore.getState().addRoute(settingsRouteDescriptor(t));
useAppStore.getState().addSettingsView(settingsGeneralView(t));
useAppStore.getState().addSettingsView(settingsAccountsView(t));
}
useAppStore.getState().addRoute(searchRouteDescriptor(t));
return null;
};
14 changes: 2 additions & 12 deletions src/boot/bootstrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/

import type { FC } from 'react';
import React, { useEffect } from 'react';

import { SnackbarManager } from '@zextras/carbonio-design-system';
import { useTranslation } from 'react-i18next';
import { BrowserRouter, Route, Switch, useParams } from 'react-router-dom';

import AppLoaderMounter from './app/app-loader-mounter';
import { registerDefaultViews } from './app/default-views';
import { DefaultViewsRegister } from './app/default-views';
import { ContextBridge } from './context-bridge';
import { Loader } from './loader';
import { TrackerProvider } from './posthog';
Expand All @@ -31,15 +29,7 @@ const FocusModeListener = (): null => {
return null;
};

export const DefaultViewsRegister = (): null => {
const [t] = useTranslation();
useEffect(() => {
registerDefaultViews(t);
}, [t]);
return null;
};

const Bootstrapper: FC = () => (
const Bootstrapper = (): React.JSX.Element => (
<TrackerProvider>
<ThemeProvider>
<ShellI18nextProvider>
Expand Down
Loading

0 comments on commit fb94e2e

Please sign in to comment.