Compare commits

...

5 Commits

17 changed files with 330 additions and 30 deletions

View File

@ -10,7 +10,9 @@
}, },
"dependencies": { "dependencies": {
"@tanstack/react-query": "^5.69.0", "@tanstack/react-query": "^5.69.0",
"@tanstack/react-table": "^8.21.2",
"axios": "^1.8.4", "axios": "^1.8.4",
"clsx": "^2.1.1",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"next": "15.2.3", "next": "15.2.3",
"next-auth": "^4.24.11", "next-auth": "^4.24.11",

31
pnpm-lock.yaml generated
View File

@ -11,9 +11,15 @@ importers:
'@tanstack/react-query': '@tanstack/react-query':
specifier: ^5.69.0 specifier: ^5.69.0
version: 5.69.0(react@19.0.0) version: 5.69.0(react@19.0.0)
'@tanstack/react-table':
specifier: ^8.21.2
version: 8.21.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
axios: axios:
specifier: ^1.8.4 specifier: ^1.8.4
version: 1.8.4 version: 1.8.4
clsx:
specifier: ^2.1.1
version: 2.1.1
jwt-decode: jwt-decode:
specifier: ^4.0.0 specifier: ^4.0.0
version: 4.0.0 version: 4.0.0
@ -509,6 +515,17 @@ packages:
peerDependencies: peerDependencies:
react: ^18 || ^19 react: ^18 || ^19
'@tanstack/react-table@8.21.2':
resolution: {integrity: sha512-11tNlEDTdIhMJba2RBH+ecJ9l1zgS2kjmexDPAraulc8jeNA4xocSNeyzextT0XJyASil4XsCYlJmf5jEWAtYg==}
engines: {node: '>=12'}
peerDependencies:
react: '>=16.8'
react-dom: '>=16.8'
'@tanstack/table-core@8.21.2':
resolution: {integrity: sha512-uvXk/U4cBiFMxt+p9/G7yUWI/UbHYbyghLCjlpWZ3mLeIZiUBSKcUnw9UnKkdRz7Z/N4UBuFLWQdJCjUe7HjvA==}
engines: {node: '>=12'}
'@tybys/wasm-util@0.9.0': '@tybys/wasm-util@0.9.0':
resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
@ -762,6 +779,10 @@ packages:
client-only@0.0.1: client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
color-convert@2.0.1: color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'} engines: {node: '>=7.0.0'}
@ -2300,6 +2321,14 @@ snapshots:
'@tanstack/query-core': 5.69.0 '@tanstack/query-core': 5.69.0
react: 19.0.0 react: 19.0.0
'@tanstack/react-table@8.21.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@tanstack/table-core': 8.21.2
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
'@tanstack/table-core@8.21.2': {}
'@tybys/wasm-util@0.9.0': '@tybys/wasm-util@0.9.0':
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
@ -2594,6 +2623,8 @@ snapshots:
client-only@0.0.1: {} client-only@0.0.1: {}
clsx@2.1.1: {}
color-convert@2.0.1: color-convert@2.0.1:
dependencies: dependencies:
color-name: 1.1.4 color-name: 1.1.4

View File

@ -1,4 +1,7 @@
"use client";
import Form from "#/components/form/form" import Form from "#/components/form/form"
import { loginSchema } from "#/schema/loginSchema"
export default function LoginPage() { export default function LoginPage() {
return( return(
@ -17,10 +20,12 @@ export default function LoginPage() {
label: "Password", label: "Password",
name: "password", name: "password",
type: "password", type: "password",
placeholder: "Enter votre mot de passe" placeholder: "Enter votre mot de passe",
showPasswordToggle: true
} }
]} ]}
submit={undefined} submit={undefined}
schema={loginSchema}
child={<button type="submit" className="btn-auth">Connexion</button>} child={<button type="submit" className="btn-auth">Connexion</button>}
/> />
</div> </div>

View File

@ -31,6 +31,7 @@ body {
padding: 12px; padding: 12px;
border: 1px solid #d1d5dc; border: 1px solid #d1d5dc;
border-radius: 9999px; border-radius: 9999px;
color: black;
&:focus { &:focus {
outline-color: none; outline-color: none;
@ -59,4 +60,9 @@ body {
color: white; color: white;
width: 100%; width: 100%;
padding: 8px; padding: 8px;
cursor: pointer;
&:hover {
background-color: rgb(22, 77, 185);
}
} }

View File

@ -0,0 +1,5 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.5 10.72V19.5C19.5 21.5 19 22.5 16.5 22.5H7.5C5 22.5 4.5 21.5 4.5 19.5V10.72" stroke="#9FA8BC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5 2.5H19C21 2.5 22 3.5 22 5.5V7.5C22 9.5 21 10.5 19 10.5H5C3 10.5 2 9.5 2 7.5V5.5C2 3.5 3 2.5 5 2.5Z" stroke="#9FA8BC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.1799 14.5H13.8199" stroke="#9FA8BC" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@ -0,0 +1,3 @@
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 11L1 6L6 1" stroke="#9FA8BC" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 191 B

View File

@ -0,0 +1,3 @@
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 11L6 6L1 1" stroke="#9FA8BC" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 191 B

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 3C4.46957 3 3.96086 3.21071 3.58579 3.58579C3.21071 3.96086 3 4.46957 3 5V19C3 19.5304 3.21071 20.0391 3.58579 20.4142C3.96086 20.7893 4.46957 21 5 21H19C19.5304 21 20.0391 20.7893 20.4142 20.4142C20.7893 20.0391 21 19.5304 21 19V5C21 4.46957 20.7893 3.96086 20.4142 3.58579C20.0391 3.21071 19.5304 3 19 3H5ZM16.95 9.796C17.1376 9.60849 17.2431 9.35412 17.2432 9.08885C17.2433 8.82358 17.138 8.56914 16.9505 8.3815C16.763 8.19386 16.5086 8.08839 16.2434 8.0883C15.9781 8.0882 15.7236 8.19349 15.536 8.381L10.586 13.331L8.465 11.21C8.37216 11.1171 8.26192 11.0434 8.14059 10.9931C8.01926 10.9428 7.8892 10.9168 7.75785 10.9168C7.49258 10.9167 7.23814 11.022 7.0505 11.2095C6.86286 11.397 6.75739 11.6514 6.7573 11.9166C6.7572 12.1819 6.86249 12.4364 7.05 12.624L9.808 15.382C9.91015 15.4842 10.0314 15.5653 10.1649 15.6206C10.2984 15.6759 10.4415 15.7044 10.586 15.7044C10.7305 15.7044 10.8736 15.6759 11.0071 15.6206C11.1406 15.5653 11.2618 15.4842 11.364 15.382L16.95 9.796Z" fill="#246BFD"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0091 12.1536L15.3973 17.5357C15.6833 17.8213 16.0711 17.9818 16.4754 17.9818C16.8797 17.9818 17.2675 17.8213 17.5535 17.5357C17.8394 17.2501 18 16.8628 18 16.4589C18 16.055 17.8394 15.6677 17.5535 15.3821L12.1632 10L17.5524 4.61791C17.6939 4.4765 17.8062 4.30863 17.8827 4.12389C17.9593 3.93916 17.9987 3.74117 17.9986 3.54123C17.9986 3.34129 17.9591 3.14332 17.8825 2.95862C17.8058 2.77392 17.6935 2.60611 17.5519 2.46476C17.4104 2.32342 17.2423 2.21131 17.0574 2.13484C16.8724 2.05837 16.6742 2.01904 16.474 2.01909C16.2739 2.01914 16.0757 2.05856 15.8908 2.13512C15.7058 2.21167 15.5378 2.32386 15.3963 2.46527L10.0091 7.84736L4.62088 2.46527C4.48035 2.31981 4.31223 2.20375 4.12632 2.12388C3.94041 2.04401 3.74044 2.00192 3.53807 2.00006C3.3357 1.99821 3.13499 2.03664 2.94764 2.1131C2.7603 2.18955 2.59008 2.30251 2.44691 2.44539C2.30374 2.58826 2.19049 2.75818 2.11377 2.94524C2.03705 3.13229 1.99839 3.33274 2.00005 3.53488C2.00171 3.73702 2.04366 3.9368 2.12345 4.12258C2.20324 4.30835 2.31927 4.47639 2.46477 4.61689L7.85504 10L2.46579 15.3831C2.32028 15.5236 2.20426 15.6917 2.12447 15.8774C2.04468 16.0632 2.00273 16.263 2.00107 16.4651C1.9994 16.6673 2.03806 16.8677 2.11478 17.0548C2.19151 17.2418 2.30476 17.4117 2.44793 17.5546C2.5911 17.6975 2.76132 17.8104 2.94866 17.8869C3.136 17.9634 3.33671 18.0018 3.53908 17.9999C3.74145 17.9981 3.94142 17.956 4.12733 17.8761C4.31324 17.7963 4.48137 17.6802 4.62189 17.5347L10.0091 12.1536Z" fill="#9FA8BC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

78
src/assets/icons/index.ts Normal file
View File

@ -0,0 +1,78 @@
import addIcon from "./add.svg"
import calendarIcon from "./Calendar Mark.svg"
import docummentTextIcon from "./document-text.svg"
import folderIcon from "./Document.svg"
import editIcon from "./edit-2.svg"
import gridIcon from "./element-3-white.svg"
import gridBlueIcon from "./element-3.svg"
import profilePicture from "./Ellipse 2.svg"
import eyeIcon from "./eye.svg"
import eyeSlashIcon from "./eye-slash.svg"
import checkboxchedIcon from "./checked.svg"
import crossIcon from "./cross.svg"
import addBlueIcon from "./icon-add.svg"
import archivesIcon from "./archives.svg"
import notificationsIcon from "./notifications.svg"
import timerIcon from "./Line Duotone.svg"
import logo from "./Logo Private Docs@2x.svg"
import logoutRed from "./logout-red.svg"
import maximizeIcon from "./maximize-3.svg"
import menuIcon from "./Menu Dots.svg"
import messagesIcon from "./message.svg"
import homeIcon from "./NavItem.svg"
import arrowLeft from "./arrowLeft.svg"
import arrowRight from "./arrowLeft.svg"
import filesIcon from "./ph_files.svg"
import pdfIcon from "./prime_file-pdf.svg"
import wordIcon from "./prime_file-word.svg"
import userIcon from "./profile.svg"
import userGroup from "./profile-2user.svg"
import userGroupBlue from "./profile-2user-blue.svg"
import rectanagle from "./Rectangle.svg"
import searchIcon from "./Search.svg"
import settingsIcon from "./setting-2.svg"
import filterIcon from "./setting-3.svg"
import shareIcon from "./share.svg"
import starIcon from "./star.svg"
import arrowUp from "./Vector.svg"
export const icons = {
addIcon,
calendarIcon,
docummentTextIcon,
folderIcon,
editIcon,
gridIcon,
gridBlueIcon,
profilePicture,
eyeIcon,
eyeSlashIcon,
checkboxchedIcon,
crossIcon,
addBlueIcon,
archivesIcon,
notificationsIcon,
timerIcon,
logo,
logoutRed,
maximizeIcon,
menuIcon,
messagesIcon,
homeIcon,
arrowLeft,
arrowRight,
filesIcon,
pdfIcon,
wordIcon,
userIcon,
userGroup,
userGroupBlue,
rectanagle,
searchIcon,
settingsIcon,
filterIcon,
shareIcon,
starIcon,
arrowUp
}

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 9C11.59 9 11.25 8.71843 11.25 8.37888V5.62112C11.25 5.28157 11.59 5 12 5C12.41 5 12.75 5.28157 12.75 5.62112V8.37888C12.75 8.72671 12.41 9 12 9Z" fill="#9FA8BC"/>
<path d="M12.0161 19.6454C9.61036 19.6454 7.21398 19.2668 4.92949 18.5096C4.08097 18.2326 3.43758 17.6324 3.15785 16.8753C2.87811 16.1181 2.97136 15.2502 3.42825 14.493L4.61246 12.5355C4.87354 12.1015 5.10666 11.289 5.10666 10.7811V8.84208C5.10666 5.06555 8.20237 2 12.0161 2C15.8298 2 18.9255 5.06555 18.9255 8.84208V10.7811C18.9255 11.2797 19.1586 12.1015 19.4197 12.5355L20.6039 14.493C21.0421 15.2132 21.1167 16.072 20.8277 16.8568C20.5386 17.6417 19.9046 18.2419 19.1027 18.5096C16.8182 19.276 14.4218 19.6454 12.0161 19.6454ZM12.0161 3.39427C8.9763 3.39427 6.50532 5.84117 6.50532 8.85131V10.7904C6.50532 11.5383 6.20694 12.6186 5.81531 13.2557L4.63111 15.2225C4.38867 15.6195 4.33273 16.0443 4.47259 16.4136C4.61246 16.783 4.92949 17.06 5.37706 17.2077C9.66631 18.6204 14.3845 18.6204 18.6737 17.2077C19.0747 17.0784 19.3824 16.783 19.5223 16.3951C19.6714 16.0073 19.6248 15.5826 19.4104 15.2225L18.2262 13.265C17.8345 12.6278 17.5361 11.5475 17.5361 10.7996V8.86055C17.5268 5.84117 15.0558 3.39427 12.0161 3.39427Z" fill="#9FA8BC"/>
<path d="M12 22C10.951 22 9.92157 21.5937 9.17647 20.8919C8.43137 20.1902 8 19.2207 8 18.2327H9.47059C9.47059 18.8605 9.7451 19.47 10.2157 19.9132C10.6863 20.3564 11.3333 20.6149 12 20.6149C13.3922 20.6149 14.5294 19.5438 14.5294 18.2327H16C16 20.3102 14.2059 22 12 22Z" fill="#9FA8BC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -2,8 +2,8 @@
import { FloatingLabelInputProps } from '#/types'; import { FloatingLabelInputProps } from '#/types';
import React, { useState } from 'react'; import React, { useState } from 'react';
import Image from 'next/image';
import { icons } from '#/assets/icons';
export default function FloatingLabelInput({ export default function FloatingLabelInput({
label, label,
@ -47,19 +47,29 @@ export default function FloatingLabelInput({
defaultValue={defaultValue} defaultValue={defaultValue}
required required
/> />
{/* {showPasswordToggle && ( {showPasswordToggle && (
<button <button
type="button" type="button"
onClick={() => setShowPassword(!showPassword)} onClick={() => setShowPassword(!showPassword)}
className="btn-floating text-gray-500 hover:text-gray-700 focus:outline-none" className="btn-floating text-gray-500 hover:text-gray-700 focus:outline-none"
> >
{showPassword ? ( {showPassword ? (
<EyeClosedIcon size={20} /> <Image
src={icons.eyeSlashIcon}
width={20}
height={20}
alt=''
/>
) : ( ) : (
<EyeOpenIcon size={20} /> <Image
src={icons.eyeIcon}
width={20}
height={20}
alt=''
/>
)} )}
</button> </button>
)} */} )}
</div> </div>
); );
@ -81,7 +91,7 @@ export default function FloatingLabelInput({
}; };
return ( return (
<div className="relative mb-9"> <div className="relative">
<label <label
htmlFor={name} htmlFor={name}
className="input-label text-gray-400 text-sm" className="input-label text-gray-400 text-sm"

View File

@ -1,38 +1,73 @@
"use client";
import FloatingLabelInput from "../floatingLabelInput" import FloatingLabelInput from "../floatingLabelInput"
import { FormProps } from "#/types" import { FormProps } from "#/types"
import { FormEvent, useState } from "react"
export default function Form({ export default function Form({
fields, fields,
submit, submit,
className, className,
child, child,
title title,
schema
} : FormProps) { } : FormProps) {
const [errors, setErrors] = useState<Record<string, string>>({});
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
const formData = new FormData(e.currentTarget)
const data = Object.fromEntries(formData)
console.log("FORM DATA = ", data)
const result = schema.safeParse(data);
console.log("ZOD = ", result.error?.format())
if(!result.success) {
const formatedErrors = result.error.format() as Record<string, { _errors?: string[] }>;
const newErrors: Record<string, string> = {};
Object.keys(formatedErrors).forEach((field) => {
if (field !== "_errors" && formatedErrors[field]._errors?.length) {
newErrors[field] = formatedErrors[field]._errors[0];
}
});
setErrors(newErrors)
} else {
setErrors({})
}
}
return ( return (
<form className={className} onSubmit={submit}> <form className={className} onSubmit={handleSubmit}>
<div className="flex justify-center text-black"> <div className="flex justify-center text-black">
<p className="text-3xl font-bold">{title}</p> <p className="text-3xl font-bold">{title}</p>
</div> </div>
<div className="gap-2 mt-2"> <div className="flex flex-col gap-8 mt-2">
{ {
fields.map((item, index) => ( fields.map((item, index) => (
<FloatingLabelInput <div key={index}>
key={index} <FloatingLabelInput
label={item.label} label={item.label}
name={item.name} name={item.name}
type={item.type} type={item.type}
button={item.button} button={item.button}
defaultValue={item.defaultValue} defaultValue={item.defaultValue}
options={item.options} options={item.options}
placeholder={item.placeholder} placeholder={item.placeholder}
showPasswordToggle={item.showPasswordToggle} showPasswordToggle={item.showPasswordToggle}
/> />
<span className="text-red-500 text-xs mt-1">{errors[item.name]}</span>
</div>
)) ))
} }
</div>
{child} {child}
</div>
</form> </form>
) )

View File

@ -1,16 +1,16 @@
import { icons } from "#/assets/icons";
import Image from "next/image"; import Image from "next/image";
export default function Header() { export default function Header() {
return( return(
<div className="w-full bg-white shadow-md py-4"> <div className="w-full bg-white shadow-md py-4">
<div className="container mx-auto text-center flex items-center justify-center"> <div className="container mx-auto text-center flex items-center justify-center gap-2">
<Image <Image
src="/file.svg" src={icons.logo}
alt="Private Docs" alt="Private Docs"
width={100}
height={100}
className="text-red-500 h-auto" className="text-red-500 h-auto"
/> />
<p className="text-2xl font-bold text-black">Private Docs</p>
</div> </div>
</div> </div>
) )

View File

@ -1,5 +1,108 @@
export default function Table() { "use client";
import {
ColumnDef,
flexRender,
getCoreRowModel,
useReactTable,
getPaginationRowModel,
SortingState,
ColumnFiltersState,
getFilteredRowModel,
} from "@tanstack/react-table"
import { useState } from "react";
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]
data: TData[]
}
export default function Table<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const [rowSelection, setRowSelection] = useState({})
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(
[]
)
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
state: {
rowSelection,
columnFilters,
},
getFilteredRowModel: getFilteredRowModel(),
onRowSelectionChange: setRowSelection,
onColumnFiltersChange: setColumnFilters,
})
function clsx(arg0: string, arg1: { 'bg-gray-300': boolean; }): string | undefined {
throw new Error("Function not implemented.");
}
return( return(
<></> <div>
<div className="rounded-md border">
<table>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return(
<th key={header.id}>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
)
})}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.length ? (
table.getRowModel().rows.map((row) => (
<tr key={row.id} className={clsx('hover:bg-gray-300', { 'bg-gray-300': row.getIsSelected()})}>
{row.getVisibleCells().map((cell) => (
<td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))
)
: (
<tr>
<td>
Aucun résultats
</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<button
className="border bg-gray-200 shadow-xs hover:bg-gray-300 hover:text-black"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Précédent
</button>
<button
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Suivant
</button>
</div>
</div>
) )
} }

View File

@ -0,0 +1,6 @@
import { z } from "zod";
export const loginSchema = z.object({
email: z.string().email("Email invalide"),
password: z.string().min(8, "Le mot de passe doit contenir au moins 8 caractères")
});

View File

@ -1,4 +1,5 @@
import { FormEventHandler, ReactNode } from "react"; import { FormEventHandler, ReactNode } from "react";
import { ZodSchema } from "zod";
export interface FloatingLabelInputProps { export interface FloatingLabelInputProps {
label: string; label: string;
@ -16,5 +17,6 @@ export interface FormProps {
fields: FloatingLabelInputProps[], fields: FloatingLabelInputProps[],
submit: FormEventHandler<HTMLFormElement> | undefined, submit: FormEventHandler<HTMLFormElement> | undefined,
className: string, className: string,
child: ReactNode child: ReactNode,
schema: ZodSchema
} }