initial commit after split
This commit is contained in:
137
webui/src/features/campaigns/CampaignWorkspace.tsx
Normal file
137
webui/src/features/campaigns/CampaignWorkspace.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Navigate, Route, Routes, useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import type { ApiSettings, AuthInfo, CampaignWorkspaceSection } from "../../types";
|
||||
import SectionSidebar from "../../layout/SectionSidebar";
|
||||
import CampaignOverviewPage from "./CampaignOverviewPage";
|
||||
import CampaignFieldsPage from "./CampaignFieldsPage";
|
||||
import GlobalSettingsPage from "./GlobalSettingsPage";
|
||||
import RecipientDataPage from "./RecipientDataPage";
|
||||
import RecipientDetailsPage from "./RecipientDetailsPage";
|
||||
import TemplateDataPage from "./TemplateDataPage";
|
||||
import AttachmentsDataPage from "./AttachmentsDataPage";
|
||||
import MailSettingsPage from "./MailSettingsPage";
|
||||
import ReviewSendPage from "./ReviewSendPage";
|
||||
import CreateWizard from "./wizard/CreateWizard";
|
||||
import ReviewWizard from "./wizard/ReviewWizard";
|
||||
import SendWizard from "./wizard/SendWizard";
|
||||
import CampaignJsonView from "./CampaignJsonView";
|
||||
import CampaignReportPage from "./CampaignReportPage";
|
||||
import CampaignAuditPage from "./CampaignAuditPage";
|
||||
import { CampaignUnsavedChangesProvider, useCampaignUnsavedChanges } from "./context/UnsavedChangesContext";
|
||||
|
||||
const sectionPaths: Record<CampaignWorkspaceSection, string> = {
|
||||
overview: "",
|
||||
campaign: "recipients",
|
||||
"global-settings": "global-settings",
|
||||
fields: "fields",
|
||||
recipients: "recipients",
|
||||
"recipient-data": "recipient-data",
|
||||
template: "template",
|
||||
files: "files",
|
||||
"mail-settings": "mail-settings",
|
||||
review: "review",
|
||||
report: "report",
|
||||
audit: "audit",
|
||||
json: "json"
|
||||
};
|
||||
|
||||
export default function CampaignWorkspace({ settings, auth }: { settings: ApiSettings; auth: AuthInfo }) {
|
||||
return (
|
||||
<CampaignUnsavedChangesProvider>
|
||||
<CampaignWorkspaceInner settings={settings} auth={auth} />
|
||||
</CampaignUnsavedChangesProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function CampaignWorkspaceInner({ settings, auth }: { settings: ApiSettings; auth: AuthInfo }) {
|
||||
const { campaignId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { requestNavigation } = useCampaignUnsavedChanges();
|
||||
const location = useLocation();
|
||||
const active = sectionFromPath(location.pathname);
|
||||
const urlVersionId = new URLSearchParams(location.search).get("version");
|
||||
const [selectedVersionId, setSelectedVersionId] = useState<string | null>(urlVersionId);
|
||||
|
||||
useEffect(() => {
|
||||
if (urlVersionId) setSelectedVersionId(urlVersionId);
|
||||
}, [urlVersionId]);
|
||||
|
||||
// Relative links inside the workspace historically dropped ?version=. Keep
|
||||
// the selected version stable for the lifetime of this campaign workspace,
|
||||
// while still opening the latest version on a fresh campaign entry.
|
||||
useEffect(() => {
|
||||
if (urlVersionId || !selectedVersionId) return;
|
||||
const params = new URLSearchParams(location.search);
|
||||
params.set("version", selectedVersionId);
|
||||
navigate(`${location.pathname}?${params.toString()}`, { replace: true });
|
||||
}, [location.pathname, location.search, navigate, selectedVersionId, urlVersionId]);
|
||||
|
||||
function select(section: CampaignWorkspaceSection) {
|
||||
const path = sectionPaths[section];
|
||||
const pathname = path ? `/campaigns/${campaignId}/${path}` : `/campaigns/${campaignId}`;
|
||||
const params = new URLSearchParams(location.search);
|
||||
const versionId = urlVersionId ?? selectedVersionId;
|
||||
if (versionId) params.set("version", versionId);
|
||||
const query = params.toString();
|
||||
const target = query ? `${pathname}?${query}` : pathname;
|
||||
if (`${location.pathname}${location.search}` === target) return;
|
||||
requestNavigation(() => navigate(target));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="workspace">
|
||||
<SectionSidebar active={active} onSelect={select} />
|
||||
<section className="workspace-content">
|
||||
<Routes>
|
||||
<Route index element={<CampaignOverviewPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="data" element={<Navigate to="../recipients" replace />} />
|
||||
<Route path="fields" element={<CampaignFieldsPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="recipients" element={<RecipientDataPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="recipient-data" element={<RecipientDetailsPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="template" element={<TemplateDataPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="files" element={<AttachmentsDataPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="attachments" element={<Navigate to="../files" replace />} />
|
||||
<Route path="mail-settings" element={<MailSettingsPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="server-settings" element={<Navigate to="../mail-settings" replace />} />
|
||||
<Route path="global-settings" element={<GlobalSettingsPage settings={settings} auth={auth} campaignId={campaignId || ""} />} />
|
||||
<Route path="review" element={<ReviewSendPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="send" element={<Navigate to="../review" replace />} />
|
||||
<Route path="report" element={<CampaignReportPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="reports" element={<Navigate to="../report" replace />} />
|
||||
<Route path="audit" element={<CampaignAuditPage settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="json" element={<CampaignJsonView settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="wizard/create" element={<CreateWizard settings={settings} campaignId={campaignId || ""} />} />
|
||||
<Route path="wizard/review" element={<ReviewWizard />} />
|
||||
<Route path="wizard/send" element={<SendWizard />} />
|
||||
<Route path="create" element={<Navigate to="../wizard/create" replace />} />
|
||||
<Route path="campaign" element={<Navigate to="../data" replace />} />
|
||||
<Route path="mail" element={<Navigate to="../mail-settings" replace />} />
|
||||
<Route path="settings" element={<Navigate to="../global-settings" replace />} />
|
||||
<Route path="Review" element={<Navigate to="../" replace />} />
|
||||
<Route path="*" element={<Navigate to="../" replace />} />
|
||||
</Routes>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function sectionFromPath(pathname: string): CampaignWorkspaceSection {
|
||||
const segments = pathname.split("/").filter(Boolean);
|
||||
const section = segments[2];
|
||||
|
||||
if (!section || section === "wizard" || section === "create") return "overview";
|
||||
if (section === "data" || section === "campaign") return "recipients";
|
||||
if (section === "global-settings" || section === "settings") return "global-settings";
|
||||
if (section === "fields") return "fields";
|
||||
if (section === "recipients") return "recipients";
|
||||
if (section === "recipient-data" || section === "recipient-details") return "recipient-data";
|
||||
if (section === "template") return "template";
|
||||
if (section === "files" || section === "attachments") return "files";
|
||||
if (section === "mail-settings" || section === "server-settings" || section === "mail") return "mail-settings";
|
||||
if (section === "review") return "review";
|
||||
if (section === "send") return "review";
|
||||
if (section === "report" || section === "reports") return "report";
|
||||
if (section === "audit") return "audit";
|
||||
if (section === "json") return "json";
|
||||
return "overview";
|
||||
}
|
||||
Reference in New Issue
Block a user