login form created
This commit is contained in:
33
frontend/src/lib/formSutff/CheckBox.Field.tsx
Normal file
33
frontend/src/lib/formSutff/CheckBox.Field.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Label } from "@radix-ui/react-label";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { useFieldContext } from ".";
|
||||
import { FieldErrors } from "./Errors.Field";
|
||||
|
||||
type CheckboxFieldProps = {
|
||||
label: string;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
export const CheckboxField = ({ label }: CheckboxFieldProps) => {
|
||||
const field = useFieldContext<boolean>();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Label htmlFor={field.name}>
|
||||
<span>{label}</span>
|
||||
</Label>
|
||||
|
||||
<Checkbox
|
||||
id={field.name}
|
||||
checked={field.state.value}
|
||||
onCheckedChange={(checked) => {
|
||||
field.handleChange(checked === true);
|
||||
}}
|
||||
onBlur={field.handleBlur}
|
||||
/>
|
||||
</div>
|
||||
<FieldErrors meta={field.state.meta} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
18
frontend/src/lib/formSutff/Errors.Field.tsx
Normal file
18
frontend/src/lib/formSutff/Errors.Field.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { AnyFieldMeta } from "@tanstack/react-form";
|
||||
|
||||
type FieldErrorsProps = {
|
||||
meta: AnyFieldMeta;
|
||||
};
|
||||
|
||||
export const FieldErrors = ({ meta }: FieldErrorsProps) => {
|
||||
if (!meta.isTouched) return null;
|
||||
|
||||
return meta.errors.map((error) => (
|
||||
<p
|
||||
key={`${error.message}-${error.code ?? "err"}`}
|
||||
className="text-sm font-medium text-destructive"
|
||||
>
|
||||
{error.message}
|
||||
</p>
|
||||
));
|
||||
};
|
||||
37
frontend/src/lib/formSutff/Input.Field.tsx
Normal file
37
frontend/src/lib/formSutff/Input.Field.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useFieldContext } from ".";
|
||||
import { FieldErrors } from "./Errors.Field";
|
||||
|
||||
type InputFieldProps = {
|
||||
label: string;
|
||||
inputType: string;
|
||||
required: boolean;
|
||||
};
|
||||
|
||||
const autoCompleteMap: Record<string, string> = {
|
||||
email: "email",
|
||||
password: "current-password",
|
||||
text: "off",
|
||||
username: "username",
|
||||
};
|
||||
|
||||
export const InputField = ({ label, inputType, required }: InputFieldProps) => {
|
||||
const field = useFieldContext<any>();
|
||||
|
||||
return (
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor={field.name}>{label}</Label>
|
||||
<Input
|
||||
id={field.name}
|
||||
autoComplete={autoCompleteMap[inputType] ?? "off"}
|
||||
value={field.state.value}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
onBlur={field.handleBlur}
|
||||
type={inputType}
|
||||
required={required}
|
||||
/>
|
||||
<FieldErrors meta={field.state.meta} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
49
frontend/src/lib/formSutff/InputPassword.Field.tsx
Normal file
49
frontend/src/lib/formSutff/InputPassword.Field.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { Eye, EyeOff } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useFieldContext } from ".";
|
||||
import { FieldErrors } from "./Errors.Field";
|
||||
|
||||
type PasswordInputProps = {
|
||||
label: string;
|
||||
required?: boolean;
|
||||
};
|
||||
|
||||
export const InputPasswordField = ({
|
||||
label,
|
||||
required = false,
|
||||
}: PasswordInputProps) => {
|
||||
const field = useFieldContext<any>();
|
||||
const [show, setShow] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="grid gap-3 mt-2">
|
||||
<Label htmlFor={field.name}>{label}</Label>
|
||||
<div className="relative">
|
||||
<Input
|
||||
id={field.name}
|
||||
type={show ? "text" : "password"}
|
||||
autoComplete="current-password"
|
||||
value={field.state.value}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
onBlur={field.handleBlur}
|
||||
required={required}
|
||||
className="pr-10"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setShow((p) => !p)}
|
||||
className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7"
|
||||
tabIndex={-1}
|
||||
>
|
||||
{show ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
|
||||
</Button>
|
||||
</div>
|
||||
<FieldErrors meta={field.state.meta} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
24
frontend/src/lib/formSutff/SubmitButton.tsx
Normal file
24
frontend/src/lib/formSutff/SubmitButton.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { useStore } from "@tanstack/react-form";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useFormContext } from ".";
|
||||
|
||||
type SubmitButtonProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export const SubmitButton = ({ children }: SubmitButtonProps) => {
|
||||
const form = useFormContext();
|
||||
|
||||
const [isSubmitting] = useStore(form.store, (state) => [
|
||||
state.isSubmitting,
|
||||
state.canSubmit,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
{children}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
23
frontend/src/lib/formSutff/index.tsx
Normal file
23
frontend/src/lib/formSutff/index.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { createFormHook, createFormHookContexts } from "@tanstack/react-form";
|
||||
import { CheckboxField } from "./CheckBox.Field";
|
||||
import { InputField } from "./Input.Field";
|
||||
import { InputPasswordField } from "./InputPassword.Field";
|
||||
import { SubmitButton } from "./SubmitButton";
|
||||
|
||||
export const { fieldContext, useFieldContext, formContext, useFormContext } =
|
||||
createFormHookContexts();
|
||||
|
||||
export const { useAppForm } = createFormHook({
|
||||
fieldComponents: {
|
||||
InputField,
|
||||
InputPasswordField,
|
||||
//SelectField,
|
||||
CheckboxField,
|
||||
//DateField,
|
||||
//TextArea,
|
||||
//Searchable,
|
||||
},
|
||||
formComponents: { SubmitButton },
|
||||
fieldContext,
|
||||
formContext,
|
||||
});
|
||||
Reference in New Issue
Block a user