"use client"; import { icons } from "lucide-react"; import { Icon } from "~/components/global"; import { LoadingButton } from "~/components/ui/button"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/components/ui/select"; import { Separator } from "~/components/ui/separator"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/components/ui/tooltip"; import { cn } from "~/lib/utils"; import { ConfigurationCategory, ConfigurationKeys, ConfigurationValue } from "~/types/schema"; export type ConfigInputs< T extends ConfigurationCategory = ConfigurationCategory, K extends ConfigurationKeys = ConfigurationKeys, > = ConfigInputProps | ConfigInputGroupProps | ConfigInputSeparatorProps; type ConfigInputProps< T extends ConfigurationCategory = ConfigurationCategory, K extends ConfigurationKeys = ConfigurationKeys, > = { inputKey: K; title: string; type: "text" | "password" | "number" | "select"; description?: string; required?: boolean; action?: { label: string; onClick: (e: React.MouseEvent) => void; loading: boolean; icon?: keyof typeof icons; }; value: ConfigurationValue; onValueChange: (key: K, value: any) => void; error?: string; onError?: (error: string) => void; validation?: (value: string) => | { success: boolean; message: string } | Promise<{ success: boolean; message: string; }>; readOnly?: boolean; minMax?: { min?: number; max?: number }; disabled?: boolean; placeholder?: string; }; type ConfigInputGroupProps< T extends ConfigurationCategory = ConfigurationCategory, K extends ConfigurationKeys = ConfigurationKeys, > = { inputKey: string; type: "group"; columns: number; children: (ConfigInputProps & { columnSpan?: number; })[]; }; type ConfigInputSeparatorProps = { inputKey: string; type: "separator"; }; export default function ConfigurationInput< T extends ConfigurationCategory = ConfigurationCategory, K extends ConfigurationKeys = ConfigurationKeys, >(props: ConfigInputProps | ConfigInputGroupProps | ConfigInputSeparatorProps) { const key = String(props.inputKey); return ( <> {props.type !== "separator" && props.type !== "group" && ( <> {...props} /> )} {props.type === "separator" && } {props.type === "group" && (
{props.children.map((child, index) => ( key={`${child.inputKey as string}@${index}`} columnSpan={child.columnSpan} {...child} /> ))}
)} ); } function Inputs< T extends ConfigurationCategory = ConfigurationCategory, K extends ConfigurationKeys = ConfigurationKeys, >( props: ConfigInputProps & { columnSpan?: number; }, ) { const key = String(props.inputKey); return (
{props.description && ( e.preventDefault()} className='cursor-default' >

{props.description}

)}
{props.type === "text" || props.type === "password" || props.type === "number" ? ( { if (props.error) { props.onError?.(""); } props.onValueChange(props.inputKey, e.target.value as ConfigurationValue); }} onBlur={async () => { try { props.onError?.(""); if (props.required && !(props.value as string).trim()) { throw new Error(`${props.title} is required.`); } if (props.validation) { const result = await props.validation(props.value as string); if (!result.success) throw new Error(result.message); } } catch (error) { const e = error as Error; props.onError?.(e.message); } }} /> ) : ( props.type === "select" && ( ) )}
{props.action && ( {props.action.icon && } {props.action.label} )}
{props.error}
); }