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:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
225
app/auth/update-account/_components/update-account-form.tsx
Normal file
225
app/auth/update-account/_components/update-account-form.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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',
|
||||
}),
|
||||
});
|
||||
51
app/auth/update-account/_lib/server/update-account.ts
Normal file
51
app/auth/update-account/_lib/server/update-account.ts
Normal 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,
|
||||
},
|
||||
);
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user