Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
0fe3fbe
fix: make dropdown menus scrollable
imdeaconu Sep 6, 2024
4ca1a44
fix: truncate overflowing table columns
imdeaconu Sep 6, 2024
921aa13
Merge branch 'commitglobal:main' into main
imdeaconu Sep 6, 2024
e5a2869
Merge branch 'commitglobal:main' into main
imdeaconu Sep 6, 2024
7866a67
Merge branch 'commitglobal:main' into main
imdeaconu Sep 9, 2024
9ea6c42
Merge branch 'commitglobal:main' into main
imdeaconu Sep 10, 2024
1bd449d
Merge branch 'commitglobal:main' into main
imdeaconu Sep 11, 2024
c9874d1
Squashed commit of the following:
imdeaconu Sep 11, 2024
b7715f3
Merge branch 'commitglobal:main' into main
imdeaconu Sep 12, 2024
0facf65
Squashed commit of the following:
imdeaconu Sep 13, 2024
67f681d
chore: remove unused import
imdeaconu Sep 13, 2024
8d73252
chore: delete duplicated / unused classes
imdeaconu Sep 16, 2024
63b21b9
Merge branch 'commitglobal:main' into main
imdeaconu Sep 17, 2024
1892e6e
Merge branch 'commitglobal:main' into main
imdeaconu Sep 18, 2024
abb7c01
feature: add searching to MonitoringObserversTagFilter
imdeaconu Sep 19, 2024
9d0b8ae
Merge branch 'commitglobal:main' into main
imdeaconu Sep 20, 2024
c9fcd3e
chore: update config files
imdeaconu Sep 20, 2024
333ba49
Revert "[NGO Admin] Rewrite the tag selector component (#675)"
imdeaconu Sep 23, 2024
580b68e
Merge branch 'main' of https://github.com/commitglobal/votemonitor
imdeaconu Sep 23, 2024
ba2dad9
Merge branch 'commitglobal:main' into main
imdeaconu Sep 25, 2024
eea4faa
Merge branch 'main' of https://github.com/commitglobal/votemonitor in…
imdeaconu Sep 26, 2024
29b8163
Merge branch 'main' of https://github.com/commitglobal/votemonitor in…
imdeaconu Sep 26, 2024
68a44ee
Merge branch 'commitglobal-main'
imdeaconu Sep 26, 2024
7cf3244
Merge branch 'main' of https://github.com/commitglobal/votemonitor in…
imdeaconu Oct 1, 2024
b6abee7
Merge branch 'commitglobal-main-s1'
imdeaconu Oct 1, 2024
cc71856
Merge branch 'commitglobal:main' into main
imdeaconu Oct 2, 2024
e45ea22
Merge branch 'commitglobal:main' into main
imdeaconu Oct 2, 2024
50d15b6
Merge branch 'commitglobal:main' into main
imdeaconu Oct 2, 2024
1ed8e99
Merge branch 'commitglobal:main' into main
imdeaconu Oct 3, 2024
c2f1395
Merge branch 'commitglobal:main' into main
imdeaconu Oct 7, 2024
eee138e
WIP: fix language selector
imdeaconu Oct 9, 2024
505face
WIPȘ add forrm wizard start page
imdeaconu Oct 9, 2024
2c6d5f0
Merge branch 'commitglobal:main' into main
imdeaconu Oct 9, 2024
8c8e18f
Merge branch 'commitglobal:main' into main
imdeaconu Oct 9, 2024
e451894
Merge branch 'main' of https://github.com/commitglobal/votemonitor in…
imdeaconu Oct 9, 2024
4a255f8
Merge branch 'commitglobal-main-fw1' into add-form-wizard
imdeaconu Oct 9, 2024
43b09eb
WIP: update FormBuilder
imdeaconu Oct 9, 2024
cff20a6
WIP: add FormBuilder screens and routes
imdeaconu Oct 10, 2024
db46a6d
Merge branch 'commitglobal:main' into main
imdeaconu Oct 10, 2024
0af5b58
Merge branch 'commitglobal:main' into add-form-wizard
imdeaconu Oct 10, 2024
5515de6
WIP: move FormBuilder into the forms directory
imdeaconu Oct 10, 2024
fa59582
WIP: add new form page instead of modal
imdeaconu Oct 11, 2024
d4827f4
Merge branch 'add-form-wizard' of https://github.com/imdeaconu/votemo…
imdeaconu Oct 11, 2024
d4b0263
Merge branch 'commitglobal:main' into main
imdeaconu Oct 12, 2024
527a2ce
Merge branch 'main' of https://github.com/commitglobal/votemonitor in…
imdeaconu Oct 12, 2024
aa5b8ac
Merge branch 'commitglobal-main' into add-form-wizard
imdeaconu Oct 12, 2024
36848d8
Merge branch 'add-form-wizard' of https://github.com/imdeaconu/votemo…
imdeaconu Oct 12, 2024
b68199d
WIP: fix Dashboard page imports
imdeaconu Oct 12, 2024
214fe10
WIP: update fform edit route
imdeaconu Oct 12, 2024
79864cd
Merge branch 'commitglobal:main' into main
imdeaconu Oct 14, 2024
a492bdd
Merge branch 'main' of https://github.com/commitglobal/votemonitor in…
imdeaconu Oct 14, 2024
66801a7
Merge branch 'commitglobal-main' into add-form-wizard
imdeaconu Oct 14, 2024
aeefd9a
Revert "resync branch" (#10)
imdeaconu Oct 14, 2024
322be73
Revert "Revert "resync branch" (#10)" (#11)
imdeaconu Oct 14, 2024
1fe38d1
fix Dashboard
imdeaconu Oct 14, 2024
3c33794
Merge branch 'add-form-wizard' of https://github.com/imdeaconu/votemo…
imdeaconu Oct 14, 2024
f810c5c
readd updated on tooltip
imdeaconu Oct 14, 2024
45d8a8e
WIP: add form template tables
imdeaconu Oct 14, 2024
5ae7edf
Merge branch 'commitglobal:main' into main
imdeaconu Oct 15, 2024
78eff78
Merge branch 'commitglobal:main' into add-form-wizard
imdeaconu Oct 15, 2024
b766cf4
Merge branch 'add-form-wizard' of https://github.com/imdeaconu/votemo…
imdeaconu Oct 15, 2024
ef63b43
WIP: fix Dashboard page
imdeaconu Oct 15, 2024
a654366
Merge branch 'commitglobal:main' into add-form-wizard
imdeaconu Oct 16, 2024
c0fe98a
Merge branch 'commitglobal:main' into main
imdeaconu Oct 17, 2024
b7b3c5c
Merge branch 'commitglobal:main' into main
imdeaconu Oct 18, 2024
a892349
Merge branch 'commitglobal:main' into main
imdeaconu Oct 19, 2024
2d98793
Merge branch 'commitglobal:main' into main
imdeaconu Oct 20, 2024
66ba8d0
Merge branch 'commitglobal:main' into main
imdeaconu Oct 21, 2024
a86608d
Merge branch 'commitglobal:main' into main
imdeaconu Oct 22, 2024
aa1745c
Merge branch 'commitglobal:main' into main
imdeaconu Oct 23, 2024
9942029
Merge branch 'commitglobal:main' into main
imdeaconu Oct 23, 2024
d855c24
Merge branch 'commitglobal:main' into main
imdeaconu Oct 25, 2024
5a2b99d
Merge branch 'commitglobal:main' into main
imdeaconu Oct 28, 2024
e9ea9a3
Merge branch 'commitglobal:main' into main
imdeaconu Oct 29, 2024
fdaba4b
Merge branch 'commitglobal:main' into main
imdeaconu Oct 29, 2024
777ab43
Merge branch 'commitglobal:main' into main
imdeaconu Nov 4, 2024
36f445a
Merge branch 'main' into add-form-wizard
imdeaconu Nov 4, 2024
1c55e5e
Merge branch 'commitglobal:main' into add-form-wizard
imdeaconu Nov 4, 2024
353e356
WIP: add form template preview
imdeaconu Nov 5, 2024
15101d6
Merge branch 'commitglobal:main' into main
imdeaconu Nov 6, 2024
1620600
Merge branch 'commitglobal:main' into add-form-wizard
imdeaconu Nov 6, 2024
325a888
update preview template dialog
imdeaconu Nov 6, 2024
580c818
create new form from template preview
imdeaconu Nov 11, 2024
ea55804
WIP: update hook for creating forms from teplates
imdeaconu Nov 12, 2024
886bfee
WIP: create reusable components
imdeaconu Nov 13, 2024
e6eb55b
WIP: hide form from form and add business logic
imdeaconu Nov 13, 2024
9289b11
Merge branch 'commitglobal:main' into main
imdeaconu Nov 28, 2024
a82ea16
Merge branch 'commitglobal:main' into main
imdeaconu Nov 30, 2024
77ce22d
Merge branch 'main' into add-form-wizard
imdeaconu Nov 30, 2024
b9431a3
WIP: fix imports
imdeaconu Nov 30, 2024
0f2f9ca
WIP: fix imports and citizen reporting for createNewForm
imdeaconu Nov 30, 2024
edc4272
fix unused import
imdeaconu Nov 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion web/src/components/LanguageSelector/LanguageSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import i18n from '@/i18n';
import { useRouter } from '@tanstack/react-router';
import { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { Label } from '../ui/label';

export const LanguageSelector: FC = () => {
const { i18n } = useTranslation(); // not passing any namespace will use the defaultNS (by default set to 'translation')
const router = useRouter();

const changeLanguage = (lng: string) => {
i18n.changeLanguage(lng);
router.invalidate();
};

const options = [
Expand Down
7 changes: 5 additions & 2 deletions web/src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type { ReactNode } from 'react';
import type { FunctionComponent } from '@/common/types';
import Breadcrumbs from './Breadcrumbs/Breadcrumbs';
import type { ReactNode } from 'react';
import BackButton from './Breadcrumbs/BackButton';
import Breadcrumbs from './Breadcrumbs/Breadcrumbs';

interface LayoutProps {
title?: string;
subtitle?: string;
enableBreadcrumbs?: boolean;
enableBackButton?: boolean;
breadcrumbs?: ReactNode;
backButton?: ReactNode;
actions?: ReactNode;
Expand All @@ -21,6 +22,7 @@ const Layout = ({
breadcrumbs,
children,
enableBreadcrumbs = true,
enableBackButton,
}: LayoutProps): FunctionComponent => {
return (
<>
Expand All @@ -29,6 +31,7 @@ const Layout = ({
{enableBreadcrumbs && (breadcrumbs || <Breadcrumbs />)}
<h1 className='flex flex-row items-center gap-3 text-3xl font-bold tracking-tight text-gray-900'>
{enableBreadcrumbs && (backButton || <BackButton />)}
{enableBackButton && (backButton || <BackButton />)}
{title}
</h1>
{subtitle ?? <h3 className='text-lg font-light'>{subtitle}</h3>}
Expand Down
15 changes: 9 additions & 6 deletions web/src/features/forms/components/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { DataTableColumnHeader } from '@/components/ui/DataTable/DataTableColumn
import { QueryParamsDataTable } from '@/components/ui/DataTable/QueryParamsDataTable';
import { useConfirm } from '@/components/ui/alert-dialog-provider';
import { Badge } from '@/components/ui/badge';
import { buttonVariants } from '@/components/ui/button';
import { Button, buttonVariants } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import {
DropdownMenu,
Expand All @@ -31,17 +31,17 @@ import {
EllipsisVerticalIcon,
FunnelIcon,
PhotoIcon,
PlusIcon,
} from '@heroicons/react/24/outline';
import { useMutation } from '@tanstack/react-query';
import { useNavigate, useRouter } from '@tanstack/react-router';
import { Link, useNavigate, useRouter } from '@tanstack/react-router';
import { ColumnDef, createColumnHelper, Row } from '@tanstack/react-table';
import { useDebounce } from '@uidotdev/usehooks';
import { format } from 'date-fns';
import { useMemo, useState, type ReactElement } from 'react';
import { FormBase, FormStatus } from '../../models/form';
import { formsKeys, useForms } from '../../queries';
import AddTranslationsDialog, { useAddTranslationsDialog } from './AddTranslationsDialog';
import CreateForm from './CreateForm';
import { FormFilters } from './FormFilters/FormFilters';
import EditFormAccessDialog, { useEditFormAccessDialog } from './EditFormAccessDialog';
import { useElectionRoundDetails } from '@/features/election-event/hooks/election-event-hooks';
Expand Down Expand Up @@ -725,9 +725,12 @@ export default function FormsDashboard(): ReactElement {
{i18n.t('electionEvent.observerForms.cardTitle')}
</div>
<div>
<CreateDialog title={i18n.t('electionEvent.observerForms.createDialogTitle')}>
<CreateForm />
</CreateDialog>
<Link to='/forms/new'>
<Button title='Create form' variant='default'>
<PlusIcon className='w-5 h-5 mr-2 -ml-1.5' />
<span>Create form</span>
</Button>
</Link>
</div>
</CardTitle>
<Separator />
Expand Down
37 changes: 22 additions & 15 deletions web/src/features/forms/components/EditForm/EditForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { QuestionType, ZFormType, type FunctionComponent } from '@/common/types';
import { QuestionType, ZFormType } from '@/common/types';
import FormQuestionsEditor from '@/components/questionsEditor/FormQuestionsEditor';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Form } from '@/components/ui/form';
Expand All @@ -25,17 +25,12 @@ import { Button, buttonVariants } from '@/components/ui/button';
import { LanguageBadge } from '@/components/ui/language-badge';
import { toast } from '@/components/ui/use-toast';
import { useCurrentElectionRoundStore } from '@/context/election-round.store';
import {
cn,
ensureTranslatedStringCorrectness,
isNilOrWhitespace,
isNotNilOrWhitespace
} from '@/lib/utils';
import { cn, ensureTranslatedStringCorrectness, isNilOrWhitespace, isNotNilOrWhitespace } from '@/lib/utils';
import { queryClient } from '@/main';
import { Route } from '@/routes/forms_.$formId.edit';
import { useMutation } from '@tanstack/react-query';
import { useBlocker, useNavigate, useRouter } from '@tanstack/react-router';
import { useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { UpdateFormRequest } from '../../models/form';
import { formDetailsQueryOptions, formsKeys } from '../../queries';
import {
Expand All @@ -49,7 +44,6 @@ import {
ZEditQuestionType,
ZTranslatedString,
} from '../../types';
import { FormDetailsBreadcrumbs } from '../FormDetailsBreadcrumbs/FormDetailsBreadcrumbs';
import EditFormDetails from './EditFormDetails';

export const ZEditFormType = z
Expand Down Expand Up @@ -215,7 +209,11 @@ export const ZEditFormType = z

export type EditFormType = z.infer<typeof ZEditFormType>;

export default function EditForm(): FunctionComponent {
interface EditFormProps {
currentTab?: string;
}

const EditForm: FC<EditFormProps> = ({ currentTab }) => {
const { formId } = Route.useParams();
const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId);
const { data: formData } = useSuspenseQuery(formDetailsQueryOptions(currentElectionRoundId, formId));
Expand Down Expand Up @@ -383,7 +381,7 @@ export default function EditForm(): FunctionComponent {
description: ensureTranslatedStringCorrectness(formData.description, formData.languages),
formType: formData.formType,
questions: editQuestions,
icon: formData.icon ?? ''
icon: formData.icon ?? '',
},
mode: 'all',
});
Expand Down Expand Up @@ -423,7 +421,7 @@ export default function EditForm(): FunctionComponent {
});
},

onSuccess: async (_, { shouldExitEditor,electionRoundId }) => {
onSuccess: async (_, { shouldExitEditor, electionRoundId }) => {
toast({
title: 'Success',
description: 'Form updated successfully',
Expand Down Expand Up @@ -474,14 +472,21 @@ export default function EditForm(): FunctionComponent {
}
}, [form.formState.isSubmitSuccessful, form.reset]);

const [activeTab, setActiveTab] = useState(currentTab ?? 'form-details');

return (
<Layout
enableBackButton
backButton={<NavigateBack to='/election-event/$tab' params={{ tab: 'observer-forms' }} />}
breadcrumbs={<FormDetailsBreadcrumbs formCode={code} formName={name[languageCode] ?? ''} />}
enableBreadcrumbs={false}
title={`${code} - ${name[languageCode]}`}>
<Form {...form}>
<form onSubmit={form.handleSubmit(saveForm)} className='flex flex-col flex-1'>
<Tabs className='flex flex-col flex-1' defaultValue='form-details'>
<Tabs
value={activeTab}
onValueChange={setActiveTab}
className='flex flex-col flex-1'
defaultValue='form-details'>
<TabsList className='grid grid-cols-2 bg-gray-200 w-[400px] mb-4'>
<TabsTrigger
value='form-details'
Expand Down Expand Up @@ -556,4 +561,6 @@ export default function EditForm(): FunctionComponent {
</Form>
</Layout>
);
}
};

export default EditForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import { authApi } from '@/common/auth-api';
import { ZFormType } from '@/common/types';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Separator } from '@/components/ui/separator';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Textarea } from '@/components/ui/textarea';
import LanguageSelect from '@/containers/LanguageSelect';
import { useCurrentElectionRoundStore } from '@/context/election-round.store';
import { useElectionRoundDetails } from '@/features/election-event/hooks/election-event-hooks';
import { FormBase, NewFormRequest } from '@/features/forms/models/form';
import { formsKeys } from '@/features/forms/queries';
import { cn, mapFormType, newTranslatedString } from '@/lib/utils';
import { queryClient } from '@/main';
import { zodResolver } from '@hookform/resolvers/zod';
import { useMutation } from '@tanstack/react-query';
import { useNavigate } from '@tanstack/react-router';
import { FC } from 'react';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';

export const CreateFormPage: FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId);
const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId);

const newFormFormSchema = z.object({
code: z.string().nonempty('Form code is required'),
name: z.string().nonempty('Form name is required'),
description: z.string().optional(),
defaultLanguage: z.string().nonempty(),
formType: ZFormType.catch(ZFormType.Values.Opening),
});

const form = useForm<z.infer<typeof newFormFormSchema>>({
resolver: zodResolver(newFormFormSchema),
});

function onSubmit(values: z.infer<typeof newFormFormSchema>) {
const name = newTranslatedString([values.defaultLanguage], values.defaultLanguage, values.name);
const description = newTranslatedString([values.defaultLanguage], values.defaultLanguage, values.description ?? '');

const newForm: NewFormRequest = {
...values,
description,
name,
languages: [values.defaultLanguage],
};

newFormMutation.mutate({ electionRoundId: currentElectionRoundId, newForm });
}

const newFormMutation = useMutation({
mutationFn: ({ electionRoundId, newForm }: { electionRoundId: string; newForm: NewFormRequest }) => {
return authApi.post<FormBase>(`/election-rounds/${electionRoundId}/forms`, newForm);
},

onSuccess: ({ data: form }) => {
queryClient.invalidateQueries({ queryKey: formsKeys.all(currentElectionRoundId) });
navigate({ to: `/forms/$formId/edit`, params: { formId: form.id }, search: { tab: 'questions' } });
},
});

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<Tabs className='flex flex-col flex-1' defaultValue='form-details'>
<TabsList className='grid grid-cols-2 bg-gray-200 w-[400px] mb-4'>
<TabsTrigger
value='form-details'
className={cn({
'border-b-4 border-red-400': form.getFieldState('name').invalid || form.getFieldState('code').invalid,
})}>
Form details
</TabsTrigger>
<TabsTrigger value='questions' disabled>
Questions
</TabsTrigger>
</TabsList>
<TabsContent value='form-details'>
<Card className='pt-0'>
<CardHeader className='flex gap-2 flex-column'>
<div className='flex flex-row items-center justify-between'>
<CardTitle className='text-xl'>Form details</CardTitle>
</div>
<Separator />
</CardHeader>
<CardContent className='flex flex-col items-baseline gap-6'>
<div className='md:inline-flex md:space-x-6 w-full'>
<div className='space-y-4 md:w-1/2'>
<FormField
control={form.control}
name='name'
render={({ field, fieldState }) => (
<FormItem>
<FormLabel>{t('form.field.name')}</FormLabel>
<Input placeholder={t('form.placeholder.name')} {...field} {...fieldState} />
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name='code'
render={({ field, fieldState }) => (
<FormItem>
<FormLabel>{t('form.field.code')}</FormLabel>
<Input placeholder={t('form.placeholder.code')} {...field} {...fieldState} />
<FormMessage />
</FormItem>
)}
/>

<FormField
control={form.control}
name='formType'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.field.formType')}</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder='Select a form type' />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value={ZFormType.Values.Opening}>
{mapFormType(ZFormType.Values.Opening)}
</SelectItem>
<SelectItem value={ZFormType.Values.Voting}>
{mapFormType(ZFormType.Values.Voting)}
</SelectItem>
<SelectItem value={ZFormType.Values.ClosingAndCounting}>
{mapFormType(ZFormType.Values.ClosingAndCounting)}
</SelectItem>
{electionRound?.isMonitoringNgoForCitizenReporting && (
<SelectItem value={ZFormType.Values.CitizenReporting}>
{mapFormType(ZFormType.Values.CitizenReporting)}
</SelectItem>
)}
<SelectItem value={ZFormType.Values.IncidentReporting}>
{mapFormType(ZFormType.Values.IncidentReporting)}
</SelectItem>
<SelectItem value={ZFormType.Values.Other}>
{mapFormType(ZFormType.Values.Other)}
</SelectItem>
</SelectContent>
</Select>
</FormItem>
)}
/>

<FormField
control={form.control}
name='defaultLanguage'
render={({ field, fieldState }) => (
<FormItem>
<FormLabel>{t('form.field.defaultLanguage')}</FormLabel>
<LanguageSelect languageCode={field.value} onLanguageSelected={field.onChange} />
<FormMessage />
</FormItem>
)}
/>
</div>
<div className='md:w-1/2'>
<FormField
control={form.control}
name='description'
render={({ field }) => (
<FormItem>
<FormLabel>{t('form.field.description')}</FormLabel>
<Textarea
resizable={false}
rows={10}
cols={100}
{...field}
placeholder={t('form.placeholder.description')}
/>
</FormItem>
)}
/>
</div>
</div>
</CardContent>
</Card>
</TabsContent>
</Tabs>
<footer className='fixed left-0 bottom-0 h-[64px] w-full bg-white'>
<div className='container flex items-center justify-end h-full gap-4'>
<Button title='Next' type='submit' variant='default' disabled={!form.formState.isValid}>
Next
</Button>
</div>
</footer>
</form>
</Form>
);
};
Loading