107 lines
3.4 KiB
TypeScript
107 lines
3.4 KiB
TypeScript
// * Packages
|
|
import { EyeIcon, EyeOffIcon } from "lucide-react";
|
|
import { useState, useEffect, useRef } from "react";
|
|
import { usePage } from "@inertiajs/react";
|
|
// * Components shadcn
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Button } from "@/components/ui/button";
|
|
// * Other
|
|
import InputError from "@/back/Components/InputError";
|
|
import WordCounter from "@/back/Components/WordCounter";
|
|
import { cn } from "@/lib/utils";
|
|
import useTrans from "@/hooks/use-translations";
|
|
|
|
type SimpleStringProps = {
|
|
className?: string;
|
|
name: string;
|
|
label: string;
|
|
value?: string;
|
|
id?: string;
|
|
type?: string;
|
|
placeholder?: string;
|
|
wordCounter?: boolean;
|
|
required?: boolean;
|
|
disabled?: boolean;
|
|
pattern?: string;
|
|
checkVisibility?: boolean;
|
|
parentErrors?: Record<string, string>,
|
|
// eslint-disable-next-line no-unused-vars
|
|
setData: (name: string, value: string) => void;
|
|
};
|
|
|
|
export default function SimpleString({
|
|
className,
|
|
value = "",
|
|
name,
|
|
label,
|
|
id = name as string,
|
|
type = "text",
|
|
placeholder = "back.enter_text_here",
|
|
wordCounter = true,
|
|
required = true,
|
|
disabled = false,
|
|
pattern,
|
|
checkVisibility = false,
|
|
parentErrors = {},
|
|
setData,
|
|
}: SimpleStringProps) {
|
|
const [isVisible, setIsVisible] = useState(checkVisibility);
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
const { errors } = usePage().props;
|
|
const localErrors = parentErrors ?? errors;
|
|
|
|
useEffect(() => {
|
|
if (inputRef.current && inputRef.current.value !== value) {
|
|
inputRef.current.value = value;
|
|
}
|
|
}, [value]);
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"flex flex-col w-full justify-between items-start gap-1.5",
|
|
className,
|
|
)}
|
|
>
|
|
<Label htmlFor={name}>{label + (required ? " *" : "")}</Label>
|
|
{wordCounter && <WordCounter value={value} />}
|
|
<div className="flex w-full">
|
|
<Input
|
|
id={id}
|
|
name={name}
|
|
type={isVisible ? "text" : type}
|
|
placeholder={useTrans(placeholder)}
|
|
defaultValue={value}
|
|
ref={inputRef}
|
|
onChange={(e) => {
|
|
setData(name, e.target.value);
|
|
}}
|
|
required={required}
|
|
disabled={disabled}
|
|
className={cn(
|
|
type === "password" || checkVisibility
|
|
? "w-[calc(100%-40px-0.25rem)]"
|
|
: "w-full",
|
|
{ "border-destructive/50": localErrors[name] },
|
|
)}
|
|
pattern={pattern ?? undefined}
|
|
/>
|
|
{(type === "password" || checkVisibility) && (
|
|
<Button
|
|
className="ms-1"
|
|
type="button"
|
|
size="icon"
|
|
onClick={() => {
|
|
setIsVisible(!isVisible);
|
|
}}
|
|
>
|
|
<EyeOffIcon className={!isVisible ? "hidden " : ""} />
|
|
<EyeIcon className={isVisible ? "hidden" : ""} />
|
|
</Button>
|
|
)}
|
|
</div>
|
|
<InputError message={localErrors[name]} />
|
|
</div>
|
|
);
|
|
}
|