MED-140: ui fixes (#69)

* MED-140: ui fixes

* make accountid optional in hook
This commit is contained in:
Helena
2025-09-02 12:14:24 +03:00
committed by GitHub
parent 3498406a0c
commit 9d62a2d86f
13 changed files with 142 additions and 64 deletions

View File

@@ -69,7 +69,7 @@ function AuthButtons() {
</div>
<div className={'flex gap-x-2.5'}>
<Button className={'hidden md:block'} asChild variant={'ghost'}>
<Button className={'block'} asChild variant={'ghost'}>
<Link href={pathsConfig.auth.signIn}>
<Trans i18nKey={'auth:signIn'} />
</Link>

View File

@@ -1,30 +1,28 @@
import { Trans } from '@kit/ui/trans';
import {
Card,
CardHeader,
CardDescription,
CardFooter,
} from '@kit/ui/card';
import Link from 'next/link';
import { Button } from '@kit/ui/button';
import { ChevronRight, HeartPulse } from 'lucide-react';
import { Button } from '@kit/ui/button';
import { Card, CardDescription, CardFooter, CardHeader } from '@kit/ui/card';
import { Trans } from '@kit/ui/trans';
export default function DashboardCards() {
return (
<div className='flex gap-4 lg:px-4'>
<div className="flex gap-4 lg:px-4">
<Card
variant="gradient-success"
className="flex flex-col justify-between"
className="xs:w-1/2 sm:w-auto flex w-full flex-col justify-between"
>
<CardHeader className="flex-row">
<div
className={'flex size-8 items-center-safe justify-center-safe rounded-full text-white bg-primary\/10 mb-6'}
className={
'bg-primary/10 mb-6 flex size-8 items-center-safe justify-center-safe rounded-full text-white'
}
>
<HeartPulse className="size-4 fill-green-500" />
</div>
<div className='ml-auto flex size-8 items-center-safe justify-center-safe rounded-full text-white bg-warning'>
<Link href='/home/order-analysis'>
<div className="bg-warning ml-auto flex size-8 items-center-safe justify-center-safe rounded-full text-white">
<Link href="/home/order-analysis">
<Button size="icon" variant="outline" className="px-2 text-black">
<ChevronRight className="size-4 stroke-2" />
</Button>
@@ -33,10 +31,10 @@ export default function DashboardCards() {
</CardHeader>
<CardFooter className="flex flex-col items-start gap-2">
<h5>
<Trans i18nKey='dashboard:heroCard.orderAnalysis.title' />
<Trans i18nKey="dashboard:heroCard.orderAnalysis.title" />
</h5>
<CardDescription className="text-primary">
<Trans i18nKey='dashboard:heroCard.orderAnalysis.description' />
<Trans i18nKey="dashboard:heroCard.orderAnalysis.description" />
</CardDescription>
</CardFooter>
</Card>

View File

@@ -166,7 +166,7 @@ export default function Dashboard({
return (
<>
<div className="grid auto-rows-fr grid-cols-2 gap-3 sm:grid-cols-4 lg:grid-cols-5">
<div className="xs:grid-cols-2 grid auto-rows-fr gap-3 sm:grid-cols-4 lg:grid-cols-5">
{cards({
gender: params?.gender,
age: params?.age,
@@ -233,8 +233,11 @@ export default function Dashboard({
index,
) => {
return (
<div className="flex justify-between" key={index}>
<div className="mr-4 flex flex-row items-center gap-4">
<div
className="flex w-full justify-between gap-3 overflow-scroll"
key={index}
>
<div className="mr-4 flex min-w-fit flex-row items-center gap-4">
<div
className={cn(
'flex size-8 items-center-safe justify-center-safe rounded-full text-white',
@@ -243,7 +246,7 @@ export default function Dashboard({
>
{icon}
</div>
<div>
<div className="min-w-fit">
<div className="inline-flex items-center gap-1 align-baseline text-sm font-medium">
{title}
<InfoTooltip content={tooltipContent} />
@@ -253,16 +256,24 @@ export default function Dashboard({
</p>
</div>
</div>
<div className="grid w-36 auto-rows-fr grid-cols-2 items-center gap-4">
<div className="grid w-36 auto-rows-fr grid-cols-2 items-center gap-4 min-w-fit">
<p className="text-sm font-medium"> {price}</p>
{href ? (
<Link href={href}>
<Button size="sm" variant="secondary">
<Button
size="sm"
variant="secondary"
className="w-full min-w-fit"
>
{buttonText}
</Button>
</Link>
) : (
<Button size="sm" variant="secondary">
<Button
size="sm"
variant="secondary"
className="w-full min-w-fit"
>
{buttonText}
</Button>
)}

View File

@@ -1,12 +1,16 @@
'use client';
import { useMemo } from 'react';
import Link from 'next/link';
import { StoreCart } from '@medusajs/types';
import { LogOut, Menu, ShoppingCart } from 'lucide-react';
import { Cross, LogOut, Menu, Shield, ShoppingCart } from 'lucide-react';
import { usePersonalAccountData } from '@kit/accounts/hooks/use-personal-account-data';
import { ApplicationRoleEnum } from '@kit/accounts/types/accounts';
import {
featureFlagsConfig,
pathsConfig,
personalAccountNavigationConfig,
} from '@kit/shared/config';
import { useSignOut } from '@kit/supabase/hooks/use-sign-out';
@@ -15,7 +19,6 @@ import {
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@kit/ui/dropdown-menu';
@@ -23,14 +26,16 @@ import { If } from '@kit/ui/if';
import { Trans } from '@kit/ui/trans';
// home imports
import { HomeAccountSelector } from '../_components/home-account-selector';
import type { UserWorkspace } from '../_lib/server/load-user-workspace';
export function HomeMobileNavigation(props: {
workspace: UserWorkspace;
cart: StoreCart | null;
}) {
const user = props.workspace.user;
const signOut = useSignOut();
const { data: personalAccountData } = usePersonalAccountData(user.id);
const Links = personalAccountNavigationConfig.routes.map((item, index) => {
if ('children' in item) {
@@ -51,7 +56,29 @@ export function HomeMobileNavigation(props: {
}
});
const cartQuantityTotal = props.cart?.items?.reduce((acc, item) => acc + item.quantity, 0) ?? 0;
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 (
@@ -61,22 +88,6 @@ export function HomeMobileNavigation(props: {
</DropdownMenuTrigger>
<DropdownMenuContent sideOffset={10} className={'w-screen rounded-none'}>
<If condition={featureFlagsConfig.enableTeamAccounts}>
<DropdownMenuGroup>
<DropdownMenuLabel>
<Trans i18nKey={'common:yourAccounts'} />
</DropdownMenuLabel>
<HomeAccountSelector
userId={props.workspace.user.id}
accounts={props.workspace.accounts}
collisionPadding={0}
/>
</DropdownMenuGroup>
<DropdownMenuSeparator />
</If>
<If condition={props.cart && hasCartItems}>
<DropdownMenuGroup>
<DropdownLink
@@ -91,6 +102,41 @@ export function HomeMobileNavigation(props: {
<DropdownMenuGroup>{Links}</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 />
<SignOutDropdownItem onSignOut={() => signOut.mutateAsync()} />

View File

@@ -52,7 +52,7 @@ export default function OrderAnalysesCards({
}
return (
<div className="grid grid-cols-3 gap-6 mt-4">
<div className="grid 2xs:grid-cols-3 gap-6 mt-4">
{analyses.map(({
title,
variant,

View File

@@ -6,8 +6,8 @@ import { listRegions } from '@lib/data/regions';
import { getAnalysisElementMedusaProductIds } from '@/utils/medusa-product';
import type { StoreProduct } from '@medusajs/types';
import { loadCurrentUserAccount } from './load-user-account';
import { AnalysisPackageWithVariant } from '~/components/select-analysis-package';
import { AccountWithParams } from '@/packages/features/accounts/src/server/api';
import { AnalysisPackageWithVariant } from '@kit/shared/components/select-analysis-package';
async function countryCodesLoader() {
const countryCodes = await listRegions().then((regions) =>

View File

@@ -5,12 +5,16 @@ import { useSupabase } from '@kit/supabase/hooks/use-supabase';
type UpdateData = Database['medreport']['Tables']['accounts']['Update'];
export function useUpdateAccountData(accountId: string) {
export function useUpdateAccountData(accountId?: string) {
const client = useSupabase();
const mutationKey = ['account:data', accountId];
const mutationFn = async (data: UpdateData) => {
if (!accountId) {
return null;
}
const response = await client
.schema('medreport')
.from('accounts')

View File

@@ -7,7 +7,7 @@ export function AuthLayoutShell({
return (
<div
className={
'flex h-screen flex-col items-center justify-center' +
'sm:py-auto flex flex-col items-center justify-center py-6' +
' bg-background lg:bg-muted/30 gap-y-10 lg:gap-y-8' +
' animate-in fade-in slide-in-from-top-16 zoom-in-95 duration-1000'
}

View File

@@ -1,6 +1,8 @@
import { Trans } from '@kit/ui/trans';
import SelectAnalysisPackage, { AnalysisPackageWithVariant } from './select-analysis-package';
import SelectAnalysisPackage, {
AnalysisPackageWithVariant,
} from './select-analysis-package';
export default function SelectAnalysisPackages({
analysisPackages,
@@ -10,11 +12,16 @@ export default function SelectAnalysisPackages({
countryCode: string;
}) {
return (
<div className="grid grid-cols-3 gap-6">
{analysisPackages.length > 0 ? analysisPackages.map(
(analysisPackage) => (
<SelectAnalysisPackage key={analysisPackage.title} analysisPackage={analysisPackage} countryCode={countryCode} />
)) : (
<div className="grid gap-6 sm:grid-cols-3">
{analysisPackages.length > 0 ? (
analysisPackages.map((analysisPackage) => (
<SelectAnalysisPackage
key={analysisPackage.title}
analysisPackage={analysisPackage}
countryCode={countryCode}
/>
))
) : (
<h4>
<Trans i18nKey="order-analysis-package:noPackagesAvailable" />
</h4>

View File

@@ -40,7 +40,7 @@ export function LanguageSelector({
}, [currentLanguage]);
const userId = user?.id;
const updateAccountMutation = useUpdateAccountData(userId!);
const updateAccountMutation = useUpdateAccountData(userId);
const revalidateUserDataQuery = useRevalidatePersonalAccountDataQuery();
const updateLanguagePreference = async (
@@ -52,6 +52,10 @@ export function LanguageSelector({
onChange(locale);
}
if (!userId) {
return i18n.changeLanguage(locale);
}
const promise = updateAccountMutation
.mutateAsync({
preferred_locale: locale,

View File

@@ -1,5 +1,7 @@
import { cn } from '../../lib/utils';
import { LanguageSelector } from '@kit/ui/language-selector';
import { cn } from '../../lib/utils';
interface HeaderProps extends React.HTMLAttributes<HTMLDivElement> {
logo?: React.ReactNode;
navigation?: React.ReactNode;
@@ -22,11 +24,16 @@ export const Header: React.FC<HeaderProps> = function ({
{...props}
>
<div className="container">
<div className="grid h-14 grid-cols-3 items-center">
<div className={'mx-auto md:mx-0'}>{logo}</div>
<div className="order-first md:order-none">{navigation}</div>
<div className="2xs:h-14 2xs:grid-cols-3 grid h-24 w-full items-center">
<div className={'mx-auto flex'}>{logo}</div>
<div className="2xs:order-none order-first">{navigation}</div>
<div className="flex items-center justify-end gap-x-2"><div className="max-w-[100px]"><LanguageSelector /></div>{actions}</div>
<div className="2xs:justify-end 2xs:gap-x-2 flex items-center justify-evenly">
<div className="max-w-[100px]">
<LanguageSelector />
</div>
{actions}
</div>
</div>
</div>
</div>

View File

@@ -42,7 +42,7 @@ function PageWithSidebar(props: PageProps) {
>
{MobileNavigation}
<div className={'bg-background flex flex-1 flex-col px-4 lg:px-0 pb-8'}>
<div className={'bg-background flex flex-1 flex-col px-4 pb-8 lg:px-0'}>
{Children}
</div>
</div>
@@ -58,7 +58,7 @@ export function PageMobileNavigation(
return (
<div
className={cn(
'flex w-full items-center border-b px-4 py-2 lg:hidden lg:px-0',
'flex w-full items-center px-4 py-2 lg:hidden lg:px-0',
props.className,
)}
>

View File

@@ -135,6 +135,7 @@
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
--breakpoint-2xs: 36rem;
--breakpoint-xs: 48rem;
--breakpoint-sm: 64rem;
--breakpoint-md: 70rem;