// noinspection JSUnusedGlobalSymbols import { useMenuContext } from '@/components/Layout/MenuProvider'; import { useThemeContext } from '@/components/Layout/ThemeProvider'; import { ChangePasswordForm } from '@/components/ra-forms'; import { ApplicaAuthProvider } from '@applica-software-guru/iam-client'; import { Dialog, useMediaQuery, useTheme } from '@mui/material'; import _ from 'lodash'; import { UseGetIdentityResult, useAuthProvider, useGetIdentity } from 'ra-core'; import React, { createContext, forwardRef, useCallback, useContext, useEffect, useMemo, useReducer, useState } from 'react'; import { useLoading } from 'react-admin'; enum LayoutActionType { UPDATE_MEDIA = 'updateMedia', UPDATE_DRAWER = 'updateDrawer', UPDATE_LOGO = 'updateLogo', UPDATE_NOTIFICATIONS = 'updateNotifications', UPDATE_THEME = 'updateTheme' } type ILayoutProviderProps = React.PropsWithChildren<{ logoMain?: React.ReactElement; logoIcon?: React.ReactElement; enableNotification: boolean; notification?: string; }>; type ILayoutMediaState = { downMd: boolean; downLg: boolean; downXl: boolean; horizontal: boolean; }; type ILayoutDrawerState = { open: boolean; width: number; handleDrawerToggle: () => void; }; type ILayoutLogoState = { icon?: React.ReactElement; main?: React.ReactElement; }; type ILayoutNotificationState = { enable: boolean; resource: string; }; type ILayoutThemeState = { iconColorOpen: string; iconColor: string; }; type ILayoutState = { drawer: ILayoutDrawerState; media: ILayoutMediaState; logo: ILayoutLogoState; notifications: ILayoutNotificationState; theme: ILayoutThemeState; }; type ILayoutAction = | { type: LayoutActionType.UPDATE_MEDIA; payload: Partial; } | { type: LayoutActionType.UPDATE_DRAWER; payload: Partial; } | { type: LayoutActionType.UPDATE_LOGO; payload: Partial; } | { type: LayoutActionType.UPDATE_NOTIFICATIONS; payload: Partial; } | { type: LayoutActionType.UPDATE_THEME; payload: Partial; }; type ILayoutContext = { state: ILayoutState; dispatch: React.Dispatch; }; function reducer(state: ILayoutState, action: ILayoutAction) { const newState = _.clone(state); const { type, payload } = action; switch (type) { case LayoutActionType.UPDATE_MEDIA: { const media = _.chain(newState.media).clone().extend(payload).value(); return _.extend(newState, { media: media }); } case LayoutActionType.UPDATE_DRAWER: { const drawer = _.chain(newState.drawer).clone().extend(payload).value(); return _.extend(newState, { drawer: drawer }); } case LayoutActionType.UPDATE_LOGO: { const logo = _.chain(newState.logo).clone().extend(payload).value(); return _.extend(newState, { logo: logo }); } case LayoutActionType.UPDATE_NOTIFICATIONS: { const notifications = _.chain(newState.notifications).clone().extend(payload).value(); return _.extend(newState, { notifications: notifications }); } case LayoutActionType.UPDATE_THEME: { const theme = _.chain(newState.theme).clone().extend(payload).value(); return _.extend(newState, { theme: theme }); } default: return newState; } } const DefaultState: ILayoutState = { drawer: { open: true, width: 260, handleDrawerToggle: () => {} }, media: { downMd: false, downLg: false, downXl: false, horizontal: false }, logo: {}, notifications: { enable: true, resource: 'entities/notification' }, theme: { iconColor: 'grey.300', iconColorOpen: 'grey.100' } }; const LayoutContext = createContext(undefined); function LayoutProvider(props: ILayoutProviderProps) { const authProvider = useAuthProvider(); const identity = useGetIdentity() as UseGetIdentityResult; const theme = useTheme(); const downMd = useMediaQuery(theme.breakpoints.down('md')); const downLg = useMediaQuery(theme.breakpoints.down('lg')); const downXl = useMediaQuery(theme.breakpoints.down('xl')); const { miniDrawer, isHorizontalLayout, themeOrientation, drawerWidth } = useThemeContext(); const isHorizontal = isHorizontalLayout(themeOrientation) && !downLg; const { drawerOpen, openDrawer } = useMenuContext(); const handleDrawerToggle = useCallback(() => { openDrawer(!drawerOpen); }, [drawerOpen, openDrawer]); const [needToChangePassword, setNeedToChangePassword] = useState(false); const [state, dispatch] = useReducer( reducer, _.chain(DefaultState) .clone() .merge({ drawer: { open: !miniDrawer || drawerOpen } }) .value() ); const handlePasswordChange = useCallback(() => setNeedToChangePassword(false), []); const value = useMemo(() => ({ state, dispatch }), [state, dispatch]); const { logoIcon, logoMain, enableNotification, notification } = props; const isLayoutLoading = useLoading(); useEffect(() => { dispatch({ type: LayoutActionType.UPDATE_MEDIA, payload: { downMd: downMd, downLg: downLg, downXl: downXl, horizontal: isHorizontal } }); }, [downMd, downLg, downXl, isHorizontal]); useEffect(() => { dispatch({ type: LayoutActionType.UPDATE_DRAWER, payload: { open: drawerOpen, width: drawerWidth, handleDrawerToggle: handleDrawerToggle } }); }, [drawerOpen, drawerWidth, handleDrawerToggle]); useEffect(() => { if (!miniDrawer) { openDrawer(!downXl); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [downXl, miniDrawer]); useEffect(() => { dispatch({ type: LayoutActionType.UPDATE_LOGO, payload: { main: logoMain, icon: logoIcon } }); }, [logoIcon, logoMain]); useEffect(() => { dispatch({ type: LayoutActionType.UPDATE_NOTIFICATIONS, payload: { enable: enableNotification, resource: notification ?? 'entities/notification' } }); }, [enableNotification, notification]); useEffect(() => { dispatch({ type: LayoutActionType.UPDATE_THEME, payload: { iconColorOpen: theme.palette.mode === 'dark' ? 'grey.200' : 'grey.300', iconColor: theme.palette.mode === 'dark' ? 'background.default' : 'grey.100' } }); }, [theme.palette.mode]); useEffect(() => { if (isLayoutLoading) return; // Check if authProvider contains a method called isImpersonating if (!authProvider.isImpersonating) { // eslint-disable-next-line no-console console.warn('authProvider does not contain a method called isImpersonating', authProvider); return; } authProvider?.isImpersonating().then((isImpersonating: boolean) => { setNeedToChangePassword(!isImpersonating && identity?.data?.needToChangePassword === true); }); }, [identity?.data?.needToChangePassword, authProvider, isLayoutLoading]); return ( {props.children} ); } function withLayoutProvider(Component: React.ComponentType

) { return forwardRef((props: P & ILayoutProviderProps & any, ref: React.ForwardedRef) => { const { logoIcon, logoMain, enableNotification, notification } = props; return ( ); }); } function useLayoutContext(): ILayoutContext { const context = useContext(LayoutContext); if (context === undefined) { throw new Error( '[Layout] useLayoutContext: context undefined. Please provide a valid LayoutContext using LayoutProvider' ); } return context; } function useLayoutDispatch(): React.Dispatch { return useLayoutContext().dispatch; } function useLayoutState(): ILayoutState { return useLayoutContext().state; } function useLayoutMediaState(): ILayoutMediaState { return useLayoutState().media; } function useLayoutDrawerState(): ILayoutDrawerState { return useLayoutState().drawer; } function useLayoutLogoState(): ILayoutLogoState { return useLayoutState().logo; } function useLayoutNotificationsState(): ILayoutNotificationState { return useLayoutState().notifications; } function useLayoutThemeState(): ILayoutThemeState { return useLayoutState().theme; } export type { ILayoutProviderProps }; export { LayoutProvider, useLayoutContext, useLayoutDispatch, useLayoutDrawerState, useLayoutLogoState, useLayoutMediaState, useLayoutNotificationsState, useLayoutState, useLayoutThemeState, withLayoutProvider };