fix: persist service media uploads
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Fragment, useEffect, useMemo, useState, type ReactNode } from "react";
|
||||
import { Fragment, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
||||
import {
|
||||
closestCenter,
|
||||
DndContext,
|
||||
@@ -1965,6 +1965,9 @@ function ServiceContentModal({
|
||||
onDelete: () => void;
|
||||
}) {
|
||||
const [draft, setDraft] = useState<Service>(service);
|
||||
const draftRef = useRef<Service>(service);
|
||||
const serviceIdRef = useRef(service.id);
|
||||
const hasUnsavedDraftRef = useRef(false);
|
||||
const [mediaPreviewUrls, setMediaPreviewUrls] = useState<{ cover: string | null; ambient: string | null }>({
|
||||
cover: service.coverImageUrl ?? null,
|
||||
ambient: service.ambientVideoUrl ?? null,
|
||||
@@ -1976,6 +1979,15 @@ function ServiceContentModal({
|
||||
const [deleteOpen, setDeleteOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const isAnotherService = service.id !== serviceIdRef.current;
|
||||
|
||||
if (!isAnotherService && hasUnsavedDraftRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
serviceIdRef.current = service.id;
|
||||
hasUnsavedDraftRef.current = false;
|
||||
draftRef.current = service;
|
||||
setDraft(service);
|
||||
setMediaPreviewUrls({
|
||||
cover: service.coverImageUrl ?? null,
|
||||
@@ -1997,8 +2009,15 @@ function ServiceContentModal({
|
||||
};
|
||||
}, [mediaPreviewUrls]);
|
||||
|
||||
function patchDraft(patch: Partial<Service>, options: { markUnsaved?: boolean } = {}) {
|
||||
const nextDraft = { ...draftRef.current, ...patch };
|
||||
hasUnsavedDraftRef.current = options.markUnsaved ?? true;
|
||||
draftRef.current = nextDraft;
|
||||
setDraft(nextDraft);
|
||||
}
|
||||
|
||||
function update<K extends keyof Service>(key: K, value: Service[K]) {
|
||||
setDraft((current) => ({ ...current, [key]: value }));
|
||||
patchDraft({ [key]: value } as Partial<Service>);
|
||||
}
|
||||
|
||||
function updateMediaPreview(slot: "cover" | "ambient", previewUrl: string | null) {
|
||||
@@ -2026,19 +2045,24 @@ function ServiceContentModal({
|
||||
const mediaKind = mediaKindFromFile(file);
|
||||
|
||||
if (slot === "cover") {
|
||||
update("coverImageUrl", storedFile.url);
|
||||
update("coverMediaKind", mediaKind);
|
||||
update("coverMediaSource", "file");
|
||||
update("coverMediaFileName", storedFile.fileName);
|
||||
patchDraft({
|
||||
coverImageUrl: storedFile.url,
|
||||
coverMediaKind: mediaKind,
|
||||
coverMediaSource: "file",
|
||||
coverMediaFileName: storedFile.fileName,
|
||||
});
|
||||
} else {
|
||||
update("ambientVideoUrl", storedFile.url);
|
||||
update("ambientMediaKind", mediaKind);
|
||||
update("ambientMediaSource", "file");
|
||||
update("ambientMediaFileName", storedFile.fileName);
|
||||
patchDraft({
|
||||
ambientVideoUrl: storedFile.url,
|
||||
ambientMediaKind: mediaKind,
|
||||
ambientMediaSource: "file",
|
||||
ambientMediaFileName: storedFile.fileName,
|
||||
});
|
||||
}
|
||||
updateMediaPreview(slot, storedFile.url);
|
||||
} catch (error) {
|
||||
setStorageError(error instanceof Error ? error.message : "Не удалось сохранить файл в storage");
|
||||
updateMediaPreview(slot, slot === "cover" ? (draft.coverImageUrl ?? null) : (draft.ambientVideoUrl ?? null));
|
||||
updateMediaPreview(slot, slot === "cover" ? (draftRef.current.coverImageUrl ?? null) : (draftRef.current.ambientVideoUrl ?? null));
|
||||
} finally {
|
||||
setUploadingSlot(null);
|
||||
}
|
||||
@@ -2048,26 +2072,29 @@ function ServiceContentModal({
|
||||
setSaveError(null);
|
||||
setIsSaving(true);
|
||||
|
||||
const currentDraft = draftRef.current;
|
||||
const result = await onSave({
|
||||
title: draft.title,
|
||||
subtitle: draft.subtitle,
|
||||
description: draft.description,
|
||||
fullDescription: draft.fullDescription,
|
||||
url: draft.url,
|
||||
launchUrl: draft.launchUrl,
|
||||
coverImageUrl: draft.coverImageUrl,
|
||||
coverMediaKind: draft.coverMediaKind,
|
||||
coverMediaSource: draft.coverMediaSource,
|
||||
coverMediaFileName: draft.coverMediaFileName,
|
||||
ambientVideoUrl: draft.ambientVideoUrl,
|
||||
ambientMediaKind: draft.ambientMediaKind,
|
||||
ambientMediaSource: draft.ambientMediaSource,
|
||||
ambientMediaFileName: draft.ambientMediaFileName,
|
||||
title: currentDraft.title,
|
||||
subtitle: currentDraft.subtitle,
|
||||
description: currentDraft.description,
|
||||
fullDescription: currentDraft.fullDescription,
|
||||
url: currentDraft.url,
|
||||
launchUrl: currentDraft.launchUrl,
|
||||
coverImageUrl: currentDraft.coverImageUrl,
|
||||
coverMediaKind: currentDraft.coverMediaKind,
|
||||
coverMediaSource: currentDraft.coverMediaSource,
|
||||
coverMediaFileName: currentDraft.coverMediaFileName,
|
||||
ambientVideoUrl: currentDraft.ambientVideoUrl,
|
||||
ambientMediaKind: currentDraft.ambientMediaKind,
|
||||
ambientMediaSource: currentDraft.ambientMediaSource,
|
||||
ambientMediaFileName: currentDraft.ambientMediaFileName,
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
setSaveError(result.message);
|
||||
setIsSaving(false);
|
||||
} else {
|
||||
hasUnsavedDraftRef.current = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2111,7 +2138,7 @@ function ServiceContentModal({
|
||||
</span>
|
||||
<input
|
||||
value={getServiceLaunchLink(draft)}
|
||||
onChange={(event) => setDraft((current) => ({ ...current, ...createServiceLaunchLinkPatch(event.target.value) }))}
|
||||
onChange={(event) => patchDraft(createServiceLaunchLinkPatch(event.target.value))}
|
||||
/>
|
||||
</label>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user