add health benefit form

fix super admin
This commit is contained in:
Danel Kungla
2025-07-23 16:33:24 +03:00
parent 2db67b7f20
commit 86b86c6752
43 changed files with 1329 additions and 561 deletions

View File

@@ -0,0 +1,83 @@
import {
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@kit/ui/form';
import { Input } from '@kit/ui/input';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@kit/ui/select';
import { Trans } from '@kit/ui/trans';
const HealthBenefitFields = () => {
return (
<div className="flex flex-col gap-3">
<FormField
name="occurance"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey="billing:healthBenefitForm.title" />
</FormLabel>
<FormControl>
<Select {...field} onValueChange={field.onChange}>
<SelectTrigger>
<SelectValue
placeholder={<Trans i18nKey="common:formField:occurance" />}
/>
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="yearly">
<Trans i18nKey="billing:occurance.yearly" />
</SelectItem>
<SelectItem value="quarterly">
<Trans i18nKey="billing:occurance.quarterly" />
</SelectItem>
<SelectItem value="monthly">
<Trans i18nKey="billing:occurance.monthly" />
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
name="amount"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans i18nKey={'common:formField:amount'} />
</FormLabel>
<FormControl>
<Input
{...field}
type="number"
onChange={(e) =>
field.onChange(
e.target.value === '' ? null : Number(e.target.value),
)
}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
);
};
export default HealthBenefitFields;

View File

@@ -0,0 +1,111 @@
'use client';
import { UpdateHealthBenefitSchema } from '@/packages/billing/core/src/schema';
import { Database } from '@/packages/supabase/src/database.types';
import { zodResolver } from '@hookform/resolvers/zod';
import { PiggyBankIcon } from 'lucide-react';
import { useForm } from 'react-hook-form';
import { Button } from '@kit/ui/button';
import { Form } from '@kit/ui/form';
import { Spinner } from '@kit/ui/makerkit/spinner';
import { Separator } from '@kit/ui/shadcn/separator';
import { toast } from '@kit/ui/shadcn/sonner';
import { Trans } from '@kit/ui/trans';
import { cn } from '~/lib/utils';
import { updateHealthBenefit } from '../_lib/server/server-actions';
import HealthBenefitFields from './health-benefit-fields';
import YearlyExpensesOverview from './yearly-expenses-overview';
const HealthBenefitForm = ({
account,
companyParams,
}: {
account: Database['medreport']['Tables']['accounts']['Row'];
companyParams: Database['medreport']['Tables']['company_params']['Row'];
}) => {
const form = useForm({
resolver: zodResolver(UpdateHealthBenefitSchema),
mode: 'onChange',
defaultValues: {
occurance: companyParams.benefit_occurance || 'yearly',
amount: companyParams.benefit_amount || 0,
},
});
return (
<Form {...form}>
<form
className="flex flex-col gap-6 px-6 text-left"
onSubmit={form.handleSubmit((data) => {
toast.promise(
() => updateHealthBenefit({ ...data, accountId: account.id }),
{
success: 'success',
error: 'error',
},
);
})}
>
<div className="mt-8 flex items-center justify-between">
<div>
<h4>
<Trans
i18nKey="billing:pageTitle"
values={{ companyName: account.slug }}
/>
</h4>
<p className="text-muted-foreground text-sm">
<Trans i18nKey="billing:description" />
</p>
</div>
<Button type="submit" className="relative">
{form.formState.isSubmitting && (
<div className="absolute inset-0 flex items-center justify-center">
<Spinner />
</div>
)}
<div className={cn({ invisible: form.formState.isSubmitting })}>
<Trans i18nKey="account:saveChanges" />
</div>
</Button>
</div>
<div className="flex flex-row gap-6">
<div className="border-border w-1/3 rounded-lg border">
<div className="p-6">
<div className="flex h-16 w-16 items-center justify-center rounded-full bg-orange-100">
<PiggyBankIcon className="h-[32px] w-[32px] stroke-orange-400 stroke-2" />
</div>
<p className="mt-4 text-sm font-medium">
<Trans i18nKey="billing:healthBenefitForm.description" />
</p>
<p className="pt-2 text-2xl font-semibold">
{companyParams.benefit_amount || 0}
</p>
</div>
<Separator />
<div className="p-6">
<HealthBenefitFields />
</div>
</div>
<div className="flex-1">
<YearlyExpensesOverview
employeeCount={22}
companyParams={companyParams}
/>
<p className="text-muted-foreground mt-2 text-sm">
<Trans i18nKey="billing:healthBenefitForm.info" />
</p>
</div>
</div>
</form>
</Form>
);
};
export default HealthBenefitForm;

View File

@@ -0,0 +1,90 @@
import { useMemo } from 'react';
import { Database } from '@/packages/supabase/src/database.types';
import { Trans } from '@kit/ui/makerkit/trans';
import { Separator } from '@kit/ui/separator';
const YearlyExpensesOverview = ({
employeeCount = 0,
companyParams,
}: {
employeeCount?: number;
companyParams: Database['medreport']['Tables']['company_params']['Row'];
}) => {
const monthlyExpensePerEmployee = useMemo(() => {
if (!companyParams.benefit_amount) {
return '0.00';
}
switch (companyParams.benefit_occurance) {
case 'yearly':
return (companyParams.benefit_amount / 12).toFixed(2);
case 'quarterly':
return (companyParams.benefit_amount / 4).toFixed(2);
case 'monthly':
return companyParams.benefit_amount.toFixed(2);
default:
return '0.00';
}
}, [companyParams]);
const maxYearlyExpensePerEmployee = useMemo(() => {
if (!companyParams.benefit_amount) {
return '0.00';
}
switch (companyParams.benefit_occurance) {
case 'yearly':
return companyParams.benefit_amount.toFixed(2);
case 'quarterly':
return (companyParams.benefit_amount * 4).toFixed(2);
case 'monthly':
return (companyParams.benefit_amount * 12).toFixed(2);
default:
return '0.00';
}
}, [companyParams]);
return (
<div className="border-border rounded-lg border p-6">
<h5>
<Trans i18nKey="billing:expensesOverview.title" />
</h5>
<div className="mt-5 flex justify-between">
<p className="text-sm font-medium">
<Trans i18nKey="billing:expensesOverview.monthly" />
</p>
<span className="text-primary text-sm font-bold">
{monthlyExpensePerEmployee}
</span>
</div>
<div className="mt-3 flex justify-between">
<p className="text-sm font-medium">
<Trans i18nKey="billing:expensesOverview.yearly" />
</p>
<span className="text-sm font-medium">
{maxYearlyExpensePerEmployee}
</span>
</div>
<div className="mt-5 mb-3 flex justify-between">
<p className="text-sm font-medium">
<Trans
i18nKey="billing:expensesOverview.total"
values={{ employeeCount: employeeCount || 0 }}
/>
</p>
<span className="text-sm font-medium">
{(Number(maxYearlyExpensePerEmployee) * employeeCount).toFixed(2)}
</span>
</div>
<Separator />
<div className="mt-4 flex justify-between">
<p className="font-semibold">Kokku</p>
<span className="font-semibold">13 200,00 </span>
</div>
</div>
);
};
export default YearlyExpensesOverview;