import { join } from 'path' import { Location } from 'history' import { Children, cloneElement, memo, ReactElement, ReactNode, useCallback, useContext, useMemo } from 'react' import { Redirect, Route, Switch, SwitchProps, useLocation } from 'react-router-dom' import { RootPathContext } from '@asb/context' import { isURLAvailable } from '@utils/permissions' import { getUserId } from '@utils/storage' export type PrivateSwitchProps = SwitchProps & { root?: string redirect?: (location?: Location) => ReactNode elseRedirect?: string | string[] } const getDefaultRedirectPath = () => getUserId() ? '/access_denied' : '/login' export const defaultRedirect = (location?: Location) => ( ) export const PrivateSwitch = memo(({ root, elseRedirect, redirect = defaultRedirect, children }) => { const rootContext = useContext(RootPathContext) const rootPath = useMemo(() => root ?? rootContext ?? '', [root, rootContext]) const location = useLocation() const toAbsolute = useCallback((path: string) => path.startsWith('/') ? path : join(rootPath, path), [rootPath]) const items = useMemo(() => Children.toArray(children).map((child) => { const element = child as ReactElement let key = element.key?.toString() if (!key) return null key = key.slice(key.lastIndexOf('$') + 1).replaceAll('=2', ':') // Ключ автоматический преобразуется в "(.+)\$ключ" // Все ":" в ключе заменяются на "=2" // TODO: улучшить метод нормализации ключа const path = toAbsolute(key) return ( isURLAvailable(path) ? cloneElement(element) : redirect(location)} /> ) }), [children, redirect, toAbsolute]) const defaultRoute = useMemo(() => { if (!elseRedirect) { const path = items.map((elm) => elm?.props.path).find((path) => path && isURLAvailable(path)) if (path) return path } else if (Array.isArray(elseRedirect)) { const path = elseRedirect.find((path) => { if (!path) return false return isURLAvailable(toAbsolute(path)) }) if (path) return toAbsolute(path) } else if(elseRedirect && isURLAvailable(toAbsolute(elseRedirect))) { return toAbsolute(elseRedirect) } return getDefaultRedirectPath() }, [items, elseRedirect, toAbsolute]) return ( {items} ) }) export default PrivateSwitch