mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-25 12:05:06 +02:00
#5313 landed the backend start_date/due_date fields + types but deliberately shipped no UI. Wire up the two editor surfaces users expect: - ProjectStartDatePicker / ProjectDueDatePicker mirror the issue pickers (same calendar-day contract, clear idiom, shared @multica/core/issues/date helpers) but are typed to UpdateProjectRequest and scoped to the "projects" i18n namespace. One component serves both surfaces via a custom trigger. - Create-project modal: two date pills; values flow into the create payload and the persisted draft (draft-store gains startDate/dueDate). - Project sidebar (project-detail): two PropRows after Lead, wired to the update mutation, with clear support (send null). - i18n: prop_start_date / prop_due_date / clear_date across en/zh-Hans/ja/ko, reusing the existing issue date wording. Tests: picker display + clear behavior (real popover), and the create modal renders both pills. typecheck + lint + i18n parity pass. Part of #5227 Co-authored-by: multica-agent <github@multica.ai>
60 lines
1.6 KiB
TypeScript
60 lines
1.6 KiB
TypeScript
import { create } from "zustand";
|
|
import { createJSONStorage, persist } from "zustand/middleware";
|
|
import type { ProjectStatus, ProjectPriority } from "../types";
|
|
import { createWorkspaceAwareStorage, registerForWorkspaceRehydration } from "../platform/workspace-storage";
|
|
import { defaultStorage } from "../platform/storage";
|
|
|
|
interface ProjectDraft {
|
|
title: string;
|
|
description: string;
|
|
status: ProjectStatus;
|
|
priority: ProjectPriority;
|
|
leadType?: "member" | "agent";
|
|
leadId?: string;
|
|
icon?: string;
|
|
// Calendar days ("YYYY-MM-DD"); empty/undefined means unset.
|
|
startDate?: string;
|
|
dueDate?: string;
|
|
}
|
|
|
|
const EMPTY_DRAFT: ProjectDraft = {
|
|
title: "",
|
|
description: "",
|
|
status: "planned",
|
|
priority: "none",
|
|
leadType: undefined,
|
|
leadId: undefined,
|
|
icon: undefined,
|
|
startDate: undefined,
|
|
dueDate: undefined,
|
|
};
|
|
|
|
interface ProjectDraftStore {
|
|
draft: ProjectDraft;
|
|
setDraft: (patch: Partial<ProjectDraft>) => void;
|
|
clearDraft: () => void;
|
|
hasDraft: () => boolean;
|
|
}
|
|
|
|
export const useProjectDraftStore = create<ProjectDraftStore>()(
|
|
persist(
|
|
(set, get) => ({
|
|
draft: { ...EMPTY_DRAFT },
|
|
setDraft: (patch) =>
|
|
set((s) => ({ draft: { ...s.draft, ...patch } })),
|
|
clearDraft: () =>
|
|
set({ draft: { ...EMPTY_DRAFT } }),
|
|
hasDraft: () => {
|
|
const { draft } = get();
|
|
return !!(draft.title || draft.description);
|
|
},
|
|
}),
|
|
{
|
|
name: "multica_project_draft",
|
|
storage: createJSONStorage(() => createWorkspaceAwareStorage(defaultStorage)),
|
|
},
|
|
),
|
|
);
|
|
|
|
registerForWorkspaceRehydration(() => useProjectDraftStore.persist.rehydrate());
|