223 lines
6.8 KiB
TypeScript
223 lines
6.8 KiB
TypeScript
'use client';
|
|
|
|
import { useMemo } from 'react';
|
|
|
|
import Link from 'next/link';
|
|
|
|
import { StoreCart } from '@medusajs/types';
|
|
import { Cross, Menu, Shield, ShoppingCart, UserCircle } from 'lucide-react';
|
|
|
|
import { usePersonalAccountData } from '@kit/accounts/hooks/use-personal-account-data';
|
|
import { ApplicationRoleEnum } from '@kit/accounts/types/accounts';
|
|
import SignOutDropdownItem from '@kit/shared/components/sign-out-dropdown-item';
|
|
import DropdownLink from '@kit/shared/components/ui/dropdown-link';
|
|
import {
|
|
pathsConfig,
|
|
personalAccountNavigationConfig,
|
|
} from '@kit/shared/config';
|
|
import { useSignOut } from '@kit/supabase/hooks/use-sign-out';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuGroup,
|
|
DropdownMenuItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from '@kit/ui/dropdown-menu';
|
|
import { If } from '@kit/ui/if';
|
|
import { cn } from '@kit/ui/shadcn';
|
|
import { Avatar, AvatarFallback, AvatarImage } from '@kit/ui/shadcn/avatar';
|
|
import { Button } from '@kit/ui/shadcn/button';
|
|
import { Trans } from '@kit/ui/trans';
|
|
|
|
// home imports
|
|
import type { UserWorkspace } from '../_lib/server/load-user-workspace';
|
|
import { UserNotifications } from './user-notifications';
|
|
|
|
const PERSONAL_ACCOUNT_SLUG = 'personal';
|
|
|
|
export function HomeMobileNavigation(props: {
|
|
workspace: UserWorkspace;
|
|
cart: StoreCart | null;
|
|
}) {
|
|
const { user, accounts } = props.workspace;
|
|
|
|
const signOut = useSignOut();
|
|
const { data: personalAccountData } = usePersonalAccountData(user.id);
|
|
|
|
const Links = personalAccountNavigationConfig.routes.map((item, index) => {
|
|
if ('children' in item) {
|
|
return item.children.map((child) => {
|
|
return (
|
|
<DropdownLink
|
|
key={child.path}
|
|
Icon={child.Icon}
|
|
path={child.path}
|
|
label={child.label}
|
|
/>
|
|
);
|
|
});
|
|
}
|
|
|
|
if ('divider' in item) {
|
|
return <DropdownMenuSeparator key={index} />;
|
|
}
|
|
});
|
|
|
|
const hasTotpFactor = useMemo(() => {
|
|
const factors = user?.factors ?? [];
|
|
return factors.some(
|
|
(factor) => factor.factor_type === 'totp' && factor.status === 'verified',
|
|
);
|
|
}, [user?.factors]);
|
|
|
|
const isSuperAdmin = useMemo(() => {
|
|
const hasAdminRole =
|
|
personalAccountData?.application_role === ApplicationRoleEnum.SuperAdmin;
|
|
|
|
return hasAdminRole && hasTotpFactor;
|
|
}, [user, personalAccountData, hasTotpFactor]);
|
|
|
|
const isDoctor = useMemo(() => {
|
|
const hasDoctorRole =
|
|
personalAccountData?.application_role === ApplicationRoleEnum.Doctor;
|
|
|
|
return hasDoctorRole && hasTotpFactor;
|
|
}, [user, personalAccountData, hasTotpFactor]);
|
|
|
|
const cartQuantityTotal =
|
|
props.cart?.items?.reduce((acc, item) => acc + item.quantity, 0) ?? 0;
|
|
const hasCartItems = cartQuantityTotal > 0;
|
|
|
|
return (
|
|
<DropdownMenu>
|
|
<div className="flex justify-between gap-3">
|
|
<Link href={pathsConfig.app.cart}>
|
|
<Button
|
|
variant="ghost"
|
|
className="relative mr-0 h-10 cursor-pointer border-1 px-4 py-2"
|
|
>
|
|
<ShoppingCart className="stroke-[1.5px]" />
|
|
{hasCartItems && (
|
|
<>
|
|
(
|
|
<span className="text-success font-bold">
|
|
{cartQuantityTotal}
|
|
</span>
|
|
)
|
|
</>
|
|
)}
|
|
</Button>
|
|
</Link>
|
|
|
|
<UserNotifications userId={user.id} />
|
|
|
|
<DropdownMenuTrigger>
|
|
<Menu className="h-6 w-6" />
|
|
</DropdownMenuTrigger>
|
|
</div>
|
|
<DropdownMenuContent sideOffset={10} className={'w-screen rounded-none'}>
|
|
<If condition={props.cart && hasCartItems}>
|
|
<DropdownMenuGroup>
|
|
<DropdownLink
|
|
path={pathsConfig.app.cart}
|
|
label="common:shoppingCartCount"
|
|
Icon={<ShoppingCart className="stroke-[1.5px]" />}
|
|
labelOptions={{ count: cartQuantityTotal }}
|
|
/>
|
|
</DropdownMenuGroup>
|
|
<DropdownMenuSeparator />
|
|
</If>
|
|
|
|
<DropdownMenuGroup>
|
|
{Links}
|
|
<DropdownLink
|
|
Icon={<UserCircle className="w-4 stroke-[1.5px]" />}
|
|
path={pathsConfig.app.personalAccountSettings}
|
|
label="common:routes.profile"
|
|
/>
|
|
</DropdownMenuGroup>
|
|
|
|
<If condition={isSuperAdmin}>
|
|
<DropdownMenuSeparator />
|
|
|
|
<DropdownMenuItem asChild>
|
|
<Link
|
|
className={
|
|
's-full flex cursor-pointer items-center space-x-2 text-yellow-700 dark:text-yellow-500'
|
|
}
|
|
href={pathsConfig.app.admin}
|
|
>
|
|
<Shield className={'h-5'} />
|
|
|
|
<span>Super Admin</span>
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
</If>
|
|
|
|
<If condition={isDoctor}>
|
|
<DropdownMenuSeparator />
|
|
|
|
<DropdownMenuItem asChild>
|
|
<Link
|
|
className={
|
|
'flex h-full cursor-pointer items-center space-x-2 text-yellow-700 dark:text-yellow-500'
|
|
}
|
|
href={pathsConfig.app.doctor}
|
|
>
|
|
<Cross className={'h-5'} />
|
|
|
|
<span>
|
|
<Trans i18nKey="common:doctor" />
|
|
</span>
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
</If>
|
|
<DropdownMenuSeparator />
|
|
|
|
<If condition={accounts.length > 0}>
|
|
<span className="text-muted-foreground px-2 text-xs">
|
|
<Trans
|
|
i18nKey={'teams:yourTeams'}
|
|
values={{ teamsCount: accounts.length }}
|
|
/>
|
|
</span>
|
|
|
|
{accounts.map((account) => (
|
|
<DropdownMenuItem key={account.value} asChild>
|
|
<Link
|
|
className={'s-full flex cursor-pointer items-center space-x-2'}
|
|
href={`${pathsConfig.app.home}/${account.value}`}
|
|
>
|
|
<div className={'flex items-center'}>
|
|
<Avatar className={'h-5 w-5 rounded-xs ' + account.image}>
|
|
<AvatarImage
|
|
{...(account.image && { src: account.image })}
|
|
/>
|
|
|
|
<AvatarFallback
|
|
className={cn('rounded-md', {
|
|
['bg-background']:
|
|
PERSONAL_ACCOUNT_SLUG === account.value,
|
|
['group-hover:bg-background']:
|
|
PERSONAL_ACCOUNT_SLUG !== account.value,
|
|
})}
|
|
>
|
|
{account.label ? account.label[0] : ''}
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
|
|
<span className={'pl-3'}>{account.label}</span>
|
|
</div>
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
))}
|
|
<DropdownMenuSeparator />
|
|
</If>
|
|
|
|
<SignOutDropdownItem onSignOut={() => signOut.mutateAsync()} />
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
);
|
|
}
|