chore: sync GovOPlaN module split state
This commit is contained in:
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user