fix(offers,invoices): per-button save loading state (only the clicked button spins)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-09 20:41:25 +02:00
parent c270cb22e9
commit 313d9218c1
2 changed files with 22 additions and 10 deletions

View File

@@ -554,6 +554,10 @@ export default function OfferDetail() {
const loading = isEdit && offerQuery.isLoading;
const [saving, setSaving] = useState(false);
// Which save action is in flight ("draft" | LIVE_STATUS | "save"), so only the
// clicked button shows its spinner — `saving` still disables all of them to
// prevent a concurrent double-submit.
const [savingAction, setSavingAction] = useState<string | null>(null);
const [errors, setErrors] = useState<Record<string, string | undefined>>({});
const [form, setForm] = useState<OfferForm>(emptyForm);
const [items, setItems] = useState<OfferItem[]>(() => [emptyItem()]);
@@ -807,6 +811,7 @@ export default function OfferDetail() {
if (Object.keys(newErrors).length > 0) return;
setSaving(true);
setSavingAction(targetStatus ?? "save");
try {
const url = isEdit ? `${API_BASE}/offers/${id}` : `${API_BASE}/offers`;
const payload: any = {
@@ -883,6 +888,7 @@ export default function OfferDetail() {
alert.error("Chyba připojení");
} finally {
setSaving(false);
setSavingAction(null);
}
};
@@ -1136,7 +1142,7 @@ export default function OfferDetail() {
onClick={() => handleSave("draft")}
disabled={saving}
>
{saving ? (
{savingAction === "draft" ? (
<CircularProgress size={16} color="inherit" />
) : (
"Uložit koncept"
@@ -1146,7 +1152,7 @@ export default function OfferDetail() {
onClick={() => handleSave(LIVE_STATUS)}
disabled={saving}
>
{saving ? (
{savingAction === LIVE_STATUS ? (
<>
<CircularProgress
size={16}
@@ -1171,7 +1177,7 @@ export default function OfferDetail() {
onClick={() => handleSave("draft")}
disabled={saving}
>
{saving ? (
{savingAction === "draft" ? (
<CircularProgress size={16} color="inherit" />
) : (
"Uložit koncept"
@@ -1182,7 +1188,7 @@ export default function OfferDetail() {
onClick={() => handleSave(LIVE_STATUS)}
disabled={saving}
>
{saving ? (
{savingAction === LIVE_STATUS ? (
<>
<CircularProgress
size={16}
@@ -1202,7 +1208,7 @@ export default function OfferDetail() {
{/* ── Edit mode, live (non-draft) offer — unchanged plain save ── */}
{isEdit && !readOnly && offerStatus !== "draft" && (
<Button onClick={() => handleSave()} disabled={saving}>
{saving ? (
{savingAction === "save" ? (
<>
<CircularProgress
size={16}