Skip to content

Commit

Permalink
refactor!: improve focus mode implementation
Browse files Browse the repository at this point in the history
BREAKING CHANGE: rename standalone to focus-mode
BREAKING CHANGE: replace standalone AppRoute field with focusMode field

refs: SHELL-138 (#326)
  • Loading branch information
CataldoMazzilli authored Oct 2, 2023
1 parent 1d40574 commit c7d3132
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 112 deletions.
5 changes: 4 additions & 1 deletion src/boot/app/app-loader-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ import {
useUserRight,
useUserRights,
getUserRight,
getUserRights
getUserRights,
useAuthenticated
} from '../../store/account';
import { getApp, getAppContext, useApp, useAppContext } from '../../store/app';
import {
Expand Down Expand Up @@ -122,6 +123,8 @@ export const getAppFunctions = (pkg: CarbonioModule): Record<string, Function> =
getActionsFactory,
useActionFactory,
getActionFactory,
// AUTH
useAuthenticated,
// ACCOUNTS
useUserAccount,
getUserAccount,
Expand Down
4 changes: 3 additions & 1 deletion src/boot/app/shared-libraries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React from 'react';
import * as ReduxJSToolkit from '@reduxjs/toolkit';
import * as ZappUI from '@zextras/carbonio-design-system';
import * as Preview from '@zextras/carbonio-ui-preview';
import * as Darkreader from 'darkreader';
import * as Lodash from 'lodash';
import * as Moment from 'moment';
import * as ReactDOM from 'react-dom';
Expand All @@ -31,7 +32,8 @@ export function injectSharedLibraries(): void {
'@reduxjs/toolkit': ReduxJSToolkit,
'@zextras/carbonio-shell-ui': {},
'@zextras/carbonio-design-system': ZappUI,
'@zextras/carbonio-ui-preview': Preview
'@zextras/carbonio-ui-preview': Preview,
darkreader: Darkreader
};
window.__ZAPP_HMR_EXPORT__ = {};
}
Expand Down
10 changes: 5 additions & 5 deletions src/boot/bootstrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ import { ContextBridge } from './context-bridge';
import { Loader } from './loader';
import ShellI18nextProvider from './shell-i18n-provider';
import { ThemeProvider } from './theme-provider';
import { BASENAME, IS_STANDALONE } from '../constants';
import { BASENAME, IS_FOCUS_MODE } from '../constants';
import { NotificationPermissionChecker } from '../notification/NotificationPermissionChecker';
import ShellView from '../shell/shell-view';
import { useAppStore } from '../store/app';

const StandaloneListener = (): null => {
const FocusModeListener = (): null => {
const { route } = useParams<{ route?: string }>();
useEffect(() => {
if (route) useAppStore.setState({ standalone: route });
if (route) useAppStore.setState({ focusMode: route });
}, [route]);
return null;
};
Expand All @@ -44,10 +44,10 @@ const Bootstrapper: FC = () => (
<SnackbarManager>
<ModalManager>
<Loader />
{IS_STANDALONE && (
{IS_FOCUS_MODE && (
<Switch>
<Route path={'/:route'}>
<StandaloneListener />
<FocusModeListener />
</Route>
</Switch>
)}
Expand Down
5 changes: 4 additions & 1 deletion src/boot/loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { find } from 'lodash';
import { useTranslation } from 'react-i18next';

import { loadApps, unloadAllApps } from './app/load-apps';
import { IS_FOCUS_MODE } from '../constants';
import { getComponents } from '../network/get-components';
import { getInfo } from '../network/get-info';
import { loginConfig } from '../network/login-config';
Expand Down Expand Up @@ -80,7 +81,9 @@ export const Loader = (): React.JSX.Element => {
} else if ('message' in promiseRejectedResult.reason) {
console.error(promiseRejectedResult.reason.message);
}
setOpen(true);
if (!IS_FOCUS_MODE) {
setOpen(true);
}
}
if (isPromiseFulfilledResult(getComponentsPromiseSettledResult)) {
loadApps(Object.values(useAppStore.getState().apps));
Expand Down
6 changes: 3 additions & 3 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ export const darkReaderDynamicThemeFixes: DynamicThemeFix = {

const base = '/carbonio/';

const standaloneBase = `${base}standalone`;
const focusModeBase = `${base}focus-mode`;

export const IS_STANDALONE = window.location.pathname.startsWith(standaloneBase);
export const BASENAME = IS_STANDALONE ? standaloneBase : base;
export const IS_FOCUS_MODE = window.location.pathname.startsWith(focusModeBase);
export const BASENAME = IS_FOCUS_MODE ? focusModeBase : base;
export const EMAIL_VALIDATION_REGEX =
// eslint-disable-next-line @typescript-eslint/no-unused-vars, max-len, no-control-regex
/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/;
Expand Down
4 changes: 2 additions & 2 deletions src/network/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
SoapContext,
SoapResponse
} from '../../types';
import { IS_STANDALONE, SHELL_APP_ID } from '../constants';
import { IS_FOCUS_MODE, SHELL_APP_ID } from '../constants';
import { report } from '../reporting/functions';
import { useAccountStore } from '../store/account';
import { useNetworkStore } from '../store/network';
Expand Down Expand Up @@ -103,7 +103,7 @@ const handleResponse = <R>(api: string, res: SoapResponse<R>): R | ErrorSoapBody
(code) => code === (<ErrorSoapResponse>res).Body.Fault.Detail?.Error?.Code
)
) {
if (IS_STANDALONE) {
if (IS_FOCUS_MODE) {
useAccountStore.setState({ authenticated: false });
} else {
goToLogin();
Expand Down
3 changes: 2 additions & 1 deletion src/shell/app-view-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import { Redirect, Route, Switch, useLocation } from 'react-router-dom';
import styled from 'styled-components';

import AppContextProvider from '../boot/app/app-context-provider';
import { IS_FOCUS_MODE } from '../constants';
import { useAppList, useAppStore, useRoutes } from '../store/app';

const _BoardsRouterContainer = styled(Container)`
flex-grow: 1;
flex-basis: 0;
min-width: 0.0625rem;
max-height: calc(100vh - 3.75rem);
max-height: ${IS_FOCUS_MODE ? '100vh' : 'calc(100vh - 3.75rem)'};
overflow-y: auto;
`;

Expand Down
11 changes: 1 addition & 10 deletions src/shell/shell-primary-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@ import styled from 'styled-components';
import BadgeWrap from './badge-wrap';
import { PrimaryAccessoryView, PrimaryBarView } from '../../types';
import AppContextProvider from '../boot/app/app-context-provider';
import {
BOARD_CONTAINER_ZINDEX,
IS_STANDALONE,
PRIMARY_BAR_WIDTH,
SEARCH_APP_ID
} from '../constants';
import { BOARD_CONTAINER_ZINDEX, PRIMARY_BAR_WIDTH, SEARCH_APP_ID } from '../constants';
import { useCurrentRoute } from '../history/hooks';
import { useAppStore } from '../store/app';
import { minimizeBoards, reopenBoards, useBoardStore } from '../store/boards';
Expand Down Expand Up @@ -155,10 +150,6 @@ const ShellPrimaryBar = (): React.JSX.Element | null => {
[accessoryViews]
);

if (IS_STANDALONE && activeRoute?.standalone?.hidePrimaryBar) {
return null;
}

return (
<PrimaryBarContainer
width={PRIMARY_BAR_WIDTH}
Expand Down
80 changes: 26 additions & 54 deletions src/shell/shell-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ import ShellHeader from './shell-header';
import ShellPrimaryBar from './shell-primary-bar';
import ShellSecondaryBar from './shell-secondary-bar';
import { ThemeCallbacksContext } from '../boot/theme-provider';
import { IS_STANDALONE } from '../constants';
import { IS_FOCUS_MODE } from '../constants';
import { useDarkReaderResultValue } from '../dark-mode/use-dark-reader-result-value';
import { useCurrentRoute } from '../history/hooks';
import { goToLogin } from '../network/utils';
import { useAccountStore } from '../store/account';
import { ShellUtilityBar } from '../utility-bar/bar';
import { ShellUtilityPanel } from '../utility-bar/panel';

Expand All @@ -48,37 +45,19 @@ function DarkReaderListener(): null {
return null;
}

const useLoginRedirection = (allowUnauthenticated?: boolean): void => {
const auth = useAccountStore((s) => s.authenticated);
useEffect(() => {
if (IS_STANDALONE && !auth && !allowUnauthenticated) {
goToLogin();
}
}, [allowUnauthenticated, auth]);
};

interface ShellComponentProps {
allowUnauthenticated?: boolean;
hideShellHeader?: boolean;
}

const ShellComponent = ({
allowUnauthenticated,
hideShellHeader
}: ShellComponentProps): React.JSX.Element => {
useLoginRedirection(allowUnauthenticated);
return (
<Background>
<DarkReaderListener />
{!(IS_STANDALONE && hideShellHeader) && (
<ShellHeader>
<ShellUtilityBar />
</ShellHeader>
)}
<Row crossAlignment="unset" style={{ position: 'relative', flexGrow: '1' }}>
const ShellComponent = (): React.JSX.Element => (
<Background>
<DarkReaderListener />
{!IS_FOCUS_MODE && (
<ShellHeader>
<ShellUtilityBar />
</ShellHeader>
)}
<Row crossAlignment="unset" style={{ position: 'relative', flexGrow: '1' }}>
{!IS_FOCUS_MODE && (
<Container
orientation="horizontal"
background="gray5"
background={'gray5'}
width="fit"
height="fill"
mainAlignment="flex-start"
Expand All @@ -87,27 +66,20 @@ const ShellComponent = ({
<ShellPrimaryBar />
<ShellSecondaryBar />
</Container>
<AppViewContainer />
<ShellUtilityPanel />
</Row>
<BoardContainer />
</Background>
);
};

const MemoShell = React.memo(ShellComponent);
)}
<AppViewContainer />
<ShellUtilityPanel />
</Row>
<BoardContainer />
</Background>
);

const ShellView = (): React.JSX.Element => {
const activeRoute = useCurrentRoute();
const allowUnauthenticated = activeRoute?.standalone?.allowUnauthenticated;
const hideShellHeader = activeRoute?.standalone?.hideShellHeader;
return (
<ShellContextProvider>
<PreviewManager>
<MemoShell allowUnauthenticated={allowUnauthenticated} hideShellHeader={hideShellHeader} />
</PreviewManager>
</ShellContextProvider>
);
};
const ShellView = (): React.JSX.Element => (
<ShellContextProvider>
<PreviewManager>
<ShellComponent />
</PreviewManager>
</ShellContextProvider>
);

export default ShellView;
15 changes: 11 additions & 4 deletions src/store/account/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
AccountSettings
} from '../../../types';

export const useAuthenticated = (): boolean => useAccountStore((s) => s.authenticated);

export const useUserAccount = (): Account => useAccountStore((s) => s.account as Account);
export const useUserAccounts = (): Array<Account> => {
const acct = useAccountStore((s) => s.account);
Expand All @@ -37,10 +39,15 @@ export const useUserSettings = (): AccountSettings => useAccountStore((s) => s.s
export const useUserSetting = <T = void>(...path: Array<string>): string | T =>
useAccountStore((s) => get(s.settings, join(path, '.')));

export const getUserAccount = (): Account => useAccountStore.getState().account as Account;
export const getUserAccounts = (): Array<Account> => [
useAccountStore.getState().account as Account
];
export const getUserAccount = (): Account | undefined => useAccountStore.getState().account;
export const getUserAccounts = (): Array<Account> => {
const { account } = useAccountStore.getState();
const accounts: Account[] = [];
if (account) {
accounts.push(account);
}
return accounts;
};
export const getUserSettings = (): AccountSettings => useAccountStore.getState().settings;
export const getUserSetting = <T = void>(...path: Array<string>): string | T =>
get(useAccountStore.getState().settings, join(path, '.'));
Expand Down
24 changes: 12 additions & 12 deletions src/store/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { normalizeApp } from './utils';
import type { AppState, CarbonioModule } from '../../../types';
import { SHELL_APP_ID } from '../../constants';

const STANDALONE_RESPONSE = 'standalone';
const FOCUS_MODE_RESPONSE = 'focus-mode';

function addIfNotPresent<T extends { id: unknown }>(
items: T[],
Expand Down Expand Up @@ -42,7 +42,7 @@ function removeById<T extends { id: unknown }>(items: T[], id: unknown): void {

// extra currying as suggested in https://github.com/pmndrs/zustand/blob/main/docs/guides/typescript.md#basic-usage
export const useAppStore = create<AppState>()((set, get) => ({
standalone: false,
focusMode: false,
apps: {},
appContexts: {},
shell: {
Expand Down Expand Up @@ -114,14 +114,14 @@ export const useAppStore = create<AppState>()((set, get) => ({
},
// add route (id route primaryBar secondaryBar app)
addRoute: (routeData): string => {
const { standalone } = get();
if (standalone && routeData.route !== standalone) {
return STANDALONE_RESPONSE;
const { focusMode } = get();
if (focusMode && (routeData.route !== focusMode || !routeData.focusMode)) {
return FOCUS_MODE_RESPONSE;
}
set(
produce<AppState>((state) => {
state.routes[routeData.id] = routeData;
if (routeData.primaryBar) {
if (routeData.primaryBar && !routeData.focusMode) {
addAndSort(state.views.primaryBar, {
app: routeData.app,
id: routeData.id,
Expand Down Expand Up @@ -199,9 +199,9 @@ export const useAppStore = create<AppState>()((set, get) => ({

// add settings
addSettingsView: (data): string => {
const { standalone } = get();
if (standalone && data.route !== standalone) {
return STANDALONE_RESPONSE;
const { focusMode } = get();
if (focusMode && data.route !== focusMode) {
return FOCUS_MODE_RESPONSE;
}
set(
produce<AppState>((state) => {
Expand All @@ -222,9 +222,9 @@ export const useAppStore = create<AppState>()((set, get) => ({
//
// add search
addSearchView: (data): string => {
const { standalone } = get();
if (standalone && data.route !== standalone) {
return STANDALONE_RESPONSE;
const { focusMode } = get();
if (focusMode && data.route !== focusMode) {
return FOCUS_MODE_RESPONSE;
}
set(
produce<AppState>((state) => {
Expand Down
6 changes: 1 addition & 5 deletions src/store/app/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,7 @@ export const normalizeRoute = (
primaryBar: data.primaryBar ?? app.icon ?? 'CubeOutline',
secondaryBar: data.secondaryBar,
appView: data.appView ?? FallbackView,
standalone: {
hidePrimaryBar: data?.standalone?.hidePrimaryBar,
hideShellHeader: data?.standalone?.hideShellHeader,
allowUnauthenticated: data?.standalone?.allowUnauthenticated
}
focusMode: data.focusMode
};
};

Expand Down
2 changes: 1 addition & 1 deletion src/utility-bar/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const checkRoute = (
view: UtilityView | PrimaryAccessoryView | SecondaryAccessoryView,
activeRoute?: AppRoute
): boolean => {
const activeRouteValues = Object.values(omit(activeRoute, 'standalone') ?? {});
const activeRouteValues = Object.values(omit(activeRoute, 'focusMode') ?? {});
if (view.blacklistRoutes) return !checkList(activeRouteValues, view.blacklistRoutes);
if (view.whitelistRoutes) return checkList(activeRouteValues, view.whitelistRoutes);
return true;
Expand Down
Loading

0 comments on commit c7d3132

Please sign in to comment.