{error}
+ )} + {loading ? ( ++ Loading work items… +
+ ) : filteredIssues.length === 0 ? ( ++ {availableIssues.length === 0 + ? "No other work items in this project." + : "No matching work items."} +
+ ) : ( ++
{unsplashError}
)} @@ -219,10 +219,10 @@ export function CoverImageModal({ type="button" key={r.id} onClick={() => setSelectedUrl(r.url)} - className={`relative aspect-video rounded-[var(--radius-md)] overflow-hidden border-2 transition-colors ${ + className={`relative aspect-video rounded-(--radius-md) overflow-hidden border-2 transition-colors ${ selectedUrl === r.url - ? "border-[var(--brand-default)] ring-2 ring-[var(--brand-200)]" - : "border-transparent hover:border-[var(--border-strong)]" + ? "border-(--brand-default) ring-2 ring-(--brand-200)" + : "border-transparent hover:border-(--border-strong)" }`} >+
Drag & drop image here
+
File formats supported: .jpeg, .jpg, .png, .webp
{uploadError && ( -- {uploadError} -
+{uploadError}
)} )} diff --git a/ui/src/components/CreateModuleModal.tsx b/ui/src/components/CreateModuleModal.tsx new file mode 100644 index 0000000..0445589 --- /dev/null +++ b/ui/src/components/CreateModuleModal.tsx @@ -0,0 +1,542 @@ +import { useState, useEffect, useRef } from "react"; +import { Modal, Button, Input, Avatar } from "./ui"; +import { DateRangeModal } from "./workspace-views/DateRangeModal"; +import { getImageUrl } from "../lib/utils"; +import { moduleService } from "../services/moduleService"; +import { workspaceService } from "../services/workspaceService"; +import type { ModuleApiResponse } from "../api/types"; +import type { WorkspaceMemberApiResponse } from "../api/types"; + +const MODULE_STATUSES = [ + { id: "backlog", label: "Backlog" }, + { id: "planned", label: "Planned" }, + { id: "in_progress", label: "In Progress" }, + { id: "paused", label: "Paused" }, + { id: "completed", label: "Completed" }, + { id: "cancelled", label: "Cancelled" }, +] as const; + +function formatDateRangeDisplay( + start: string | null, + end: string | null, +): string { + if (!start && !end) return "Start date → End date"; + const fmt = (s: string) => + new Date(s).toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + }); + if (start && end) return `${fmt(start)} → ${fmt(end)}`; + return start ? fmt(start) : end ? fmt(end) : "Start date → End date"; +} + +export interface CreateModuleModalProps { + open: boolean; + onClose: () => void; + workspaceSlug: string; + projectId: string; + projectName: string; + onCreated?: (module: ModuleApiResponse) => void; +} + +export function CreateModuleModal({ + open, + onClose, + workspaceSlug, + projectId, + projectName, + onCreated, +}: CreateModuleModalProps) { + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); + const [startDate, setStartDate] = useState- {error} -
+{error}
)} {/* Actions */} -