chore: sync GovOPlaN module split state

This commit is contained in:
2026-07-10 12:51:18 +02:00
parent 57f6066bf7
commit 52e6ed49c5
66 changed files with 8868 additions and 4072 deletions

View File

@@ -1,8 +1,10 @@
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useSearchParams } from "react-router-dom";
import { useDeltaWatermarks } from "@govoplan/core-webui";
import type { ApiSettings } from "../../../types";
import {
getCampaignWorkspace
getCampaignWorkspaceDelta,
type CampaignWorkspaceDeltaResponse
} from "../../../api/campaigns";
import type { CampaignWorkspaceData } from "../utils/campaignView";
@@ -34,6 +36,21 @@ export function useCampaignWorkspaceData(
const [data, setData] = useState<CampaignWorkspaceData>(initialData);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const dataRef = useRef<CampaignWorkspaceData>(initialData);
const { getDeltaWatermark, setDeltaWatermark, resetDeltaWatermark } = useDeltaWatermarks();
const queryKey = useMemo(
() => JSON.stringify({
campaignId,
selectedVersionId,
includeCurrentVersion,
includeSummary,
includeVersions,
apiBaseUrl: settings.apiBaseUrl,
apiKey: settings.apiKey,
accessToken: settings.accessToken
}),
[campaignId, selectedVersionId, includeCurrentVersion, includeSummary, includeVersions, settings.apiBaseUrl, settings.apiKey, settings.accessToken]
);
const reload = useCallback(async () => {
if (!campaignId) return;
@@ -41,26 +58,39 @@ export function useCampaignWorkspaceData(
setError("");
try {
const shouldLoadVersions = includeCurrentVersion || includeVersions;
const response = await getCampaignWorkspace(settings, campaignId, {
versionId: selectedVersionId,
includeCurrentVersion,
includeSummary,
includeVersions: shouldLoadVersions,
});
setData({
campaign: response.campaign,
versions: response.versions,
currentVersion: response.current_version,
summary: response.summary
});
let nextWatermark = getDeltaWatermark(queryKey);
let merged: CampaignWorkspaceData = dataRef.current;
let hasMore = false;
do {
const response = await getCampaignWorkspaceDelta(settings, campaignId, {
versionId: selectedVersionId,
includeCurrentVersion,
includeSummary,
includeVersions: shouldLoadVersions,
since: nextWatermark,
});
merged = mergeWorkspaceDelta(merged, response);
nextWatermark = response.watermark ?? null;
hasMore = response.has_more;
} while (hasMore);
setDeltaWatermark(queryKey, nextWatermark);
dataRef.current = merged;
setData(merged);
} catch (err) {
dataRef.current = initialData;
setData(initialData);
resetDeltaWatermark(queryKey);
setError(err instanceof Error ? err.message : String(err));
} finally {
setLoading(false);
}
}, [settings, campaignId, includeCurrentVersion, includeSummary, includeVersions, selectedVersionId]);
}, [settings, campaignId, includeCurrentVersion, includeSummary, includeVersions, selectedVersionId, queryKey, getDeltaWatermark, setDeltaWatermark, resetDeltaWatermark]);
useEffect(() => {
resetDeltaWatermark(queryKey);
dataRef.current = initialData;
setData(initialData);
}, [queryKey, resetDeltaWatermark]);
useEffect(() => {
reload();
@@ -68,3 +98,34 @@ export function useCampaignWorkspaceData(
return { data, loading, error, reload, setError };
}
function mergeWorkspaceDelta(current: CampaignWorkspaceData, response: CampaignWorkspaceDeltaResponse): CampaignWorkspaceData {
if (response.full) {
return {
campaign: response.campaign,
versions: response.versions,
currentVersion: response.current_version,
summary: response.summary
};
}
const deletedVersionIds = new Set(
response.deleted
.filter((item) => item.resource_type === "campaign_version")
.map((item) => item.id)
);
const versionMap = new Map(current.versions.map((version) => [version.id, version]));
for (const version of response.versions) {
versionMap.set(version.id, version);
}
for (const versionId of deletedVersionIds) {
versionMap.delete(versionId);
}
const currentVersionDeleted = current.currentVersion ? deletedVersionIds.has(current.currentVersion.id) : false;
return {
campaign: response.campaign ?? current.campaign,
versions: Array.from(versionMap.values()).sort((left, right) => (right.version_number ?? 0) - (left.version_number ?? 0)),
currentVersion: response.current_version ?? (currentVersionDeleted ? null : current.currentVersion),
summary: response.summary ?? current.summary
};
}