feat: fix lucide-react renders

feat: fix mobile designs
feat: remove conflicting react-hook-form
feat: change update-account-form path
This commit is contained in:
Danel Kungla
2025-07-18 17:19:12 +03:00
parent 8c090f9d68
commit eec8a12db2
22 changed files with 198 additions and 156 deletions

View File

@@ -10,7 +10,7 @@ import CompanyOfferForm from './_components/company-offer-form';
function CompanyOffer() {
return (
<div className="border-border flex max-w-5xl flex-row overflow-hidden rounded-3xl border">
<div className="flex w-1/2 flex-col px-12 py-14 text-center">
<div className="flex flex-col px-12 py-14 text-center md:w-1/2">
<MedReportLogo />
<h1 className="pt-8">
<Trans i18nKey={'account:requestCompanyAccount:title'} />
@@ -20,7 +20,7 @@ function CompanyOffer() {
</p>
<CompanyOfferForm />
</div>
<div className="w-1/2 min-w-[460px] bg-[url(/assets/med-report-logo-big.png)] bg-cover bg-center bg-no-repeat"></div>
<div className="hidden w-1/2 min-w-[460px] bg-[url(/assets/med-report-logo-big.png)] bg-cover bg-center bg-no-repeat md:block"></div>
</div>
);
}

View File

@@ -0,0 +1,225 @@
'use client';
import Link from 'next/link';
import { User } from '@supabase/supabase-js';
import { ExternalLink } from '@/public/assets/external-link';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { Button } from '@kit/ui/button';
import { Checkbox } from '@kit/ui/checkbox';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@kit/ui/form';
import { Input } from '@kit/ui/input';
import { Trans } from '@kit/ui/trans';
import { UpdateAccountSchema } from '../_lib/schemas/update-account.schema';
import { onUpdateAccount } from '../_lib/server/update-account';
export function UpdateAccountForm({ user }: { user: User }) {
const form = useForm({
resolver: zodResolver(UpdateAccountSchema),
mode: 'onChange',
defaultValues: {
firstName: '',
lastName: '',
personalCode: '',
email: user.email,
phone: '',
city: '',
weight: 0,
height: 0,
userConsent: false,
},
});
return (
<Form {...form}>
<form
className="flex flex-col gap-6 px-6 pt-10 text-left"
onSubmit={form.handleSubmit(onUpdateAccount)}
>
<FormField
name="firstName"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey={'common:formField:firstName'} />
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="lastName"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey={'common:formField:lastName'} />
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="personalCode"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey={'common:formField:personalCode'} />
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey={'common:formField:email'} />
</FormLabel>
<FormControl>
<Input {...field} disabled />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="phone"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey={'common:formField:phone'} />
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="city"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey={'common:formField:city'} />
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex flex-row justify-between gap-4">
<FormField
name="weight"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey={'common:formField:weight'} />
</FormLabel>
<FormControl>
<Input
type="number"
placeholder="kg"
{...field}
value={field.value ?? ''}
onChange={(e) =>
field.onChange(
e.target.value === '' ? null : Number(e.target.value),
)
}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="height"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey={'common:formField:height'} />
</FormLabel>
<FormControl>
<Input
placeholder="cm"
type="number"
{...field}
value={field.value ?? ''}
onChange={(e) =>
field.onChange(
e.target.value === '' ? null : Number(e.target.value),
)
}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<FormField
name="userConsent"
render={({ field }) => (
<FormItem>
<div className="flex flex-row items-center gap-2 pb-1">
<FormControl>
<Checkbox
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
<FormLabel>
<Trans i18nKey={'account:updateAccount:userConsentLabel'} />
</FormLabel>
</div>
<Link
href={''}
className="flex flex-row items-center gap-2 text-sm hover:underline"
target="_blank"
>
<ExternalLink />
<Trans i18nKey={'account:updateAccount:userConsentUrlTitle'} />
</Link>
</FormItem>
)}
/>
<Button disabled={form.formState.isSubmitting} type="submit">
<Trans i18nKey={'account:updateAccount:button'} />
</Button>
</form>
</Form>
);
}

View File

@@ -0,0 +1,44 @@
import { z } from 'zod';
export const UpdateAccountSchema = z.object({
firstName: z
.string({
required_error: 'First name is required',
})
.nonempty(),
lastName: z
.string({
required_error: 'Last name is required',
})
.nonempty(),
personalCode: z
.string({
required_error: 'Personal code is required',
})
.nonempty(),
email: z.string().email({
message: 'Email is required',
}),
phone: z
.string({
required_error: 'Phone number is required',
})
.nonempty(),
city: z.string().optional(),
weight: z
.number({
required_error: 'Weight is required',
invalid_type_error: 'Weight must be a number',
})
.gt(0, { message: 'Weight must be greater than 0' }),
height: z
.number({
required_error: 'Height is required',
invalid_type_error: 'Height must be a number',
})
.gt(0, { message: 'Height must be greater than 0' }),
userConsent: z.boolean().refine((val) => val === true, {
message: 'Must be true',
}),
});

View File

@@ -0,0 +1,51 @@
'use server';
import { redirect } from 'next/navigation';
import { createAuthApi } from '@kit/auth/api';
import { enhanceAction } from '@kit/next/actions';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import pathsConfig from '~/config/paths.config';
import { UpdateAccountSchema } from '../schemas/update-account.schema';
export interface AccountSubmitData {
firstName: string;
lastName: string;
personalCode: string;
email: string;
phone?: string;
city?: string;
weight: number | null;
height: number | null;
userConsent: boolean;
}
export const onUpdateAccount = enhanceAction(
async (params: AccountSubmitData) => {
const client = getSupabaseServerClient();
const api = createAuthApi(client);
try {
await api.updateAccount(params);
console.log('SUCCESS', pathsConfig.auth.updateAccountSuccess);
} catch (err: unknown) {
if (err instanceof Error) {
console.warn('On update account error: ' + err.message);
}
console.warn('On update account error: ', err);
}
const hasUnseenMembershipConfirmation =
await api.hasUnseenMembershipConfirmation();
if (hasUnseenMembershipConfirmation) {
redirect(pathsConfig.auth.membershipConfirmation);
} else {
redirect(pathsConfig.app.selectPackage);
}
},
{
schema: UpdateAccountSchema,
},
);

View File

@@ -4,13 +4,14 @@ import { BackButton } from '@/components/back-button';
import { MedReportLogo } from '@/components/med-report-logo';
import pathsConfig from '@/config/paths.config';
import { signOutAction } from '@/lib/actions/sign-out';
import { UpdateAccountForm } from '@/packages/features/auth/src/components/update-account-form';
import { getSupabaseServerClient } from '@/packages/supabase/src/clients/server-client';
import { Trans } from '@kit/ui/trans';
import { withI18n } from '~/lib/i18n/with-i18n';
import { UpdateAccountForm } from './_components/update-account-form';
async function UpdateAccount() {
const client = getSupabaseServerClient();
@@ -24,7 +25,7 @@ async function UpdateAccount() {
return (
<div className="border-border flex max-w-5xl flex-row overflow-hidden rounded-3xl border">
<div className="relative flex w-1/2 min-w-md flex-col px-12 pt-7 pb-22 text-center">
<div className="relative flex min-w-md flex-col px-12 pt-7 pb-22 text-center md:w-1/2">
<BackButton onBack={signOutAction} />
<MedReportLogo />
<h1 className="pt-8">
@@ -35,7 +36,7 @@ async function UpdateAccount() {
</p>
<UpdateAccountForm user={user} />
</div>
<div className="w-1/2 min-w-[460px] bg-[url(/assets/med-report-logo-big.png)] bg-cover bg-center bg-no-repeat"></div>
<div className="hidden w-1/2 min-w-[460px] bg-[url(/assets/med-report-logo-big.png)] bg-cover bg-center bg-no-repeat md:block"></div>
</div>
);
}

View File

@@ -50,7 +50,7 @@ const AnalysisLevelBar = ({
level: AnalysisResultLevel;
}) => {
return (
<div className="flex h-3 w-full max-w-[360px] gap-1">
<div className="mt-4 flex h-3 w-full max-w-[360px] gap-1 sm:mt-0">
{normLowerIncluded && (
<>
<Level

View File

@@ -1,7 +1,11 @@
import React from 'react';
'use client';
import React, { useState } from 'react';
import { Info } from 'lucide-react';
import { cn } from '@kit/ui/utils';
import AnalysisLevelBar, { AnalysisResultLevel } from './analysis-level-bar';
export enum AnalysisStatus {
@@ -33,6 +37,7 @@ const Analysis = ({
normUpper: number;
};
}) => {
const [showTooltip, setShowTooltip] = useState(false);
const isUnderNorm = value < normLower;
const getAnalysisResultLevel = () => {
if (isUnderNorm) {
@@ -54,12 +59,21 @@ const Analysis = ({
};
return (
<div className="border-border flex items-center justify-between rounded-lg border px-5 py-3">
<div className="border-border grid grid-cols-2 items-center justify-between rounded-lg border px-5 py-3 sm:flex">
<div className="flex items-center gap-2 font-semibold">
{name}
<div className="group/tooltip relative">
<div
className="group/tooltip relative"
onClick={() => setShowTooltip(!showTooltip)}
onMouseLeave={() => setShowTooltip(false)}
>
<Info className="hover" />{' '}
<div className="absolute bottom-full left-1/2 z-10 mb-2 hidden -translate-x-1/2 rounded bg-gray-800 px-2 py-1 text-sm whitespace-nowrap text-white group-hover/tooltip:block">
<div
className={cn(
'absolute bottom-full left-1/2 z-10 mb-2 hidden -translate-x-1/2 rounded border bg-white p-4 text-sm whitespace-nowrap group-hover/tooltip:block',
{ block: showTooltip },
)}
>
This text changes when you hover the box above.
</div>
</div>
@@ -68,7 +82,7 @@ const Analysis = ({
<div className="font-semibold">{value}</div>
<div className="text-muted-foreground text-sm">{unit}</div>
</div>
<div className="text-muted-foreground text-center text-sm">
<div className="text-muted-foreground mt-4 flex gap-2 text-center text-sm sm:mt-0 sm:block sm:gap-0">
{normLower} - {normUpper}
<div>Normaalne vahemik</div>
</div>

View File

@@ -1,6 +1,7 @@
'use client';
import Link from 'next/link';
import { InfoTooltip } from '@/components/ui/info-tooltip';
import { BlendingModeIcon, RulerHorizontalIcon } from '@radix-ui/react-icons';
import {
@@ -130,7 +131,7 @@ const dummyRecommendations = [
export default function Dashboard() {
return (
<>
<div className="grid auto-rows-fr grid-cols-5 gap-3">
<div className="grid auto-rows-fr grid-cols-2 gap-3 sm:grid-cols-4 lg:grid-cols-5">
{dummyCards.map(
({
title,
@@ -190,7 +191,7 @@ export default function Dashboard() {
) => {
return (
<div className="flex justify-between" key={index}>
<div className="flex flex-row items-center gap-4">
<div className="mr-4 flex flex-row items-center gap-4">
<div
className={cn(
'flex size-8 items-center-safe justify-center-safe rounded-full text-white',

View File

@@ -1,14 +1,14 @@
import Link from 'next/link';
import SelectAnalysisPackages from '@/components/select-analysis-packages';
import { CaretRightIcon } from '@radix-ui/react-icons';
import { Scale } from 'lucide-react';
import { Trans } from '@kit/ui/trans';
import { Button } from '@kit/ui/button';
import { Trans } from '@kit/ui/trans';
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
import { withI18n } from '~/lib/i18n/with-i18n';
import SelectAnalysisPackages from '@/components/select-analysis-packages';
import { MedReportLogo } from '../../components/med-report-logo';
import pathsConfig from '../../config/paths.config';
@@ -40,12 +40,14 @@ async function SelectPackagePage() {
/>
</div>
<SelectAnalysisPackages />
<Link href={pathsConfig.app.home}>
<Button variant="secondary" className="align-center">
<Trans i18nKey={'marketing:notInterestedInAudit'} />{' '}
<CaretRightIcon className="size-4" />
</Button>
</Link>
<div className="flex justify-center">
<Link href={pathsConfig.app.home}>
<Button variant="secondary" className="align-center">
<Trans i18nKey="marketing:notInterestedInAudit" />{' '}
<CaretRightIcon className="size-4" />
</Button>
</Link>
</div>
</div>
);
}