mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 04:51:51 +00:00
124 lines
3.3 KiB
TypeScript
124 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import type { Dispatch, FormEvent, SetStateAction } from "react";
|
|
import { useState } from "react";
|
|
|
|
import { SaveIcon } from "@/components/icons";
|
|
import { Button } from "@/components/shadcn";
|
|
import { useToast } from "@/components/shadcn";
|
|
import { Input } from "@/components/shadcn/input/input";
|
|
|
|
interface EditNameFormProps {
|
|
currentValue: string;
|
|
label: string;
|
|
successMessage: string;
|
|
placeholder?: string;
|
|
helperText?: string;
|
|
validate?: (value: string) => string | null;
|
|
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
|
onSave: (value: string) => Promise<unknown>;
|
|
}
|
|
|
|
export function EditNameForm({
|
|
currentValue,
|
|
label,
|
|
successMessage,
|
|
placeholder,
|
|
helperText,
|
|
validate,
|
|
setIsOpen,
|
|
onSave,
|
|
}: EditNameFormProps) {
|
|
const [value, setValue] = useState(currentValue);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const { toast } = useToast();
|
|
|
|
const handleSubmit = async (e: FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
const trimmed = value.trim();
|
|
if (validate) {
|
|
const validationError = validate(trimmed);
|
|
if (validationError) {
|
|
setError(validationError);
|
|
return;
|
|
}
|
|
}
|
|
|
|
setError(null);
|
|
setIsLoading(true);
|
|
|
|
const result = (await onSave(trimmed)) as Record<string, unknown>;
|
|
|
|
setIsLoading(false);
|
|
|
|
const errors = result?.errors as Array<{ detail: string }> | undefined;
|
|
|
|
if (errors && errors.length > 0) {
|
|
toast({
|
|
variant: "destructive",
|
|
title: "Oops! Something went wrong",
|
|
description: `${errors[0].detail}`,
|
|
});
|
|
} else if (result?.error) {
|
|
toast({
|
|
variant: "destructive",
|
|
title: "Oops! Something went wrong",
|
|
description: String(result.error),
|
|
});
|
|
} else {
|
|
toast({ title: "Success!", description: successMessage });
|
|
setIsOpen(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
|
|
<div className="text-md">
|
|
Current {label.toLowerCase()}:{" "}
|
|
<span className="font-bold">{currentValue || "—"}</span>
|
|
</div>
|
|
<div className="flex flex-col gap-2">
|
|
<label
|
|
htmlFor="edit-name-input"
|
|
className="text-text-neutral-primary text-sm font-medium"
|
|
>
|
|
{label}
|
|
</label>
|
|
<Input
|
|
id="edit-name-input"
|
|
value={value}
|
|
onChange={(e) => {
|
|
setValue(e.target.value);
|
|
if (error) setError(null);
|
|
}}
|
|
placeholder={placeholder ?? currentValue}
|
|
disabled={isLoading}
|
|
aria-invalid={!!error}
|
|
/>
|
|
{error && <p className="text-destructive text-xs">{error}</p>}
|
|
{helperText && !error && (
|
|
<p className="text-muted-foreground text-xs">{helperText}</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex w-full justify-end gap-4">
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="lg"
|
|
onClick={() => setIsOpen(false)}
|
|
disabled={isLoading}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button type="submit" size="lg" disabled={isLoading}>
|
|
{!isLoading && <SaveIcon size={24} />}
|
|
{isLoading ? "Loading" : "Save"}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|