From 7d525737657e254124d6d73acf1d8260c5279986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Mon, 15 Sep 2025 17:13:20 +0300 Subject: [PATCH] Container Crm Management --- .../views/crm/components/ActivityDetails.tsx | 154 +- ui/src/views/crm/components/ActivityForm.tsx | 266 ++- .../views/crm/components/ActivityRecords.tsx | 891 ++++----- ui/src/views/crm/components/CustomerCards.tsx | 206 +-- ui/src/views/crm/components/CustomerEdit.tsx | 1075 +++++------ ui/src/views/crm/components/CustomerForm.tsx | 914 +++++---- .../views/crm/components/CustomerFormNew.tsx | 907 +++++---- ui/src/views/crm/components/CustomerList.tsx | 164 +- .../crm/components/CustomerListWithToggle.tsx | 99 +- ui/src/views/crm/components/CustomerView.tsx | 1648 ++++++++--------- .../crm/components/LossReasonCardView.tsx | 76 +- .../views/crm/components/LossReasonModal.tsx | 189 +- ui/src/views/crm/components/LossReasons.tsx | 688 ++++--- .../crm/components/OpportunityDetails.tsx | 127 +- .../views/crm/components/OpportunityForm.tsx | 245 +-- .../crm/components/OpportunityManagement.tsx | 566 +++--- .../views/crm/components/SalesOrderForm.tsx | 1328 +++++++------ .../views/crm/components/SalesOrderView.tsx | 695 ++++--- ui/src/views/crm/components/SalesOrders.tsx | 494 +++-- .../views/crm/components/SalesTeamCreate.tsx | 686 ++++--- ui/src/views/crm/components/SalesTeamEdit.tsx | 720 ++++--- ui/src/views/crm/components/SalesTeamView.tsx | 768 ++++---- ui/src/views/crm/components/SalesTeams.tsx | 615 +++--- 23 files changed, 6155 insertions(+), 7366 deletions(-) diff --git a/ui/src/views/crm/components/ActivityDetails.tsx b/ui/src/views/crm/components/ActivityDetails.tsx index 9e6ef6d8..e1b41c13 100644 --- a/ui/src/views/crm/components/ActivityDetails.tsx +++ b/ui/src/views/crm/components/ActivityDetails.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React from 'react' import { FaTimes, FaCalendar, @@ -12,10 +12,10 @@ import { FaFlag, FaFileAlt, FaHistory, -} from "react-icons/fa"; -import { CrmActivity } from "../../../types/crm"; -import { mockEmployees } from "../../../mocks/mockEmployees"; -import { mockBusinessParties } from "../../../mocks/mockBusinessParties"; +} from 'react-icons/fa' +import { CrmActivity } from '../../../types/crm' +import { mockEmployees } from '../../../mocks/mockEmployees' +import { mockBusinessParties } from '../../../mocks/mockBusinessParties' import { getActivityStatusColor, getActivityStatusText, @@ -23,28 +23,22 @@ import { getPsActivityTypeText, getPriorityColor, getPriorityText, -} from "../../../utils/erp"; + getActivityTypeText, +} from '../../../utils/erp' interface ActivityDetailsProps { - isOpen: boolean; - onClose: () => void; - onEdit: (activity: CrmActivity) => void; - activity: CrmActivity | null; + isOpen: boolean + onClose: () => void + onEdit: (activity: CrmActivity) => void + activity: CrmActivity | null } -const ActivityDetails: React.FC = ({ - isOpen, - onClose, - onEdit, - activity, -}) => { - if (!isOpen || !activity) return null; +const ActivityDetails: React.FC = ({ isOpen, onClose, onEdit, activity }) => { + if (!isOpen || !activity) return null - const customer = mockBusinessParties.find( - (c) => c.id === activity.customerId - ); + const customer = mockBusinessParties.find((c) => c.id === activity.customerId) - const ActivityIcon = getActivityTypeIcon(activity.activityType); + const ActivityIcon = getActivityTypeIcon(activity.activityType) return (
@@ -56,12 +50,8 @@ const ActivityDetails: React.FC = ({
-

- {activity.subject} -

-

- {getPsActivityTypeText(activity.activityType)} -

+

{activity.subject}

+

{getActivityTypeText(activity.activityType)}

@@ -72,10 +62,7 @@ const ActivityDetails: React.FC = ({ Düzenle -
@@ -87,7 +74,7 @@ const ActivityDetails: React.FC = ({
{getActivityStatusText(activity.status)} @@ -96,11 +83,7 @@ const ActivityDetails: React.FC = ({
-
+
{getPriorityText(activity.priority)} @@ -112,7 +95,7 @@ const ActivityDetails: React.FC = ({
- {new Date(activity.activityDate).toLocaleDateString("tr-TR")} + {new Date(activity.activityDate).toLocaleDateString('tr-TR')}

Tarih

@@ -139,9 +122,7 @@ const ActivityDetails: React.FC = ({
- +

{activity.subject}

@@ -150,9 +131,7 @@ const ActivityDetails: React.FC = ({ -

- {activity.description} -

+

{activity.description}

)} @@ -163,13 +142,10 @@ const ActivityDetails: React.FC = ({ Başlangıç Saati

- {new Date(activity.startTime).toLocaleTimeString( - "tr-TR", - { - hour: "2-digit", - minute: "2-digit", - } - )} + {new Date(activity.startTime).toLocaleTimeString('tr-TR', { + hour: '2-digit', + minute: '2-digit', + })}

)} @@ -180,13 +156,10 @@ const ActivityDetails: React.FC = ({ Bitiş Saati

- {new Date(activity.endTime).toLocaleTimeString( - "tr-TR", - { - hour: "2-digit", - minute: "2-digit", - } - )} + {new Date(activity.endTime).toLocaleTimeString('tr-TR', { + hour: '2-digit', + minute: '2-digit', + })}

)} @@ -232,16 +205,12 @@ const ActivityDetails: React.FC = ({
- - {customer.primaryContact?.email} - + {customer.primaryContact?.email}
{customer.primaryContact?.phone && (
- - {customer.primaryContact.phone} - + {customer.primaryContact.phone}
)}
@@ -261,14 +230,10 @@ const ActivityDetails: React.FC = ({
- +
- - {activity.assigned?.fullName} - + {activity.assigned?.fullName}
@@ -279,20 +244,15 @@ const ActivityDetails: React.FC = ({
{activity.participants.map((participantId, index) => { - const employee = mockEmployees.find( - (emp) => emp.id === participantId - ); + const employee = mockEmployees.find((emp) => emp.id === participantId) return ( -
+
{employee ? employee.fullName : participantId}
- ); + ) })}
@@ -316,9 +276,7 @@ const ActivityDetails: React.FC = ({
- {new Date(activity.followUpDate).toLocaleDateString( - "tr-TR" - )} + {new Date(activity.followUpDate).toLocaleDateString('tr-TR')}
@@ -329,9 +287,7 @@ const ActivityDetails: React.FC = ({ -

- {activity.followUpActivity} -

+

{activity.followUpActivity}

)}
@@ -351,9 +307,7 @@ const ActivityDetails: React.FC = ({ -

- {activity.outcome} -

+

{activity.outcome}

)} @@ -362,9 +316,7 @@ const ActivityDetails: React.FC = ({ -

- {activity.nextSteps} -

+

{activity.nextSteps}

)} @@ -381,14 +333,10 @@ const ActivityDetails: React.FC = ({
-

- Aktivite Oluşturuldu -

+

Aktivite Oluşturuldu

- {new Date(activity.creationTime).toLocaleDateString( - "tr-TR" - )} + {new Date(activity.creationTime).toLocaleDateString('tr-TR')}

@@ -396,14 +344,10 @@ const ActivityDetails: React.FC = ({
-

- Son Güncelleme -

+

Son Güncelleme

- {new Date( - activity.lastModificationTime - ).toLocaleDateString("tr-TR")} + {new Date(activity.lastModificationTime).toLocaleDateString('tr-TR')}

@@ -414,7 +358,7 @@ const ActivityDetails: React.FC = ({ - ); -}; + ) +} -export default ActivityDetails; +export default ActivityDetails diff --git a/ui/src/views/crm/components/ActivityForm.tsx b/ui/src/views/crm/components/ActivityForm.tsx index 065adaf7..f356da3b 100644 --- a/ui/src/views/crm/components/ActivityForm.tsx +++ b/ui/src/views/crm/components/ActivityForm.tsx @@ -1,163 +1,140 @@ -import React, { useState, useEffect } from "react"; -import { FaTimes, FaCalendar, FaFileAlt, FaFlag } from "react-icons/fa"; -import { - CrmActivity, - CrmActivityTypeEnum, - ActivityStatusEnum, -} from "../../../types/crm"; -import { mockBusinessParties } from "../../../mocks/mockBusinessParties"; -import { mockEmployees } from "../../../mocks/mockEmployees"; -import MultiSelectEmployee from "../../../components/common/MultiSelectEmployee"; -import { BusinessParty, PriorityEnum } from "../../../types/common"; -import { - getActivityStatusText, - getPriorityText, - getActivityTypeText, -} from "../../../utils/erp"; +import React, { useState, useEffect } from 'react' +import { FaTimes, FaCalendar, FaFileAlt, FaFlag } from 'react-icons/fa' +import { CrmActivity, CrmActivityTypeEnum, ActivityStatusEnum } from '../../../types/crm' +import { mockBusinessParties } from '../../../mocks/mockBusinessParties' +import { mockEmployees } from '../../../mocks/mockEmployees' +import MultiSelectEmployee from '../../../components/common/MultiSelectEmployee' +import { BusinessParty, PriorityEnum } from '../../../types/common' +import { getActivityStatusText, getPriorityText, getActivityTypeText } from '../../../utils/erp' interface ActivityFormProps { - isOpen: boolean; - onClose: () => void; - onSave: (activity: CrmActivity) => void; - activity?: CrmActivity | null; - mode: "create" | "edit"; + isOpen: boolean + onClose: () => void + onSave: (activity: CrmActivity) => void + activity?: CrmActivity | null + mode: 'create' | 'edit' } -const ActivityForm: React.FC = ({ - isOpen, - onClose, - onSave, - activity, - mode, -}) => { +const ActivityForm: React.FC = ({ isOpen, onClose, onSave, activity, mode }) => { const [formData, setFormData] = useState({ - id: "", + id: '', activityType: CrmActivityTypeEnum.Call, - subject: "", - description: "", - customerId: "", - contactId: "", - activityDate: "", - startTime: "", - endTime: "", - duration: "", - assignedTo: "", + subject: '', + description: '', + customerId: '', + contactId: '', + activityDate: '', + startTime: '', + endTime: '', + duration: '', + assignedTo: '', participants: [] as string[], // Array of employee IDs status: ActivityStatusEnum.Planned, priority: PriorityEnum.Normal, - followUpDate: "", - followUpActivity: "", - outcome: "", - nextSteps: "", - }); + followUpDate: '', + followUpActivity: '', + outcome: '', + nextSteps: '', + }) - const [customers] = useState(mockBusinessParties); - const [errors, setErrors] = useState>({}); + const [customers] = useState(mockBusinessParties) + const [errors, setErrors] = useState>({}) useEffect(() => { - if (activity && mode === "edit") { + if (activity && mode === 'edit') { setFormData({ id: activity.id, activityType: activity.activityType, subject: activity.subject, - description: activity.description || "", - customerId: activity.customerId || "", - contactId: activity.contactId || "", - activityDate: activity.activityDate.toISOString().split("T")[0], - startTime: activity.startTime - ? activity.startTime.toISOString().slice(11, 16) - : "", - endTime: activity.endTime - ? activity.endTime.toISOString().slice(11, 16) - : "", - duration: activity.duration?.toString() || "", + description: activity.description || '', + customerId: activity.customerId || '', + contactId: activity.contactId || '', + activityDate: activity.activityDate.toISOString().split('T')[0], + startTime: activity.startTime ? activity.startTime.toISOString().slice(11, 16) : '', + endTime: activity.endTime ? activity.endTime.toISOString().slice(11, 16) : '', + duration: activity.duration?.toString() || '', assignedTo: activity.assignedTo, participants: activity.participants || [], // Keep as array of IDs status: activity.status, priority: activity.priority, followUpDate: activity.followUpDate - ? activity.followUpDate.toISOString().split("T")[0] - : "", - followUpActivity: activity.followUpActivity || "", - outcome: activity.outcome || "", - nextSteps: activity.nextSteps || "", - }); - } else if (mode === "create") { - const today = new Date().toISOString().split("T")[0]; + ? activity.followUpDate.toISOString().split('T')[0] + : '', + followUpActivity: activity.followUpActivity || '', + outcome: activity.outcome || '', + nextSteps: activity.nextSteps || '', + }) + } else if (mode === 'create') { + const today = new Date().toISOString().split('T')[0] setFormData({ id: `act_${Date.now()}`, activityType: CrmActivityTypeEnum.Call, - subject: "", - description: "", - customerId: "", - contactId: "", + subject: '', + description: '', + customerId: '', + contactId: '', activityDate: today, - startTime: "", - endTime: "", - duration: "", - assignedTo: "Mevcut Kullanıcı", + startTime: '', + endTime: '', + duration: '', + assignedTo: 'Mevcut Kullanıcı', participants: [], // Empty array for new activities status: ActivityStatusEnum.Planned, priority: PriorityEnum.Normal, - followUpDate: "", - followUpActivity: "", - outcome: "", - nextSteps: "", - }); + followUpDate: '', + followUpActivity: '', + outcome: '', + nextSteps: '', + }) } - }, [activity, mode, isOpen]); + }, [activity, mode, isOpen]) const handleInputChange = ( - e: React.ChangeEvent< - HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement - > + e: React.ChangeEvent, ) => { - const { name, value } = e.target; + const { name, value } = e.target setFormData((prev) => ({ ...prev, [name]: value, - })); + })) // Clear error when user starts typing if (errors[name]) { setErrors((prev) => ({ ...prev, - [name]: "", - })); + [name]: '', + })) } - }; + } const validateForm = () => { - const newErrors: Record = {}; + const newErrors: Record = {} if (!formData.subject.trim()) { - newErrors.subject = "Aktivite konusu zorunludur"; + newErrors.subject = 'Aktivite konusu zorunludur' } if (!formData.activityDate) { - newErrors.activityDate = "Aktivite tarihi zorunludur"; + newErrors.activityDate = 'Aktivite tarihi zorunludur' } if (!formData.assignedTo.trim()) { - newErrors.assignedTo = "Sorumlu kişi zorunludur"; + newErrors.assignedTo = 'Sorumlu kişi zorunludur' } - if ( - formData.duration && - (isNaN(Number(formData.duration)) || Number(formData.duration) <= 0) - ) { - newErrors.duration = "Süre geçerli bir sayı olmalıdır"; + if (formData.duration && (isNaN(Number(formData.duration)) || Number(formData.duration) <= 0)) { + newErrors.duration = 'Süre geçerli bir sayı olmalıdır' } - setErrors(newErrors); - return Object.keys(newErrors).length === 0; - }; + setErrors(newErrors) + return Object.keys(newErrors).length === 0 + } const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); + e.preventDefault() if (!validateForm()) { - return; + return } const activityData: CrmActivity = { @@ -179,21 +156,19 @@ const ActivityForm: React.FC = ({ participants: formData.participants, // Already an array of IDs status: formData.status, priority: formData.priority, - followUpDate: formData.followUpDate - ? new Date(formData.followUpDate) - : undefined, + followUpDate: formData.followUpDate ? new Date(formData.followUpDate) : undefined, followUpActivity: formData.followUpActivity || undefined, outcome: formData.outcome || undefined, nextSteps: formData.nextSteps || undefined, creationTime: activity?.creationTime || new Date(), lastModificationTime: new Date(), - }; + } - onSave(activityData); - onClose(); - }; + onSave(activityData) + onClose() + } - if (!isOpen) return null; + if (!isOpen) return null return (
@@ -201,12 +176,9 @@ const ActivityForm: React.FC = ({ {/* Header */}

- {mode === "create" ? "Yeni Aktivite Oluştur" : "Aktivite Düzenle"} + {mode === 'create' ? 'Yeni Aktivite Oluştur' : 'Aktivite Düzenle'}

-
@@ -240,28 +212,22 @@ const ActivityForm: React.FC = ({
- + - {errors.subject && ( -

{errors.subject}

- )} + {errors.subject &&

{errors.subject}

}
- +