feat: make responsiblePerson required on project creation/edit
- Zod schema: responsiblePerson now min(1) required, no longer optional - ProjectModal: required indicator (*), HTML required attribute, no undefined fallback - ProjectWizard: same fix for create flow - Existing projects with null responsiblePerson still work (DB allows null) - Validation enforced at API boundary on new creates/updates Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -204,7 +204,7 @@ export function ProjectModal({ project, onClose }: ProjectModalProps) {
|
|||||||
startDate: new Date(form.startDate),
|
startDate: new Date(form.startDate),
|
||||||
endDate: new Date(form.endDate),
|
endDate: new Date(form.endDate),
|
||||||
status: form.status as unknown as ProjectStatus,
|
status: form.status as unknown as ProjectStatus,
|
||||||
responsiblePerson: form.responsiblePerson.trim() || undefined,
|
responsiblePerson: form.responsiblePerson.trim(),
|
||||||
...(form.color ? { color: form.color } : {}),
|
...(form.color ? { color: form.color } : {}),
|
||||||
...(form.utilizationCategoryId ? { utilizationCategoryId: form.utilizationCategoryId } : {}),
|
...(form.utilizationCategoryId ? { utilizationCategoryId: form.utilizationCategoryId } : {}),
|
||||||
...(form.clientId ? { clientId: form.clientId } : {}),
|
...(form.clientId ? { clientId: form.clientId } : {}),
|
||||||
@@ -223,7 +223,7 @@ export function ProjectModal({ project, onClose }: ProjectModalProps) {
|
|||||||
status: form.status as unknown as ProjectStatus,
|
status: form.status as unknown as ProjectStatus,
|
||||||
staffingReqs: [],
|
staffingReqs: [],
|
||||||
dynamicFields: {},
|
dynamicFields: {},
|
||||||
responsiblePerson: form.responsiblePerson.trim() || undefined,
|
responsiblePerson: form.responsiblePerson.trim(),
|
||||||
...(form.color ? { color: form.color } : {}),
|
...(form.color ? { color: form.color } : {}),
|
||||||
...(form.utilizationCategoryId ? { utilizationCategoryId: form.utilizationCategoryId } : {}),
|
...(form.utilizationCategoryId ? { utilizationCategoryId: form.utilizationCategoryId } : {}),
|
||||||
...(form.clientId ? { clientId: form.clientId } : {}),
|
...(form.clientId ? { clientId: form.clientId } : {}),
|
||||||
@@ -521,8 +521,8 @@ export function ProjectModal({ project, onClose }: ProjectModalProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className={labelClass} htmlFor="responsiblePerson">
|
<label className={labelClass} htmlFor="responsiblePerson">
|
||||||
Responsible Person
|
Responsible Person <span className="text-red-500">*</span>
|
||||||
<InfoTooltip content="Project lead or account manager responsible for this project." />
|
<InfoTooltip content="Project lead or account manager responsible for this project. Required." />
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="responsiblePerson"
|
id="responsiblePerson"
|
||||||
@@ -530,6 +530,7 @@ export function ProjectModal({ project, onClose }: ProjectModalProps) {
|
|||||||
value={form.responsiblePerson}
|
value={form.responsiblePerson}
|
||||||
onChange={(e) => setField("responsiblePerson", e.target.value)}
|
onChange={(e) => setField("responsiblePerson", e.target.value)}
|
||||||
placeholder="Name or EID"
|
placeholder="Name or EID"
|
||||||
|
required
|
||||||
className={inputClass}
|
className={inputClass}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1089,7 +1089,7 @@ export function ProjectWizard({ open, onClose }: ProjectWizardProps) {
|
|||||||
endDate: new Date(state.endDate),
|
endDate: new Date(state.endDate),
|
||||||
staffingReqs: state.staffingReqs,
|
staffingReqs: state.staffingReqs,
|
||||||
status: state.saveAsDraft ? ProjectStatus.DRAFT : ProjectStatus.ACTIVE,
|
status: state.saveAsDraft ? ProjectStatus.DRAFT : ProjectStatus.ACTIVE,
|
||||||
responsiblePerson: state.responsiblePerson.trim() || undefined,
|
responsiblePerson: state.responsiblePerson.trim(),
|
||||||
blueprintId: state.blueprintId ?? undefined,
|
blueprintId: state.blueprintId ?? undefined,
|
||||||
dynamicFields: {},
|
dynamicFields: {},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export const CreateProjectBaseSchema = z.object({
|
|||||||
dynamicFields: z.record(z.string(), z.unknown()).default({}),
|
dynamicFields: z.record(z.string(), z.unknown()).default({}),
|
||||||
blueprintId: z.string().optional(),
|
blueprintId: z.string().optional(),
|
||||||
status: z.nativeEnum(ProjectStatus).default(ProjectStatus.DRAFT),
|
status: z.nativeEnum(ProjectStatus).default(ProjectStatus.DRAFT),
|
||||||
responsiblePerson: z.string().max(200).optional(),
|
responsiblePerson: z.string().min(1, "Responsible person is required").max(200),
|
||||||
color: z.string().regex(/^#[0-9a-fA-F]{6}$/, "Must be a hex color like #3b82f6").optional(),
|
color: z.string().regex(/^#[0-9a-fA-F]{6}$/, "Must be a hex color like #3b82f6").optional(),
|
||||||
utilizationCategoryId: z.string().optional(),
|
utilizationCategoryId: z.string().optional(),
|
||||||
clientId: z.string().optional(),
|
clientId: z.string().optional(),
|
||||||
|
|||||||
Reference in New Issue
Block a user