From 2217722243f00069e69fb08908be904525852c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Mon, 15 Sep 2025 23:27:01 +0300 Subject: [PATCH] Project Management --- .../Seeds/SeederData.json | 20 +- .../components/ActivityTypeFormModal.tsx | 410 ++- .../project/components/ActivityTypes.tsx | 691 ++--- .../views/project/components/ProjectForm.tsx | 2680 ++++++++--------- .../views/project/components/ProjectGantt.tsx | 718 ++--- .../views/project/components/ProjectList.tsx | 1117 ++++--- .../project/components/ProjectPhases.tsx | 645 ++-- .../views/project/components/ProjectTasks.tsx | 10 +- .../views/project/components/ProjectView.tsx | 1857 ++++++------ .../project/components/TaskDailyUpdates.tsx | 626 ++-- .../project/components/TaskViewModal.tsx | 2 +- 11 files changed, 4063 insertions(+), 4713 deletions(-) diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json index 18c3869f..cde35f6c 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json @@ -4686,70 +4686,70 @@ { "key": "admin.project.list", - "path": "/admin/project", + "path": "/admin/projects", "componentPath": "@/views/project/components/ProjectList", "routeType": "protected", "authority": null }, { "key": "admin.project.new", - "path": "/admin/project/new", + "path": "/admin/projects/new", "componentPath": "@/views/project/components/ProjectForm", "routeType": "protected", "authority": null }, { "key": "admin.project.edit", - "path": "/admin/project/edit/:id", + "path": "/admin/projects/edit/:id", "componentPath": "@/views/project/components/ProjectForm", "routeType": "protected", "authority": null }, { "key": "admin.project.detail", - "path": "/admin/project/:id", + "path": "/admin/projects/:id", "componentPath": "@/views/project/components/ProjectView", "routeType": "protected", "authority": null }, { "key": "admin.project.tasks", - "path": "/admin/project/tasks", + "path": "/admin/projects/tasks", "componentPath": "@/views/project/components/ProjectTasks", "routeType": "protected", "authority": null }, { "key": "admin.project.phases", - "path": "/admin/project/phases", + "path": "/admin/projects/phases", "componentPath": "@/views/project/components/ProjectPhases", "routeType": "protected", "authority": null }, { "key": "admin.project.activities", - "path": "/admin/project/activities", + "path": "/admin/projects/activities", "componentPath": "@/views/project/components/ActivityTypes", "routeType": "protected", "authority": null }, { "key": "admin.project.workload", - "path": "/admin/project/workload", + "path": "/admin/projects/workload", "componentPath": "@/views/project/components/ProjectGantt", "routeType": "protected", "authority": null }, { "key": "admin.project.costTracking", - "path": "/admin/project/cost-tracking", + "path": "/admin/projects/cost-tracking", "componentPath": "@/views/project/components/CostTimeTracking", "routeType": "protected", "authority": null }, { "key": "admin.project.dailyUpdates", - "path": "/admin/project/daily-updates", + "path": "/admin/projects/daily-updates", "componentPath": "@/views/project/components/TaskDailyUpdates", "routeType": "protected", "authority": null diff --git a/ui/src/views/project/components/ActivityTypeFormModal.tsx b/ui/src/views/project/components/ActivityTypeFormModal.tsx index 36eabf7d..8d10d368 100644 --- a/ui/src/views/project/components/ActivityTypeFormModal.tsx +++ b/ui/src/views/project/components/ActivityTypeFormModal.tsx @@ -1,13 +1,13 @@ -import React, { useState, useEffect } from "react"; -import { FaSave, FaTimes } from "react-icons/fa"; -import { PsActivityTypeEnum, PsActivity } from "../../../types/ps"; -import { getPsActivityTypeText } from "../../../utils/erp"; +import React, { useState, useEffect } from 'react' +import { FaSave, FaTimes } from 'react-icons/fa' +import { PsActivityTypeEnum, PsActivity } from '../../../types/ps' +import { getPsActivityTypeText } from '../../../utils/erp' interface ActivityTypeFormModalProps { - open: boolean; - activityType: PsActivity | null; - onClose: () => void; - onSave: (activityType: Partial) => void; + open: boolean + activityType: PsActivity | null + onClose: () => void + onSave: (activityType: Partial) => void } const ActivityTypeFormModal: React.FC = ({ @@ -17,277 +17,253 @@ const ActivityTypeFormModal: React.FC = ({ onSave, }) => { const [formData, setFormData] = useState>({ - name: "", - description: "", - category: "", + name: '', + description: '', + category: '', defaultDuration: 1, activityType: PsActivityTypeEnum.WorkLog, isActive: true, - }); + }) - const [errors, setErrors] = useState>({}); + const [errors, setErrors] = useState>({}) useEffect(() => { if (activityType) { setFormData({ ...activityType, - }); + }) } else { setFormData({ - name: "", - description: "", - category: "", + name: '', + description: '', + category: '', defaultDuration: 1, activityType: PsActivityTypeEnum.WorkLog, isActive: true, - }); + }) } - setErrors({}); - }, [activityType]); + setErrors({}) + }, [activityType]) const handleInputChange = ( field: keyof PsActivity, - value: string | number | boolean | PsActivityTypeEnum + value: string | number | boolean | PsActivityTypeEnum, ) => { setFormData((prev) => ({ ...prev, [field]: value, - })); + })) // Clear error when user starts typing if (errors[field]) { setErrors((prev) => ({ ...prev, - [field]: "", - })); + [field]: '', + })) } - }; + } const validateForm = (): boolean => { - const newErrors: Record = {}; + const newErrors: Record = {} if (!formData.name?.trim()) { - newErrors.name = "Aktivite türü adı zorunludur"; + newErrors.name = 'Aktivite türü adı zorunludur' } if (!formData.description?.trim()) { - newErrors.description = "Açıklama zorunludur"; + newErrors.description = 'Açıklama zorunludur' } if (!formData.category?.trim()) { - newErrors.category = "Kategori zorunludur"; + newErrors.category = 'Kategori zorunludur' } if (!formData.defaultDuration || formData.defaultDuration <= 0) { - newErrors.defaultDuration = "Varsayılan süre pozitif bir sayı olmalıdır"; + newErrors.defaultDuration = 'Varsayılan süre pozitif bir sayı olmalıdır' } - setErrors(newErrors); - return Object.keys(newErrors).length === 0; - }; + setErrors(newErrors) + return Object.keys(newErrors).length === 0 + } const handleSave = () => { if (validateForm()) { - onSave(formData); - onClose(); + onSave(formData) + onClose() } - }; + } - if (!open) return null; + if (!open) return null return (
-
+
- -
- {/* Header */} -
-
-

- {activityType ? "Aktivite Türü Düzenle" : "Yeni Aktivite Türü"} -

- -
-
- - {/* Form */} -
+
+
- {/* Activity Type */} -
- - + handleInputChange('activityType', e.target.value as PsActivityTypeEnum) + } + className={`w-full px-2.5 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ + errors.activityType ? 'border-red-500' : 'border-gray-300' + }`} + > + {Object.values(PsActivityTypeEnum).map((type) => ( + + ))} + + {errors.activityType && ( +

{errors.activityType}

+ )} +
+ + {/* Name */} +
+ + handleInputChange('name', e.target.value)} + className={`w-full px-2.5 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ + errors.name ? 'border-red-500' : 'border-gray-300' + }`} + placeholder="Aktivite türü adını girin" + /> + {errors.name &&

{errors.name}

} +
+ + {/* Description */} +
+ +