153 lines
4.4 KiB
TypeScript
153 lines
4.4 KiB
TypeScript
"use client";
|
|
|
|
import { useRouter } from "next/navigation";
|
|
import { useState } from "react";
|
|
|
|
type EstimateAction = "approve" | "decline" | "question";
|
|
|
|
type EstimateActionsProps = {
|
|
token: string;
|
|
};
|
|
|
|
type ActionResponse = {
|
|
message?: string;
|
|
};
|
|
|
|
const actionLabels: Record<EstimateAction, string> = {
|
|
approve: "Freigeben",
|
|
decline: "Ablehnen",
|
|
question: "Rückfrage senden",
|
|
};
|
|
|
|
async function readActionMessage(response: Response) {
|
|
try {
|
|
const body = await response.json() as ActionResponse;
|
|
return body.message || "Die Aktion konnte nicht abgeschlossen werden.";
|
|
} catch {
|
|
return "Die Aktion konnte nicht abgeschlossen werden.";
|
|
}
|
|
}
|
|
|
|
export function EstimateActions({ token }: EstimateActionsProps) {
|
|
const router = useRouter();
|
|
const [activeForm, setActiveForm] = useState<Exclude<EstimateAction, "approve"> | null>(null);
|
|
const [message, setMessage] = useState("");
|
|
const [pendingAction, setPendingAction] = useState<EstimateAction | null>(null);
|
|
const [feedback, setFeedback] = useState<{ type: "success" | "error"; text: string } | null>(null);
|
|
|
|
async function submitAction(action: EstimateAction, actionMessage = "") {
|
|
setPendingAction(action);
|
|
setFeedback(null);
|
|
|
|
try {
|
|
const response = await fetch(`/api/status/${encodeURIComponent(token)}/estimate/${action}`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({ message: actionMessage.trim() || null }),
|
|
});
|
|
const responseMessage = await readActionMessage(response);
|
|
|
|
if (!response.ok) {
|
|
setFeedback({ type: "error", text: responseMessage });
|
|
return;
|
|
}
|
|
|
|
setMessage("");
|
|
setActiveForm(null);
|
|
setFeedback({ type: "success", text: responseMessage });
|
|
router.refresh();
|
|
} catch {
|
|
setFeedback({
|
|
type: "error",
|
|
text: "Die Aktion konnte momentan nicht gesendet werden. Bitte versuchen Sie es erneut.",
|
|
});
|
|
} finally {
|
|
setPendingAction(null);
|
|
}
|
|
}
|
|
|
|
const isPending = pendingAction !== null;
|
|
|
|
return (
|
|
<div className="estimate-actions-panel">
|
|
<div className="estimate-action-buttons">
|
|
<button
|
|
className="button"
|
|
disabled={isPending}
|
|
type="button"
|
|
onClick={() => void submitAction("approve")}
|
|
>
|
|
{pendingAction === "approve" ? "Wird freigegeben..." : actionLabels.approve}
|
|
</button>
|
|
<button
|
|
className="button light"
|
|
disabled={isPending}
|
|
type="button"
|
|
onClick={() => {
|
|
setActiveForm("question");
|
|
setFeedback(null);
|
|
}}
|
|
>
|
|
Rückfrage
|
|
</button>
|
|
<button
|
|
className="button danger"
|
|
disabled={isPending}
|
|
type="button"
|
|
onClick={() => {
|
|
setActiveForm("decline");
|
|
setFeedback(null);
|
|
}}
|
|
>
|
|
Ablehnen
|
|
</button>
|
|
</div>
|
|
|
|
{activeForm && (
|
|
<form
|
|
className="estimate-action-form"
|
|
onSubmit={(event) => {
|
|
event.preventDefault();
|
|
void submitAction(activeForm, message);
|
|
}}
|
|
>
|
|
<label htmlFor={`estimate-${activeForm}-message`}>
|
|
{activeForm === "decline" ? "Nachricht zur Ablehnung" : "Ihre Rückfrage"}
|
|
</label>
|
|
<textarea
|
|
id={`estimate-${activeForm}-message`}
|
|
name="message"
|
|
rows={4}
|
|
value={message}
|
|
placeholder={activeForm === "decline" ? "Optionaler Hinweis für uns" : "Ihre Frage zum Kostenvoranschlag"}
|
|
onChange={(event) => setMessage(event.currentTarget.value)}
|
|
/>
|
|
<div className="estimate-form-actions">
|
|
<button className="button" disabled={isPending} type="submit">
|
|
{pendingAction === activeForm ? "Wird gesendet..." : actionLabels[activeForm]}
|
|
</button>
|
|
<button
|
|
className="button light"
|
|
disabled={isPending}
|
|
type="button"
|
|
onClick={() => {
|
|
setActiveForm(null);
|
|
setMessage("");
|
|
}}
|
|
>
|
|
Abbrechen
|
|
</button>
|
|
</div>
|
|
</form>
|
|
)}
|
|
|
|
{feedback && (
|
|
<p className={`estimate-feedback ${feedback.type === "error" ? "error" : "success"}`} role="status">
|
|
{feedback.text}
|
|
</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|