From 4e5322ba0c4430d16e7fd91dfa05b85cbd0a2f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Mon, 15 Sep 2025 22:22:43 +0300 Subject: [PATCH] =?UTF-8?q?Container=20g=C3=BCncellemesi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/dev-dist/sw.js | 2 +- ui/src/types/mrp.ts | 4 +- .../views/accounting/AccountingManagement.tsx | 42 - .../accounting/components/BankManagement.tsx | 2 +- .../accounting/components/CashManagement.tsx | 2 +- .../components/CheckNoteManagement.tsx | 2 +- .../components/CurrentAccountManagement.tsx | 54 +- .../components/InvoiceManagement.tsx | 2 +- .../components/WaybillManagement.tsx | 2 +- ui/src/views/crm/CRMManagement.tsx | 49 - .../views/crm/components/ActivityDetails.tsx | 1 - .../views/crm/components/ActivityRecords.tsx | 2 +- ui/src/views/crm/components/CustomerCards.tsx | 2 +- ui/src/views/crm/components/CustomerEdit.tsx | 6 +- ui/src/views/crm/components/CustomerForm.tsx | 2 +- .../views/crm/components/CustomerFormNew.tsx | 2 +- ui/src/views/crm/components/CustomerList.tsx | 2 +- .../crm/components/CustomerListWithToggle.tsx | 2 +- ui/src/views/crm/components/CustomerView.tsx | 2 +- ui/src/views/crm/components/LossReasons.tsx | 122 +- .../crm/components/OpportunityManagement.tsx | 34 +- .../views/crm/components/SalesOrderForm.tsx | 2 +- .../views/crm/components/SalesOrderView.tsx | 2 +- ui/src/views/crm/components/SalesOrders.tsx | 2 +- .../views/crm/components/SalesTeamCreate.tsx | 2 +- ui/src/views/crm/components/SalesTeamEdit.tsx | 2 +- ui/src/views/crm/components/SalesTeamView.tsx | 2 +- ui/src/views/crm/components/SalesTeams.tsx | 2 +- ui/src/views/hr/HRManagement.tsx | 49 - .../maintenance/MaintenanceManagement.tsx | 41 - .../components/WorkCenterCards.tsx | 1118 +++++++------ .../maintenance/components/WorkCenterForm.tsx | 2 +- .../maintenance/components/WorkCenterList.tsx | 627 ++++---- ui/src/views/mrp/MRPManagement.tsx | 41 - ui/src/views/mrp/components/BOMManagement.tsx | 572 ++++--- .../views/mrp/components/DemandPlanning.tsx | 852 +++++----- .../mrp/components/OperationDefinitions.tsx | 703 ++++----- ui/src/views/mrp/components/OperationForm.tsx | 2 +- .../mrp/components/OperationFormModal.tsx | 2 +- .../views/mrp/components/OperationTypes.tsx | 620 ++++---- ui/src/views/mrp/components/PlanningGantt.tsx | 11 +- .../mrp/components/ProductionOrderForm.tsx | 1054 ++++++------- .../mrp/components/ProductionOrderList.tsx | 1384 ++++++++--------- .../mrp/components/ProductionOrderView.tsx | 769 +++++---- ui/src/views/mrp/components/Requirements.tsx | 315 ++-- ui/src/views/mrp/components/WorkOrders.tsx | 472 +++--- ui/src/views/project/ProjectManagement.tsx | 44 - .../supplyChain/SupplyChainManagement.tsx | 55 - .../views/warehouse/WarehouseManagement.tsx | 43 - 49 files changed, 4049 insertions(+), 5079 deletions(-) delete mode 100644 ui/src/views/accounting/AccountingManagement.tsx delete mode 100644 ui/src/views/crm/CRMManagement.tsx delete mode 100644 ui/src/views/hr/HRManagement.tsx delete mode 100644 ui/src/views/maintenance/MaintenanceManagement.tsx delete mode 100644 ui/src/views/mrp/MRPManagement.tsx delete mode 100644 ui/src/views/project/ProjectManagement.tsx delete mode 100644 ui/src/views/supplyChain/SupplyChainManagement.tsx delete mode 100644 ui/src/views/warehouse/WarehouseManagement.tsx diff --git a/ui/dev-dist/sw.js b/ui/dev-dist/sw.js index 9c4e9a72..abf60c30 100644 --- a/ui/dev-dist/sw.js +++ b/ui/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-a959eb95'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "/index.html", - "revision": "0.sbo84r6raa" + "revision": "0.daul0044rt" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("/index.html"), { diff --git a/ui/src/types/mrp.ts b/ui/src/types/mrp.ts index 23e6ef92..e1bc7508 100644 --- a/ui/src/types/mrp.ts +++ b/ui/src/types/mrp.ts @@ -1,4 +1,3 @@ -import { CrmSalesOrder } from "./admin/crm"; import { PmWorkCenter, WorkOrderStatusEnum } from "./pm"; import { MmMaterial, @@ -7,6 +6,7 @@ import { QualityStatusEnum, } from "./mm"; import { PriorityEnum } from "./common"; +import { CrmSalesOrder } from "./crm"; export interface MrpProductionOrder { // Üretim Emri @@ -196,7 +196,7 @@ export interface MrpDemandForecast { notes: string; } -export interface MrpPurchaseSuggestionn extends MrpRecommendation { +export interface MrpPurchaseSuggestion extends MrpRecommendation { // Satınalma Tavsiyesi supplierId: string; supplier?: MmMaterialSupplier; diff --git a/ui/src/views/accounting/AccountingManagement.tsx b/ui/src/views/accounting/AccountingManagement.tsx deleted file mode 100644 index 9e738c78..00000000 --- a/ui/src/views/accounting/AccountingManagement.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from "react"; -import { Outlet, useLocation } from "react-router-dom"; -import ModuleHeader from "../../components/common/ModuleHeader"; - -const AccountingManagement: React.FC = () => { - const location = useLocation(); - - // Define page mappings for breadcrumbs - const getPageTitle = (pathname: string) => { - if ( - pathname === "/admin/accounting" || - pathname === "/admin/accounting/current-accounts" - ) - return "Cari Hesap Yönetimi"; - if (pathname === "/admin/accounting/waybills") return "İrsaliye Yönetimi"; - if (pathname === "/admin/accounting/invoices") return "Fatura Yönetimi"; - if (pathname === "/admin/accounting/cash") return "Kasa Yönetimi"; - if (pathname === "/admin/accounting/bank") return "Banka Yönetimi"; - if (pathname === "/admin/accounting/check-note") return "Çek & Senet Takibi"; - return "Muhasebe Yönetimi"; - }; - - const pageTitle = getPageTitle(location.pathname); - - // Create breadcrumbs: Anasayfa / CRM Yönetimi / Sayfanın Adı - const breadcrumbs = [{ name: "CRM Yönetimi", href: "/admin/crm" }]; - - return ( -
- - -
- -
-
- ); -}; - -export default AccountingManagement; diff --git a/ui/src/views/accounting/components/BankManagement.tsx b/ui/src/views/accounting/components/BankManagement.tsx index 569729c9..740f53bf 100644 --- a/ui/src/views/accounting/components/BankManagement.tsx +++ b/ui/src/views/accounting/components/BankManagement.tsx @@ -458,7 +458,7 @@ const BankManagement: React.FC = ({ ); return ( -
+
{/* Header */}
diff --git a/ui/src/views/accounting/components/CashManagement.tsx b/ui/src/views/accounting/components/CashManagement.tsx index 8f70cce5..0351cbc4 100644 --- a/ui/src/views/accounting/components/CashManagement.tsx +++ b/ui/src/views/accounting/components/CashManagement.tsx @@ -336,7 +336,7 @@ const CashManagement: React.FC = ({ .reduce((sum, m) => sum + m.amount, 0); return ( -
+
{/* Header */}
diff --git a/ui/src/views/accounting/components/CheckNoteManagement.tsx b/ui/src/views/accounting/components/CheckNoteManagement.tsx index 72534824..249836c9 100644 --- a/ui/src/views/accounting/components/CheckNoteManagement.tsx +++ b/ui/src/views/accounting/components/CheckNoteManagement.tsx @@ -662,7 +662,7 @@ const CheckNoteManagement: React.FC = ({ }) return ( -
+
{/* Header */}
diff --git a/ui/src/views/accounting/components/CurrentAccountManagement.tsx b/ui/src/views/accounting/components/CurrentAccountManagement.tsx index d2c19b7f..941caa34 100644 --- a/ui/src/views/accounting/components/CurrentAccountManagement.tsx +++ b/ui/src/views/accounting/components/CurrentAccountManagement.tsx @@ -20,8 +20,12 @@ import CurrentAccountDetails from "./CurrentAccountDetails"; import CurrentAccountMovementForm from "./CurrentAccountMovementForm"; import Widget from "../../../components/common/Widget"; import { + getAccountTypeColor, + getAccountTypeText, getFiDocumentTypeColor, getFiDocumentTypeText, + getRiskGroupColor, + getRiskGroupText, } from "../../../utils/erp"; interface CurrentAccountManagementProps { @@ -351,46 +355,6 @@ const CurrentAccountManagement: React.FC = ({ } }); - const getAccountTypeLabel = (type: AccountTypeEnum) => { - const typeLabels = { - [AccountTypeEnum.Customer]: "Müşteri", - [AccountTypeEnum.Supplier]: "Tedarikçi", - [AccountTypeEnum.Both]: "Müşteri/Tedarikçi", - [AccountTypeEnum.Other]: "Diğer", - }; - return typeLabels[type]; - }; - - const getAccountTypeColor = (type: AccountTypeEnum) => { - const typeColors = { - [AccountTypeEnum.Customer]: "bg-blue-100 text-blue-800", - [AccountTypeEnum.Supplier]: "bg-green-100 text-green-800", - [AccountTypeEnum.Both]: "bg-purple-100 text-purple-800", - [AccountTypeEnum.Other]: "bg-gray-100 text-gray-800", - }; - return typeColors[type]; - }; - - const getRiskGroupLabel = (riskGroup: RiskGroupEnum) => { - const riskLabels = { - [RiskGroupEnum.Low]: "Düşük Risk", - [RiskGroupEnum.Medium]: "Orta Risk", - [RiskGroupEnum.High]: "Yüksek Risk", - [RiskGroupEnum.Blocked]: "Blokeli", - }; - return riskLabels[riskGroup]; - }; - - const getRiskGroupColor = (riskGroup: RiskGroupEnum) => { - const riskColors = { - [RiskGroupEnum.Low]: "bg-green-100 text-green-800", - [RiskGroupEnum.Medium]: "bg-yellow-100 text-yellow-800", - [RiskGroupEnum.High]: "bg-orange-100 text-orange-800", - [RiskGroupEnum.Blocked]: "bg-red-100 text-red-800", - }; - return riskColors[riskGroup]; - }; - const formatBalance = (balance: number) => { const isDebit = balance > 0; const absBalance = Math.abs(balance); @@ -438,7 +402,7 @@ const CurrentAccountManagement: React.FC = ({ account.type )}`} > - {getAccountTypeLabel(account.type)} + {getAccountTypeText(account.type)} ), }, @@ -486,7 +450,7 @@ const CurrentAccountManagement: React.FC = ({ account.riskGroup )}`} > - {getRiskGroupLabel(account.riskGroup)} + {getRiskGroupText(account.riskGroup)} ), }, @@ -566,7 +530,7 @@ const CurrentAccountManagement: React.FC = ({ ); return ( -
+
{/* Header */}
@@ -682,7 +646,7 @@ const CurrentAccountManagement: React.FC = ({ {Object.values(AccountTypeEnum).map((type) => ( ))} @@ -699,7 +663,7 @@ const CurrentAccountManagement: React.FC = ({ {Object.values(RiskGroupEnum).map((risk) => ( ))} diff --git a/ui/src/views/accounting/components/InvoiceManagement.tsx b/ui/src/views/accounting/components/InvoiceManagement.tsx index 14095b64..eb4e4141 100644 --- a/ui/src/views/accounting/components/InvoiceManagement.tsx +++ b/ui/src/views/accounting/components/InvoiceManagement.tsx @@ -311,7 +311,7 @@ const InvoiceManagement: React.FC = ({ })); return ( -
+
{/* Header */}
diff --git a/ui/src/views/accounting/components/WaybillManagement.tsx b/ui/src/views/accounting/components/WaybillManagement.tsx index 5075b940..a01eddbb 100644 --- a/ui/src/views/accounting/components/WaybillManagement.tsx +++ b/ui/src/views/accounting/components/WaybillManagement.tsx @@ -310,7 +310,7 @@ const WaybillManagement: React.FC = ({ })); return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/CRMManagement.tsx b/ui/src/views/crm/CRMManagement.tsx deleted file mode 100644 index 17c7d944..00000000 --- a/ui/src/views/crm/CRMManagement.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import { Outlet, useLocation } from "react-router-dom"; -import ModuleHeader from "../../components/common/ModuleHeader"; - -const CRMManagement: React.FC = () => { - const location = useLocation(); - - // Define page mappings for breadcrumbs - const getPageTitle = (pathname: string) => { - if (pathname === "/admin/crm" || pathname === "/admin/crm/customers") return "Müşteriler"; - if (pathname === "/admin/crm/sales-teams") return "Satış Takımları"; - if (pathname === "/admin/crm/sales-teams/new") return "Yeni Satış Takımı"; - if (pathname.includes("/admin/crm/sales-teams/edit/")) return "Satış Takımı Düzenle"; - if (pathname.includes("/admin/crm/sales-teams/") && !pathname.includes("edit") && !pathname.includes("new")) return "Satış Takımı Detayları"; - if (pathname === "/admin/crm/loss-reasons") return "Kayıp Nedenleri"; - if (pathname === "/admin/crm/opportunities") return "Fırsatlar"; - if (pathname === "/admin/crm/activities") return "Aktiviteler"; - if (pathname === "/admin/crm/sales-orders") return "Satış Siparişleri"; - if (pathname === "/admin/crm/sales-orders/new") return "Yeni Satış Siparişi"; - if (pathname.includes("/admin/crm/sales-orders/edit/")) return "Satış Siparişi Düzenle"; - if (pathname.includes("/admin/crm/sales-orders/") && !pathname.includes("edit") && !pathname.includes("new")) return "Satış Siparişi Detayları"; - if (pathname === "/admin/crm/customers/new") return "Yeni Müşteri"; - if (pathname.includes("/admin/crm/customers/edit/")) return "Müşteri Düzenle"; - if (pathname.includes("/admin/crm/customers/") && !pathname.includes("edit") && !pathname.includes("new")) return "Müşteri Detayları"; - return "CRM Yönetimi"; - }; - - const pageTitle = getPageTitle(location.pathname); - - // Create breadcrumbs: Anasayfa / CRM Yönetimi / Sayfanın Adı - const breadcrumbs = [ - { name: "CRM Yönetimi", href: "/admin/crm" } - ]; - - return ( -
- - -
- -
-
- ); -}; - -export default CRMManagement; diff --git a/ui/src/views/crm/components/ActivityDetails.tsx b/ui/src/views/crm/components/ActivityDetails.tsx index e1b41c13..0d827150 100644 --- a/ui/src/views/crm/components/ActivityDetails.tsx +++ b/ui/src/views/crm/components/ActivityDetails.tsx @@ -20,7 +20,6 @@ import { getActivityStatusColor, getActivityStatusText, getActivityTypeIcon, - getPsActivityTypeText, getPriorityColor, getPriorityText, getActivityTypeText, diff --git a/ui/src/views/crm/components/ActivityRecords.tsx b/ui/src/views/crm/components/ActivityRecords.tsx index da5915b8..c784d62b 100644 --- a/ui/src/views/crm/components/ActivityRecords.tsx +++ b/ui/src/views/crm/components/ActivityRecords.tsx @@ -253,7 +253,7 @@ const ActivityRecords: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/components/CustomerCards.tsx b/ui/src/views/crm/components/CustomerCards.tsx index dc3db675..de5e57a0 100644 --- a/ui/src/views/crm/components/CustomerCards.tsx +++ b/ui/src/views/crm/components/CustomerCards.tsx @@ -113,7 +113,7 @@ const CustomerCards: React.FC = () => { } return ( -
+
{/* Header Actions */}
diff --git a/ui/src/views/crm/components/CustomerEdit.tsx b/ui/src/views/crm/components/CustomerEdit.tsx index d074ffcb..378fc79f 100644 --- a/ui/src/views/crm/components/CustomerEdit.tsx +++ b/ui/src/views/crm/components/CustomerEdit.tsx @@ -166,7 +166,7 @@ const CustomerEdit: React.FC = () => { return ( -
+
{/* Header */}
@@ -196,8 +196,8 @@ const CustomerEdit: React.FC = () => {
-
- +
+
diff --git a/ui/src/views/crm/components/CustomerForm.tsx b/ui/src/views/crm/components/CustomerForm.tsx index 3e4e2a04..b1c2a073 100644 --- a/ui/src/views/crm/components/CustomerForm.tsx +++ b/ui/src/views/crm/components/CustomerForm.tsx @@ -123,7 +123,7 @@ const CustomerForm: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/components/CustomerFormNew.tsx b/ui/src/views/crm/components/CustomerFormNew.tsx index d0896f95..7dfb7a4a 100644 --- a/ui/src/views/crm/components/CustomerFormNew.tsx +++ b/ui/src/views/crm/components/CustomerFormNew.tsx @@ -121,7 +121,7 @@ const CustomerForm: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/components/CustomerList.tsx b/ui/src/views/crm/components/CustomerList.tsx index e8a2c761..7c6bfd5e 100644 --- a/ui/src/views/crm/components/CustomerList.tsx +++ b/ui/src/views/crm/components/CustomerList.tsx @@ -82,7 +82,7 @@ const CustomerList: React.FC = () => { } return ( -
+
{/* Header Actions */}
diff --git a/ui/src/views/crm/components/CustomerListWithToggle.tsx b/ui/src/views/crm/components/CustomerListWithToggle.tsx index 5ed763a5..f84e5aff 100644 --- a/ui/src/views/crm/components/CustomerListWithToggle.tsx +++ b/ui/src/views/crm/components/CustomerListWithToggle.tsx @@ -12,7 +12,7 @@ const CustomerListWithToggle: React.FC = () => { return ( -
+
{/* Header with View Toggle */}
diff --git a/ui/src/views/crm/components/CustomerView.tsx b/ui/src/views/crm/components/CustomerView.tsx index 8ad83ec9..9d02e477 100644 --- a/ui/src/views/crm/components/CustomerView.tsx +++ b/ui/src/views/crm/components/CustomerView.tsx @@ -128,7 +128,7 @@ const CustomerView: React.FC = () => { return ( -
+
{/* Breadcrumb */} diff --git a/ui/src/views/crm/components/LossReasons.tsx b/ui/src/views/crm/components/LossReasons.tsx index c73fcb92..0488ba82 100644 --- a/ui/src/views/crm/components/LossReasons.tsx +++ b/ui/src/views/crm/components/LossReasons.tsx @@ -221,7 +221,7 @@ const LossReasons: React.FC = () => { return ( -
+
{/* Header */}
@@ -391,79 +391,79 @@ const LossReasons: React.FC = () => {

Arama kriterlerinizi değiştirmeyi deneyin.

)} +
- {/* Modals */} - { - setIsModalOpen(false) - setEditingReason(null) - }} - onSave={handleSave} - editingReason={editingReason} - mode={modalMode} - /> + {/* Modals */} + { + setIsModalOpen(false) + setEditingReason(null) + }} + onSave={handleSave} + editingReason={editingReason} + mode={modalMode} + /> - {/* Delete Confirmation Modal */} - {isDeleteModalOpen && ( -
-
- {/* Header */} -
-
- -

Silme Onayı

+ {/* Delete Confirmation Modal */} + {isDeleteModalOpen && ( +
+
+ {/* Header */} +
+
+ +

Silme Onayı

+
+ +
+ + {/* Content */} +
+
+
+
+

+ Kayıp nedeni silinsin mi? +

+

+ "{reasonToDelete?.name}" kayıp nedenini + silmek üzeresiniz. Bu işlem geri alınamaz. +

+
+ + {/* Buttons */} +
+ -
- - {/* Content */} -
-
-
- -
-

- Kayıp nedeni silinsin mi? -

-

- "{reasonToDelete?.name}" kayıp nedenini - silmek üzeresiniz. Bu işlem geri alınamaz. -

-
- - {/* Buttons */} -
- - -
- )} -
+
+ )} ) } diff --git a/ui/src/views/crm/components/OpportunityManagement.tsx b/ui/src/views/crm/components/OpportunityManagement.tsx index 97e7d317..edf8f863 100644 --- a/ui/src/views/crm/components/OpportunityManagement.tsx +++ b/ui/src/views/crm/components/OpportunityManagement.tsx @@ -237,7 +237,7 @@ const OpportunityManagement: React.FC = () => { return ( -
+
{/* Header */}
@@ -384,23 +384,23 @@ const OpportunityManagement: React.FC = () => {

Arama kriterlerinizi değiştirmeyi deneyin.

)} - - {/* Modals */} - - -
+ + {/* Modals */} + + + ) } diff --git a/ui/src/views/crm/components/SalesOrderForm.tsx b/ui/src/views/crm/components/SalesOrderForm.tsx index 40a6f994..6c4d5ab5 100644 --- a/ui/src/views/crm/components/SalesOrderForm.tsx +++ b/ui/src/views/crm/components/SalesOrderForm.tsx @@ -246,7 +246,7 @@ const SalesOrderForm: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/components/SalesOrderView.tsx b/ui/src/views/crm/components/SalesOrderView.tsx index 0827638d..7b3dffd0 100644 --- a/ui/src/views/crm/components/SalesOrderView.tsx +++ b/ui/src/views/crm/components/SalesOrderView.tsx @@ -73,7 +73,7 @@ const SalesOrderView: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/components/SalesOrders.tsx b/ui/src/views/crm/components/SalesOrders.tsx index efab756c..83b99780 100644 --- a/ui/src/views/crm/components/SalesOrders.tsx +++ b/ui/src/views/crm/components/SalesOrders.tsx @@ -203,7 +203,7 @@ const SalesOrders: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/components/SalesTeamCreate.tsx b/ui/src/views/crm/components/SalesTeamCreate.tsx index acf9e51d..9f55e4a1 100644 --- a/ui/src/views/crm/components/SalesTeamCreate.tsx +++ b/ui/src/views/crm/components/SalesTeamCreate.tsx @@ -133,7 +133,7 @@ const SalesTeamCreate: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/components/SalesTeamEdit.tsx b/ui/src/views/crm/components/SalesTeamEdit.tsx index f45b34b2..79f855e3 100644 --- a/ui/src/views/crm/components/SalesTeamEdit.tsx +++ b/ui/src/views/crm/components/SalesTeamEdit.tsx @@ -181,7 +181,7 @@ const SalesTeamEdit: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/components/SalesTeamView.tsx b/ui/src/views/crm/components/SalesTeamView.tsx index c625eab2..7d7ff0e2 100644 --- a/ui/src/views/crm/components/SalesTeamView.tsx +++ b/ui/src/views/crm/components/SalesTeamView.tsx @@ -72,7 +72,7 @@ const SalesTeamView: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/crm/components/SalesTeams.tsx b/ui/src/views/crm/components/SalesTeams.tsx index 15f62ea1..7becd81d 100644 --- a/ui/src/views/crm/components/SalesTeams.tsx +++ b/ui/src/views/crm/components/SalesTeams.tsx @@ -201,7 +201,7 @@ const SalesTeams: React.FC = () => { return ( -
+
{/* Header */}
diff --git a/ui/src/views/hr/HRManagement.tsx b/ui/src/views/hr/HRManagement.tsx deleted file mode 100644 index 2d1cd20a..00000000 --- a/ui/src/views/hr/HRManagement.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import { Outlet, useLocation } from "react-router-dom"; -import ModuleHeader from "../../components/common/ModuleHeader"; - -const HRManagement: React.FC = () => { - const location = useLocation(); - - // Define page mappings for breadcrumbs - const getPageTitle = (pathname: string) => { - if (pathname === "/admin/hr" || pathname === "/admin/hr/") return "Personel Listesi"; - if (pathname === "/admin/hr/departments") return "Departman Yönetimi"; - if (pathname === "/admin/hr/cost-centers") return "Maliyet Merkezi Yönetimi"; - if (pathname === "/admin/hr/organization") return "Organizasyon Şeması"; - if (pathname === "/admin/hr/leave-management") return "İzin Yönetimi"; - if (pathname === "/admin/hr/overtimes-management") return "Mesai Yönetimi"; - if (pathname === "/admin/hr/payroll") return "Bordro Yönetimi"; - if (pathname === "/admin/hr/job-positions") return "İş Pozisyonları"; - if (pathname === "/admin/hr/employment-types") return "İstihdam Türleri"; - if (pathname === "/admin/hr/badges") return "Rozet Yönetimi"; - if (pathname === "/admin/hr/360-templates") return "360 Derece Şablonları"; - if (pathname === "/admin/hr/360-evaluation") return "360 Derece Değerlendirme"; - if (pathname === "/admin/hr/employees/new") return "Yeni Çalışan"; - if (pathname.includes("/admin/hr/employees/edit/")) return "Çalışan Düzenle"; - if (pathname.includes("/admin/hr/employees/") && !pathname.includes("edit") && !pathname.includes("new")) return "Çalışan Detayları"; - return "İnsan Kaynakları"; - }; - - const pageTitle = getPageTitle(location.pathname); - - // Create breadcrumbs: Anasayfa / İnsan Kaynakları / Sayfanın Adı - const breadcrumbs = [ - { name: "İnsan Kaynakları", href: "/admin/hr" } - ]; - - return ( -
- - -
- -
-
- ); -}; - -export default HRManagement; diff --git a/ui/src/views/maintenance/MaintenanceManagement.tsx b/ui/src/views/maintenance/MaintenanceManagement.tsx deleted file mode 100644 index 3ca7c34a..00000000 --- a/ui/src/views/maintenance/MaintenanceManagement.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from "react"; -import { Outlet, useLocation } from "react-router-dom"; -import ModuleHeader from "../../components/common/ModuleHeader"; - -const MaintenanceManagement: React.FC = () => { - const location = useLocation(); - - // Define page mappings for breadcrumbs - const getPageTitle = (pathname: string) => { - if (pathname === "/admin/maintenance" || pathname === "/admin/maintenance/" || pathname === "/admin/maintenance/equipment") return "İş Merkezleri"; - if (pathname === "/admin/maintenance/workcenters") return "İş Merkezleri"; - if (pathname === "/admin/maintenance/plans") return "Bakım Planları"; - if (pathname === "/admin/maintenance/calendar") return "Bakım Takvimi"; - if (pathname === "/admin/maintenance/teams") return "Bakım Takımları"; - if (pathname === "/admin/maintenance/faults") return "Arıza Bildirimleri"; - if (pathname === "/admin/maintenance/workorders") return "Bakım İş Emirleri"; - return "Bakım Yönetimi"; - }; - - const pageTitle = getPageTitle(location.pathname); - - // Create breadcrumbs: Anasayfa / Bakım Yönetimi / Sayfanın Adı - const breadcrumbs = [ - { name: "Bakım Yönetimi", href: "/admin/maintenance" } - ]; - - return ( -
- - -
- -
-
- ); -}; - -export default MaintenanceManagement; diff --git a/ui/src/views/maintenance/components/WorkCenterCards.tsx b/ui/src/views/maintenance/components/WorkCenterCards.tsx index a590ddbb..1c2594c9 100644 --- a/ui/src/views/maintenance/components/WorkCenterCards.tsx +++ b/ui/src/views/maintenance/components/WorkCenterCards.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState } from 'react' import { FaPlus, FaSearch, @@ -13,95 +13,84 @@ import { FaTh, FaList, FaIndustry, -} from "react-icons/fa"; +} from 'react-icons/fa' import { PmWorkCenter, WorkCenterStatusEnum, CriticalityLevelEnum, PmMaintenancePlan, -} from "../../../types/pm"; -import { mockWorkCenters } from "../../../mocks/mockWorkCenters"; -import NewWorkCenterModal from "./NewWorkCenterModal"; -import ViewWorkCenterModal from "./ViewWorkCenterModal"; -import EditWorkCenterModal from "./EditWorkCenterModal"; -import MaintenancePlanModal from "./MaintenancePlanModal"; -import StatusUpdateModal from "./StatusUpdateModal"; -import Widget from "../../../components/common/Widget"; +} from '../../../types/pm' +import { mockWorkCenters } from '../../../mocks/mockWorkCenters' +import NewWorkCenterModal from './NewWorkCenterModal' +import ViewWorkCenterModal from './ViewWorkCenterModal' +import EditWorkCenterModal from './EditWorkCenterModal' +import MaintenancePlanModal from './MaintenancePlanModal' +import StatusUpdateModal from './StatusUpdateModal' +import Widget from '../../../components/common/Widget' import { getWorkCenterStatusColor, getWorkCenterStatusText, getCriticalityLevelColor, getCriticalityLevelText, getWorkCenterStatusIcon, -} from "../../../utils/erp"; +} from '../../../utils/erp' +import { Container } from '@/components/shared' const WorkCenterCards: React.FC = () => { - const [searchTerm, setSearchTerm] = useState(""); - const [statusFilter, setStatusFilter] = useState< - WorkCenterStatusEnum | "all" - >("all"); - const [criticalityFilter, setCriticalityFilter] = useState< - CriticalityLevelEnum | "all" - >("all"); - const [showModal, setShowModal] = useState(false); - const [showViewModal, setShowViewModal] = useState(false); - const [showEditModal, setShowEditModal] = useState(false); - const [showMaintenancePlanModal, setShowMaintenancePlanModal] = - useState(false); - const [showStatusUpdateModal, setShowStatusUpdateModal] = useState(false); - const [editingWorkCenter, setEditingWorkCenter] = - useState(null); - const [viewingWorkCenter, setViewingWorkCenter] = - useState(null); - const [selectedWorkCenters, setSelectedWorkCenters] = useState([]); - const [workCenters, setWorkCenters] = - useState(mockWorkCenters); - const [viewMode, setViewMode] = useState<"cards" | "list">("cards"); + const [searchTerm, setSearchTerm] = useState('') + const [statusFilter, setStatusFilter] = useState('all') + const [criticalityFilter, setCriticalityFilter] = useState('all') + const [showModal, setShowModal] = useState(false) + const [showViewModal, setShowViewModal] = useState(false) + const [showEditModal, setShowEditModal] = useState(false) + const [showMaintenancePlanModal, setShowMaintenancePlanModal] = useState(false) + const [showStatusUpdateModal, setShowStatusUpdateModal] = useState(false) + const [editingWorkCenter, setEditingWorkCenter] = useState(null) + const [viewingWorkCenter, setViewingWorkCenter] = useState(null) + const [selectedWorkCenters, setSelectedWorkCenters] = useState([]) + const [workCenters, setWorkCenters] = useState(mockWorkCenters) + const [viewMode, setViewMode] = useState<'cards' | 'list'>('cards') const filteredWorkCenters = workCenters.filter((workCenter) => { const matchesSearch = workCenter.code.toLowerCase().includes(searchTerm.toLowerCase()) || workCenter.name.toLowerCase().includes(searchTerm.toLowerCase()) || - workCenter.manufacturer - ?.toLowerCase() - .includes(searchTerm.toLowerCase()) || - workCenter.location.toLowerCase().includes(searchTerm.toLowerCase()); - const matchesStatus = - statusFilter === "all" || workCenter.status === statusFilter; + workCenter.manufacturer?.toLowerCase().includes(searchTerm.toLowerCase()) || + workCenter.location.toLowerCase().includes(searchTerm.toLowerCase()) + const matchesStatus = statusFilter === 'all' || workCenter.status === statusFilter const matchesCriticality = - criticalityFilter === "all" || - workCenter.criticality === criticalityFilter; - return matchesSearch && matchesStatus && matchesCriticality; - }); + criticalityFilter === 'all' || workCenter.criticality === criticalityFilter + return matchesSearch && matchesStatus && matchesCriticality + }) const isWarrantyExpiring = (workCenter: PmWorkCenter) => { - if (!workCenter.warrantyExpiry) return false; - const today = new Date(); - const diffTime = workCenter.warrantyExpiry.getTime() - today.getTime(); - const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); - return diffDays <= 90 && diffDays > 0; - }; + if (!workCenter.warrantyExpiry) return false + const today = new Date() + const diffTime = workCenter.warrantyExpiry.getTime() - today.getTime() + const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + return diffDays <= 90 && diffDays > 0 + } const isWarrantyExpired = (workCenter: PmWorkCenter) => { - if (!workCenter.warrantyExpiry) return false; - const today = new Date(); - return workCenter.warrantyExpiry < today; - }; + if (!workCenter.warrantyExpiry) return false + const today = new Date() + return workCenter.warrantyExpiry < today + } const handleAddWorkCenter = () => { - setEditingWorkCenter(null); - setShowModal(true); - }; + setEditingWorkCenter(null) + setShowModal(true) + } const handleView = (workCenter: PmWorkCenter) => { - setViewingWorkCenter(workCenter); - setShowViewModal(true); - }; + setViewingWorkCenter(workCenter) + setShowViewModal(true) + } const handleEdit = (workCenter: PmWorkCenter) => { - setEditingWorkCenter(workCenter); - setShowEditModal(true); - }; + setEditingWorkCenter(workCenter) + setShowEditModal(true) + } const handleSaveNewWorkCenter = (workCenter: Partial) => { const newWorkCenter: PmWorkCenter = { @@ -109,599 +98,536 @@ const WorkCenterCards: React.FC = () => { id: `EQP${Date.now()}`, creationTime: new Date(), lastModificationTime: new Date(), - } as PmWorkCenter; - setWorkCenters([...workCenters, newWorkCenter]); - }; + } as PmWorkCenter + setWorkCenters([...workCenters, newWorkCenter]) + } const handleSaveEditWorkCenter = (workCenter: PmWorkCenter) => { - setWorkCenters( - workCenters.map((eq) => (eq.id === workCenter.id ? workCenter : eq)) - ); - }; + setWorkCenters(workCenters.map((eq) => (eq.id === workCenter.id ? workCenter : eq))) + } const handleCreateMaintenancePlan = (plans: PmMaintenancePlan[]) => { // In a real app, this would save to the backend - console.log("Creating maintenance plans:", plans); - alert(`${plans.length} bakım planı oluşturuldu!`); - setSelectedWorkCenters([]); - }; + console.log('Creating maintenance plans:', plans) + alert(`${plans.length} bakım planı oluşturuldu!`) + setSelectedWorkCenters([]) + } const handleUpdateStatus = (updatedWorkCenters: PmWorkCenter[]) => { // Update work centers in state - const updatedIds = updatedWorkCenters.map((eq) => eq.id); + const updatedIds = updatedWorkCenters.map((eq) => eq.id) setWorkCenters( workCenters.map((eq) => updatedIds.includes(eq.id) ? updatedWorkCenters.find((updated) => updated.id === eq.id) || eq - : eq - ) - ); - setSelectedWorkCenters([]); - alert(`${updatedWorkCenters.length} iş merkezinin durumu güncellendi!`); - }; + : eq, + ), + ) + setSelectedWorkCenters([]) + alert(`${updatedWorkCenters.length} iş merkezinin durumu güncellendi!`) + } const getSelectedWorkCenterObjects = () => { - return workCenters.filter((eq) => selectedWorkCenters.includes(eq.id)); - }; + return workCenters.filter((eq) => selectedWorkCenters.includes(eq.id)) + } const handleSelectWorkCenter = (workCenterId: string) => { setSelectedWorkCenters((prev) => prev.includes(workCenterId) ? prev.filter((id) => id !== workCenterId) - : [...prev, workCenterId] - ); - }; + : [...prev, workCenterId], + ) + } const getWorkCenterAge = (installationDate: Date) => { - const today = new Date(); - const diffTime = today.getTime() - installationDate.getTime(); - const diffYears = Math.floor(diffTime / (1000 * 60 * 60 * 24 * 365)); - return diffYears; - }; + const today = new Date() + const diffTime = today.getTime() - installationDate.getTime() + const diffYears = Math.floor(diffTime / (1000 * 60 * 60 * 24 * 365)) + return diffYears + } return ( -
- {/* Header */} -
-
-

İş Merkezleri

-

- Tüm iş merkezlerini yönetin ve takip edin -

-
-
- {/* View Toggle */} -
+ +
+ {/* Header */} +
+
+

İş Merkezleri

+

Tüm iş merkezlerini yönetin ve takip edin

+
+
+ {/* View Toggle */} +
+ + +
+ -
- -
-
- {/* Summary Cards */} -
- + {/* Summary Cards */} +
+ - e.status === WorkCenterStatusEnum.Operational - ).length - } - color="green" - icon="FaCheckCircle" - /> + e.status === WorkCenterStatusEnum.Operational).length} + color="green" + icon="FaCheckCircle" + /> - e.status === WorkCenterStatusEnum.OutOfOrder - ).length - } - color="red" - icon="FaExclamationTriangle" - /> + e.status === WorkCenterStatusEnum.OutOfOrder).length} + color="red" + icon="FaExclamationTriangle" + /> - e.status === WorkCenterStatusEnum.UnderMaintenance - ).length - } - color="orange" - icon="FaWrench" - /> -
- - {/* Filters */} -
-
- - setSearchTerm(e.target.value)} - className="w-full pl-9 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" + e.status === WorkCenterStatusEnum.UnderMaintenance).length + } + color="orange" + icon="FaWrench" />
-
- - -
-
- -
-
- {/* Work Center Content */} - {viewMode === "cards" ? ( - /* Work Center Cards */ -
- {filteredWorkCenters.map((workCenter) => ( -
+
+ + setSearchTerm(e.target.value)} + className="w-full pl-9 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" + /> +
+
+ + handleSelectWorkCenter(workCenter.id)} - className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" - /> -

- {workCenter.code} -

- - {getWorkCenterStatusIcon(workCenter.status)} - {getWorkCenterStatusText(workCenter.status)} - -
-

- {workCenter.name} -

-

- {workCenter.description} -

-
-
- - - -
-
- -
-
-
- Marka/Model -

- {workCenter.manufacturer} {workCenter.model} -

-
-
- Seri No -

- {workCenter.serialNumber} -

-
-
- Konum -

- - {workCenter.location} -

-
-
- Yaş -

- {getWorkCenterAge(workCenter.installationDate)} yıl -

-
-
- -
- - {getCriticalityLevelText(workCenter.criticality)} Kritiklik - - - {workCenter.workCenterType?.name} - -
- - {workCenter.warrantyExpiry && ( -
-
- Garanti - - {workCenter.warrantyExpiry.toLocaleDateString("tr-TR")} - {isWarrantyExpiring(workCenter) && - !isWarrantyExpired(workCenter) && ( - - (Yakında) - - )} - {isWarrantyExpired(workCenter) && ( - - (Doldu) - - )} - -
-
- )} -
- - {/* Specifications Preview */} - {workCenter.specifications.length > 0 && ( -
-
- Teknik Özellikler -
-
- {workCenter.specifications.slice(0, 4).map((spec) => ( -
- - {spec.specificationName}: - - - {spec.specificationValue} {spec.unit} - -
- ))} - {workCenter.specifications.length > 4 && ( -
- - +{workCenter.specifications.length - 4} daha... - -
- )} -
-
- )} - -
-
-
- - - Kurulum:{" "} - {workCenter.installationDate.toLocaleDateString("tr-TR")} - -
-
- - - Son Güncelleme:{" "} - {workCenter.lastModificationTime.toLocaleDateString( - "tr-TR" - )} - -
-
-
-
- ))} + + + + + + +
+
+ +
- ) : ( - /* List View */ -
-
- - - - - - - - - - - - - - - {filteredWorkCenters.map((workCenter) => ( - - - - - - - - - - - ))} - -
- 0 - } - onChange={(e) => { - if (e.target.checked) { - setSelectedWorkCenters( - filteredWorkCenters.map((eq) => eq.id) - ); - } else { - setSelectedWorkCenters([]); - } - }} - className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" - /> - - İş Merkezi - - Durum - - Kritiklik - - Konum - - Yaş - - Garanti - - İşlemler -
+ + {/* Work Center Content */} + {viewMode === 'cards' ? ( + /* Work Center Cards */ +
+ {filteredWorkCenters.map((workCenter) => ( +
+
+
+
handleSelectWorkCenter(workCenter.id)} className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" /> -
-
-
-
- -
-
-
-
- {workCenter.code} -
-
- {workCenter.name} -
-
- {workCenter.manufacturer} {workCenter.model} -
-
-
-
+

{workCenter.code}

{getWorkCenterStatusIcon(workCenter.status)} - - {getWorkCenterStatusText(workCenter.status)} - + {getWorkCenterStatusText(workCenter.status)} -
- - {getCriticalityLevelText(workCenter.criticality)} - - -
- +
+

{workCenter.name}

+

{workCenter.description}

+ +
+ + + +
+ + +
+
+
+ Marka/Model +

+ {workCenter.manufacturer} {workCenter.model} +

+
+
+ Seri No +

{workCenter.serialNumber}

+
+
+ Konum +

+ {workCenter.location} -

-
- {getWorkCenterAge(workCenter.installationDate)} yıl - - {workCenter.warrantyExpiry ? ( +

+ +
+ Yaş +

+ {getWorkCenterAge(workCenter.installationDate)} yıl +

+
+ + +
+ + {getCriticalityLevelText(workCenter.criticality)} Kritiklik + + {workCenter.workCenterType?.name} +
+ + {workCenter.warrantyExpiry && ( +
+
+ Garanti - {workCenter.warrantyExpiry.toLocaleDateString( - "tr-TR" + {workCenter.warrantyExpiry.toLocaleDateString('tr-TR')} + {isWarrantyExpiring(workCenter) && !isWarrantyExpired(workCenter) && ( + (Yakında) )} - {isWarrantyExpiring(workCenter) && - !isWarrantyExpired(workCenter) && ( -
- Yakında dolacak -
- )} {isWarrantyExpired(workCenter) && ( -
Dolmuş
+ (Doldu) )}
- ) : ( - - - )} -
-
- - -
-
+
+ )} +
+ + {/* Specifications Preview */} + {workCenter.specifications.length > 0 && ( +
+
Teknik Özellikler
+
+ {workCenter.specifications.slice(0, 4).map((spec) => ( +
+ {spec.specificationName}: + + {spec.specificationValue} {spec.unit} + +
+ ))} + {workCenter.specifications.length > 4 && ( +
+ + +{workCenter.specifications.length - 4} daha... + +
+ )} +
+
+ )} + +
+
+
+ + + Kurulum: {workCenter.installationDate.toLocaleDateString('tr-TR')} + +
+
+ + + Son Güncelleme:{' '} + {workCenter.lastModificationTime.toLocaleDateString('tr-TR')} + +
+
+
+
+ ))}
-
- )} - - {filteredWorkCenters.length === 0 && ( -
- -

- İş Merkezi bulunamadı -

-

- Arama kriterlerinizi değiştirin veya yeni bir iş merkezi ekleyin. -

- -
- )} - - {/* Bulk Actions */} - {selectedWorkCenters.length > 0 && ( -
-
- - {selectedWorkCenters.length} iş merkezi seçildi - -
- - - + ) : ( + /* List View */ +
+
+ + + + + + + + + + + + + + + {filteredWorkCenters.map((workCenter) => ( + + + + + + + + + + + ))} + +
+ 0 + } + onChange={(e) => { + if (e.target.checked) { + setSelectedWorkCenters(filteredWorkCenters.map((eq) => eq.id)) + } else { + setSelectedWorkCenters([]) + } + }} + className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" + /> + + İş Merkezi + + Durum + + Kritiklik + + Konum + + Yaş + + Garanti + + İşlemler +
+ handleSelectWorkCenter(workCenter.id)} + className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" + /> + +
+
+
+ +
+
+
+
+ {workCenter.code} +
+
{workCenter.name}
+
+ {workCenter.manufacturer} {workCenter.model} +
+
+
+
+ + {getWorkCenterStatusIcon(workCenter.status)} + {getWorkCenterStatusText(workCenter.status)} + + + + {getCriticalityLevelText(workCenter.criticality)} + + +
+ + {workCenter.location} +
+
+ {getWorkCenterAge(workCenter.installationDate)} yıl + + {workCenter.warrantyExpiry ? ( + + {workCenter.warrantyExpiry.toLocaleDateString('tr-TR')} + {isWarrantyExpiring(workCenter) && !isWarrantyExpired(workCenter) && ( +
Yakında dolacak
+ )} + {isWarrantyExpired(workCenter) && ( +
Dolmuş
+ )} +
+ ) : ( + - + )} +
+
+ + + +
+
-
- )} + )} + + {filteredWorkCenters.length === 0 && ( +
+ +

İş Merkezi bulunamadı

+

+ Arama kriterlerinizi değiştirin veya yeni bir iş merkezi ekleyin. +

+ +
+ )} + + {/* Bulk Actions */} + {selectedWorkCenters.length > 0 && ( +
+
+ + {selectedWorkCenters.length} iş merkezi seçildi + +
+ + + +
+
+
+ )} +
{/* Modal for Add/Edit */} { onSave={handleUpdateStatus} selectedWorkCenters={getSelectedWorkCenterObjects()} /> -
- ); -}; + + ) +} -export default WorkCenterCards; +export default WorkCenterCards diff --git a/ui/src/views/maintenance/components/WorkCenterForm.tsx b/ui/src/views/maintenance/components/WorkCenterForm.tsx index 62672c4d..f4770277 100644 --- a/ui/src/views/maintenance/components/WorkCenterForm.tsx +++ b/ui/src/views/maintenance/components/WorkCenterForm.tsx @@ -224,7 +224,7 @@ const WorkCenterForm: React.FC = () => { } return ( -
+
{/* Header */}
diff --git a/ui/src/views/maintenance/components/WorkCenterList.tsx b/ui/src/views/maintenance/components/WorkCenterList.tsx index 83cf855f..62f4e569 100644 --- a/ui/src/views/maintenance/components/WorkCenterList.tsx +++ b/ui/src/views/maintenance/components/WorkCenterList.tsx @@ -27,6 +27,7 @@ import { getCriticalityLevelColor, getCriticalityLevelText, } from '../../../utils/erp' +import { Container } from '@/components/shared' const WorkCenterList: React.FC = () => { const [searchTerm, setSearchTerm] = useState('') @@ -75,330 +76,332 @@ const WorkCenterList: React.FC = () => { } return ( -
- {/* Header Actions */} -
-
-
- - setSearchTerm(e.target.value)} - className="pl-10 pr-4 py-1.5 text-sm w-80 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> + +
+ {/* Header Actions */} +
+
+
+ + setSearchTerm(e.target.value)} + className="pl-10 pr-4 py-1.5 text-sm w-80 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" + /> +
+ +
- -
+
+ -
- - - - - Yeni İş Merkezi - -
-
- - {/* Filters Panel */} - {showFilters && ( -
-
-
- - -
- -
- - -
- -
- -
-
-
- )} - - {/* Statistics Cards */} -
-
-
-
-

Toplam İş Merkezi

-

{workCenter?.length || 0}

-
- + + + Yeni İş Merkezi +
-
-
-
-

Operasyonel

-

- {workCenter?.filter((e) => e.status === WorkCenterStatusEnum.Operational).length || - 0} -

-
- -
-
+ {/* Filters Panel */} + {showFilters && ( +
+
+
+ + +
-
-
-
-

Bakımda

-

- {workCenter?.filter((e) => e.status === WorkCenterStatusEnum.UnderMaintenance) - .length || 0} -

-
- -
-
+
+ + +
-
-
-
-

Kritik İş Merkezi

-

- {workCenter?.filter((e) => e.criticality === CriticalityLevelEnum.Critical) - .length || 0} -

-
- -
-
-
- - {/* WorkCenter Table */} -
-
-

WorkCenter Listesi

-
- -
- - - - - - - - - - - - - - - {workCenter?.map((eq) => ( - - - - - - - - - - - - - - - - ))} - -
- İş Merkezi Bilgileri - - Üretici / Model - - Lokasyon / Departman - - Durum / Kritiklik - - Kurulum / Garanti - - Performans - - İşlemler -
-
-
-
- -
-
-
-
{eq.code}
-
{eq.name}
- {eq.serialNumber && ( -
S/N: {eq.serialNumber}
- )} -
-
-
-
-
- {eq.manufacturer || '-'} -
-
{eq.model || '-'}
-
{eq.workCenterType?.name}
-
-
-
-
{eq.location}
-
{eq.departmentId}
-
-
-
- - {getWorkCenterStatusIcon(eq.status)} - {getWorkCenterStatusText(eq.status)} - -
- {getCriticalityLevelText(eq.criticality)} -
-
-
-
-
- - {dayjs(eq.installationDate).format('DD.MM.YYYY')} -
- {eq.warrantyExpiry && ( -
- Garanti: {dayjs(eq.warrantyExpiry).format('DD.MM.YYYY')} -
- )} -
-
-
-
- - 98.5% Uptime -
-
- - Verimli -
-
-
-
- - - - - - - - - -
-
-
- - {(!workCenter || workCenter.length === 0) && ( -
- -

İş Merkezi bulunamadı

-

Yeni iş merkezi ekleyerek başlayın.

-
- - - Yeni İş Merkezi Ekle - +
+ +
)} + + {/* Statistics Cards */} +
+
+
+
+

Toplam İş Merkezi

+

{workCenter?.length || 0}

+
+ +
+
+ +
+
+
+

Operasyonel

+

+ {workCenter?.filter((e) => e.status === WorkCenterStatusEnum.Operational) + .length || 0} +

+
+ +
+
+ +
+
+
+

Bakımda

+

+ {workCenter?.filter((e) => e.status === WorkCenterStatusEnum.UnderMaintenance) + .length || 0} +

+
+ +
+
+ +
+
+
+

Kritik İş Merkezi

+

+ {workCenter?.filter((e) => e.criticality === CriticalityLevelEnum.Critical) + .length || 0} +

+
+ +
+
+
+ + {/* WorkCenter Table */} +
+
+

WorkCenter Listesi

+
+ +
+ + + + + + + + + + + + + + + {workCenter?.map((eq) => ( + + + + + + + + + + + + + + + + ))} + +
+ İş Merkezi Bilgileri + + Üretici / Model + + Lokasyon / Departman + + Durum / Kritiklik + + Kurulum / Garanti + + Performans + + İşlemler +
+
+
+
+ +
+
+
+
{eq.code}
+
{eq.name}
+ {eq.serialNumber && ( +
S/N: {eq.serialNumber}
+ )} +
+
+
+
+
+ {eq.manufacturer || '-'} +
+
{eq.model || '-'}
+
{eq.workCenterType?.name}
+
+
+
+
{eq.location}
+
{eq.departmentId}
+
+
+
+ + {getWorkCenterStatusIcon(eq.status)} + {getWorkCenterStatusText(eq.status)} + +
+ {getCriticalityLevelText(eq.criticality)} +
+
+
+
+
+ + {dayjs(eq.installationDate).format('DD.MM.YYYY')} +
+ {eq.warrantyExpiry && ( +
+ Garanti: {dayjs(eq.warrantyExpiry).format('DD.MM.YYYY')} +
+ )} +
+
+
+
+ + 98.5% Uptime +
+
+ + Verimli +
+
+
+
+ + + + + + + + + +
+
+
+ + {(!workCenter || workCenter.length === 0) && ( +
+ +

İş Merkezi bulunamadı

+

Yeni iş merkezi ekleyerek başlayın.

+
+ + + Yeni İş Merkezi Ekle + +
+
+ )} +
-
+ ) } diff --git a/ui/src/views/mrp/MRPManagement.tsx b/ui/src/views/mrp/MRPManagement.tsx deleted file mode 100644 index 9e2a93b4..00000000 --- a/ui/src/views/mrp/MRPManagement.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from "react"; -import { Outlet, useLocation } from "react-router-dom"; -import ModuleHeader from "../../components/common/ModuleHeader"; - -const MRPManagement: React.FC = () => { - const location = useLocation(); - - // Define page mappings for breadcrumbs - const getPageTitle = (pathname: string) => { - if (pathname === "/admin/mrp/operation-types") return "Operasyon Türleri"; - if (pathname === "/admin/mrp/workcenters") return "İş Merkezleri"; - if (pathname === "/admin/mrp/operations") return "Operasyon Tanımları"; - if (pathname === "/admin/mrp/bom") return "Ürün Ağaçları (BOM)"; - if (pathname === "/admin/mrp/production-orders") return "Üretim Emirleri"; - if (pathname === "/admin/mrp/work-orders") return "İş Emirleri"; - if (pathname === "/admin/mrp/demand-planning") return "Talep Planlama"; - if (pathname === "/admin/mrp/material-requirements") return "Malzeme İhtiyaçları"; - if (pathname === "/admin/mrp/planning-gantt") return "Planlama Gantt"; - return "MRP Yönetimi"; - }; - - const pageTitle = getPageTitle(location.pathname); - - // Create breadcrumbs: Anasayfa / MRP Yönetimi / Sayfanın Adı - const breadcrumbs = [{ name: "MRP Yönetimi", href: "/admin/mrp" }]; - - return ( -
- - -
- -
-
- ); -}; - -export default MRPManagement; diff --git a/ui/src/views/mrp/components/BOMManagement.tsx b/ui/src/views/mrp/components/BOMManagement.tsx index 474b033f..b1595f29 100644 --- a/ui/src/views/mrp/components/BOMManagement.tsx +++ b/ui/src/views/mrp/components/BOMManagement.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState } from 'react' import { FaPlus, FaSearch, @@ -10,347 +10,325 @@ import { FaCopy, FaExclamationTriangle, FaClock, -} from "react-icons/fa"; -import { MrpBOM, MrpBOMComponent, MrpBOMOperation } from "../../../types/mrp"; -import BOMFormModal from "./BOMFormModal"; -import { getBOMTypeColor, getBOMTypeName } from "../../../utils/erp"; -import { mockBOMs } from "../../../mocks/mockBOMs"; +} from 'react-icons/fa' +import { MrpBOM, MrpBOMComponent, MrpBOMOperation } from '../../../types/mrp' +import BOMFormModal from './BOMFormModal' +import { getBOMTypeColor, getBOMTypeName } from '../../../utils/erp' +import { mockBOMs } from '../../../mocks/mockBOMs' +import { Container } from '@/components/shared' const BOMManagement: React.FC = () => { - const [searchTerm, setSearchTerm] = useState(""); - const [showModal, setShowModal] = useState(false); - const [editingBOM, setEditingBOM] = useState(null); - const [selectedBOM, setSelectedBOM] = useState(null); + const [searchTerm, setSearchTerm] = useState('') + const [showModal, setShowModal] = useState(false) + const [editingBOM, setEditingBOM] = useState(null) + const [selectedBOM, setSelectedBOM] = useState(null) // Mock data - replace with actual API calls - const [boms, setBoms] = useState(mockBOMs); + const [boms, setBoms] = useState(mockBOMs) const filteredBOMs = boms.filter( (bom) => bom.bomCode.toLowerCase().includes(searchTerm.toLowerCase()) || bom.materialId.toLowerCase().includes(searchTerm.toLowerCase()) || - bom.version.toLowerCase().includes(searchTerm.toLowerCase()) - ); + bom.version.toLowerCase().includes(searchTerm.toLowerCase()), + ) const getTotalOperationTime = (operations: MrpBOMOperation[]) => { - return operations.reduce( - (total, op) => total + op.setupTime + op.runTime, - 0 - ); - }; + return operations.reduce((total, op) => total + op.setupTime + op.runTime, 0) + } const getTotalComponents = (components: MrpBOMComponent[]) => { - return components.length; - }; + return components.length + } const getActiveComponents = (components: MrpBOMComponent[]) => { - return components.filter((comp) => comp.isActive).length; - }; + return components.filter((comp) => comp.isActive).length + } const handleEdit = (bom: MrpBOM) => { - setEditingBOM(bom); - setShowModal(true); - }; + setEditingBOM(bom) + setShowModal(true) + } const handleAddNew = () => { - setEditingBOM(null); - setShowModal(true); - }; + setEditingBOM(null) + setShowModal(true) + } const handleViewDetails = (bom: MrpBOM) => { - setSelectedBOM(bom); + setSelectedBOM(bom) - console.log(bom); - }; + console.log(bom) + } const handleCopy = (bom: MrpBOM) => { - console.log("Copying BOM:", bom.bomCode); + console.log('Copying BOM:', bom.bomCode) // Implementation for copying BOM - }; + } const handleSave = (bom: MrpBOM) => { setBoms((prev) => { - const existing = prev.find((b) => b.id === bom.id); - if (existing) return prev.map((b) => (b.id === bom.id ? bom : b)); - return [...prev, { ...bom, id: bom.id || String(Date.now()) }]; - }); - setShowModal(false); - }; + const existing = prev.find((b) => b.id === bom.id) + if (existing) return prev.map((b) => (b.id === bom.id ? bom : b)) + return [...prev, { ...bom, id: bom.id || String(Date.now()) }] + }) + setShowModal(false) + } return ( -
- {/* Header */} -
-
-

- Ürün Ağaçları (BOM) -

-

- Ürün bileşenlerini ve üretim operasyonlarını yönetin -

+ +
+ {/* Header */} +
+
+

Ürün Ağaçları (BOM)

+

+ Ürün bileşenlerini ve üretim operasyonlarını yönetin +

+
+
- -
- {/* Search Bar */} -
- - setSearchTerm(e.target.value)} - className="w-full pl-10 pr-4 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" - /> -
+ {/* Search Bar */} +
+ + setSearchTerm(e.target.value)} + className="w-full pl-10 pr-4 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" + /> +
-
- {/* BOM List */} -
-

BOM Listesi

- {filteredBOMs.map((bom) => ( -
-
-
-
- -

- {bom.bomCode} -

+
+ {/* BOM List */} +
+

BOM Listesi

+ {filteredBOMs.map((bom) => ( +
+
+
+
+ +

{bom.bomCode}

+ + {getBOMTypeName(bom.bomType)} + +
+

+ Malzeme: {bom.material?.code} - {bom.material?.name} - v{bom.version} +

+

Temel Miktar: {bom.baseQuantity}

+
+
+ + + + +
+
+ +
+
+ + + Bileşenler + + + {getActiveComponents(bom.components)}/{getTotalComponents(bom.components)} + +
+
+ + + Toplam Süre + + {getTotalOperationTime(bom.operations)} dk +
+
+ Geçerlilik + {bom.validFrom.toLocaleDateString('tr-TR')} +
+
+ + {/* Status and Warnings */} +
+
- {getBOMTypeName(bom.bomType)} + {bom.isActive ? 'Aktif' : 'Pasif'} + {bom.validTo && new Date() > bom.validTo && ( + + + Süresi Dolmuş + + )}
-

- Malzeme: {bom.material?.code} - {bom.material?.name} - v - {bom.version} -

-

- Temel Miktar: {bom.baseQuantity} -

-
-
- - - - + + {bom.lastModificationTime.toLocaleDateString('tr-TR')} +
+ ))} -
-
- + {filteredBOMs.length === 0 && ( +
+ +

BOM bulunamadı

+

+ Arama kriterlerinizi değiştirin veya yeni bir BOM ekleyin. +

+
+ )} +
+ + {/* BOM Details */} +
+

BOM Detayları

+ {selectedBOM ? ( +
+
+

{selectedBOM.bomCode}

+
+
+ Malzeme: {selectedBOM.material?.code} - {selectedBOM.material?.name} +
+
Versiyon: {selectedBOM.version}
+
Tip: {getBOMTypeName(selectedBOM.bomType)}
+
Temel Miktar: {selectedBOM.baseQuantity}
+
+
+ + {/* Components */} +
+
- Bileşenler - - - {getActiveComponents(bom.components)}/ - {getTotalComponents(bom.components)} - -
-
- - - Toplam Süre - - - {getTotalOperationTime(bom.operations)} dk - -
-
- Geçerlilik - - {bom.validFrom.toLocaleDateString("tr-TR")} - -
-
- - {/* Status and Warnings */} -
-
- - {bom.isActive ? "Aktif" : "Pasif"} - - {bom.validTo && new Date() > bom.validTo && ( - - - Süresi Dolmuş - - )} -
- - {bom.lastModificationTime.toLocaleDateString("tr-TR")} - -
-
- ))} - - {filteredBOMs.length === 0 && ( -
- -

- BOM bulunamadı -

-

- Arama kriterlerinizi değiştirin veya yeni bir BOM ekleyin. -

-
- )} -
- - {/* BOM Details */} -
-

BOM Detayları

- {selectedBOM ? ( -
-
-

- {selectedBOM.bomCode} -

-
-
- Malzeme: {selectedBOM.material?.code} -{" "} - {selectedBOM.material?.name} -
-
Versiyon: {selectedBOM.version}
-
Tip: {getBOMTypeName(selectedBOM.bomType)}
-
Temel Miktar: {selectedBOM.baseQuantity}
-
-
- - {/* Components */} -
-
- - Bileşenler ({selectedBOM.components.length}) -
-
- {selectedBOM.components.map((component) => ( -
-
- - {component.position}. {component.material?.code} -{" "} - {component.material?.name} - -
- {component.isPhantom && ( - - Phantom - - )} - - {component.isActive ? "Aktif" : "Pasif"} + Bileşenler ({selectedBOM.components.length}) + +
+ {selectedBOM.components.map((component) => ( +
+
+ + {component.position}. {component.material?.code} -{' '} + {component.material?.name} +
+ {component.isPhantom && ( + + Phantom + + )} + + {component.isActive ? 'Aktif' : 'Pasif'} + +
+
+
+ Miktar: {component.quantity} {component.unitId} | Fire: % + {component.scrapPercentage}
-
- Miktar: {component.quantity} {component.unitId} | Fire: - %{component.scrapPercentage} -
-
- ))} + ))} +
-
- {/* Operations */} -
-
- - Operasyonlar ({selectedBOM.operations.length}) -
-
- {selectedBOM.operations.map((operation) => ( -
-
- - {operation.sequence}. {operation.operation?.code} -{" "} - {operation.operation?.name} - - - {operation.isActive ? "Aktif" : "Pasif"} - + {/* Operations */} +
+
+ + Operasyonlar ({selectedBOM.operations.length}) +
+
+ {selectedBOM.operations.map((operation) => ( +
+
+ + {operation.sequence}. {operation.operation?.code} -{' '} + {operation.operation?.name} + + + {operation.isActive ? 'Aktif' : 'Pasif'} + +
+
+ Hazırlık: {operation.setupTime}dk | İşlem: {operation.runTime}dk | Kuyruk:{' '} + {operation.queueTime}dk | Taşıma: {operation.moveTime}dk +
-
- Hazırlık: {operation.setupTime}dk | İşlem:{" "} - {operation.runTime}dk | Kuyruk: {operation.queueTime}dk - | Taşıma: {operation.moveTime}dk -
-
- ))} + ))} +
-
- ) : ( -
- -

- BOM Detaylarını Görüntüle -

-

- Detaylarını görmek için sol taraftan bir BOM seçin. -

-
- )} + ) : ( +
+ +

+ BOM Detaylarını Görüntüle +

+

Detaylarını görmek için sol taraftan bir BOM seçin.

+
+ )} +
@@ -360,8 +338,8 @@ const BOMManagement: React.FC = () => { onSave={handleSave} onClose={() => setShowModal(false)} /> -
- ); -}; + + ) +} -export default BOMManagement; +export default BOMManagement diff --git a/ui/src/views/mrp/components/DemandPlanning.tsx b/ui/src/views/mrp/components/DemandPlanning.tsx index 7c0842a2..39c763b5 100644 --- a/ui/src/views/mrp/components/DemandPlanning.tsx +++ b/ui/src/views/mrp/components/DemandPlanning.tsx @@ -1,60 +1,43 @@ -import React, { useState } from "react"; -import { - FaArrowUp, - FaBullseye, - FaPlus, - FaEdit, - FaTrash, - FaCalculator, -} from "react-icons/fa"; +import React, { useState } from 'react' +import { FaArrowUp, FaBullseye, FaPlus, FaEdit, FaTrash, FaCalculator } from 'react-icons/fa' import { MrpDemandForecast, ForecastMethodEnum, MrpMaterialRequirement, RequirementSourceTypeEnum, -} from "../../../types/mrp"; -import DataTable, { Column } from "../../../components/common/DataTable"; -import { - mockDemandForecasts, - mockMaterialRequirements, -} from "../../../mocks/mockDemandPlanning"; -import { mockMaterials } from "../../../mocks/mockMaterials"; -import DemandForecastFormModal from "./DemandForecastFormModal"; -import MaterialRequirementFormModal from "./MaterialRequirementFormModal"; -import Widget from "../../../components/common/Widget"; +} from '../../../types/mrp' +import DataTable, { Column } from '../../../components/common/DataTable' +import { mockDemandForecasts, mockMaterialRequirements } from '../../../mocks/mockDemandPlanning' +import { mockMaterials } from '../../../mocks/mockMaterials' +import DemandForecastFormModal from './DemandForecastFormModal' +import MaterialRequirementFormModal from './MaterialRequirementFormModal' +import Widget from '../../../components/common/Widget' +import { Container } from '@/components/shared' const DemandPlanning: React.FC = () => { // Mock data - in a real app, this would come from a store/API - const [demandForecasts, setDemandForecasts] = - useState(mockDemandForecasts); - const [materialRequirements, setMaterialRequirements] = useState< - MrpMaterialRequirement[] - >(mockMaterialRequirements); - const [searchTerm, setSearchTerm] = useState(""); - const [selectedMethod, setSelectedMethod] = useState< - ForecastMethodEnum | "all" - >("all"); - const [activeTab, setActiveTab] = useState<"forecasts" | "requirements">( - "forecasts" - ); + const [demandForecasts, setDemandForecasts] = useState(mockDemandForecasts) + const [materialRequirements, setMaterialRequirements] = + useState(mockMaterialRequirements) + const [searchTerm, setSearchTerm] = useState('') + const [selectedMethod, setSelectedMethod] = useState('all') + const [activeTab, setActiveTab] = useState<'forecasts' | 'requirements'>('forecasts') // Modal state - const [isForecastModalOpen, setIsForecastModalOpen] = useState(false); - const [editingForecast, setEditingForecast] = - useState(null); - const [isRequirementModalOpen, setIsRequirementModalOpen] = useState(false); - const [editingRequirement, setEditingRequirement] = - useState(null); + const [isForecastModalOpen, setIsForecastModalOpen] = useState(false) + const [editingForecast, setEditingForecast] = useState(null) + const [isRequirementModalOpen, setIsRequirementModalOpen] = useState(false) + const [editingRequirement, setEditingRequirement] = useState(null) // Event handlers const handleAddForecast = () => { - console.log("Add forecast"); - setEditingForecast(null); - setIsForecastModalOpen(true); - }; + console.log('Add forecast') + setEditingForecast(null) + setIsForecastModalOpen(true) + } const handleSaveForecast = ( - forecastData: Omit & { id?: string } + forecastData: Omit & { id?: string }, ) => { if (editingForecast && forecastData.id) { // Update existing forecast @@ -63,10 +46,10 @@ const DemandPlanning: React.FC = () => { ...forecastData, material: mockMaterials.find((m) => m.id === forecastData.materialId), lastModificationTime: new Date(), - }; + } setDemandForecasts((prev) => - prev.map((f) => (f.id === forecastData.id ? updatedForecast : f)) - ); + prev.map((f) => (f.id === forecastData.id ? updatedForecast : f)), + ) } else { // Create new forecast const newForecast: MrpDemandForecast = { @@ -75,37 +58,37 @@ const DemandPlanning: React.FC = () => { material: mockMaterials.find((m) => m.id === forecastData.materialId), creationTime: new Date(), lastModificationTime: new Date(), - }; - setDemandForecasts((prev) => [...prev, newForecast]); + } + setDemandForecasts((prev) => [...prev, newForecast]) } - handleCloseModal(); - }; + handleCloseModal() + } const handleCloseModal = () => { - setIsForecastModalOpen(false); - setEditingForecast(null); - setIsRequirementModalOpen(false); - setEditingRequirement(null); - }; + setIsForecastModalOpen(false) + setEditingForecast(null) + setIsRequirementModalOpen(false) + setEditingRequirement(null) + } const handleEditForecast = (forecast: MrpDemandForecast) => { - console.log("Edit forecast:", forecast); - setEditingForecast(forecast); - setIsForecastModalOpen(true); - }; + console.log('Edit forecast:', forecast) + setEditingForecast(forecast) + setIsForecastModalOpen(true) + } const handleAddRequirement = () => { - setEditingRequirement(null); - setIsRequirementModalOpen(true); - }; + setEditingRequirement(null) + setIsRequirementModalOpen(true) + } const handleEditRequirement = (requirement: MrpMaterialRequirement) => { - setEditingRequirement(requirement); - setIsRequirementModalOpen(true); - }; + setEditingRequirement(requirement) + setIsRequirementModalOpen(true) + } const handleSaveRequirement = ( - reqData: Omit & { id?: string } + reqData: Omit & { id?: string }, ) => { if (editingRequirement && reqData.id) { // Update @@ -113,102 +96,90 @@ const DemandPlanning: React.FC = () => { ...editingRequirement, ...reqData, material: mockMaterials.find((m) => m.id === reqData.materialId), - }; - setMaterialRequirements((prev) => - prev.map((r) => (r.id === reqData.id ? updatedReq : r)) - ); + } + setMaterialRequirements((prev) => prev.map((r) => (r.id === reqData.id ? updatedReq : r))) } else { // Create const newReq: MrpMaterialRequirement = { ...reqData, id: `mr-${Date.now()}`, material: mockMaterials.find((m) => m.id === reqData.materialId), - }; - setMaterialRequirements((prev) => [...prev, newReq]); + } + setMaterialRequirements((prev) => [...prev, newReq]) } - handleCloseModal(); - }; + handleCloseModal() + } const handleDeleteForecast = (id: string) => { - console.log("Delete forecast:", id); - if (window.confirm("Bu tahmini silmek istediğinizden emin misiniz?")) { - setDemandForecasts((prev) => prev.filter((f) => f.id !== id)); + console.log('Delete forecast:', id) + if (window.confirm('Bu tahmini silmek istediğinizden emin misiniz?')) { + setDemandForecasts((prev) => prev.filter((f) => f.id !== id)) } - }; + } const handleDeleteRequirement = (id: string) => { - if ( - window.confirm( - "Bu malzeme ihtiyacını silmek istediğinizden emin misiniz?" - ) - ) { - setMaterialRequirements((prev) => prev.filter((r) => r.id !== id)); + if (window.confirm('Bu malzeme ihtiyacını silmek istediğinizden emin misiniz?')) { + setMaterialRequirements((prev) => prev.filter((r) => r.id !== id)) } - }; + } const handleCalculateDemand = () => { // Mock implementation to simulate calculating actual demand and accuracy if ( !window.confirm( - "Mevcut tahminler için gerçekleşen talep ve doğruluk oranları hesaplanacaktır. Bu işlem geri alınamaz. Devam etmek istiyor musunuz?" + 'Mevcut tahminler için gerçekleşen talep ve doğruluk oranları hesaplanacaktır. Bu işlem geri alınamaz. Devam etmek istiyor musunuz?', ) ) { - return; + return } setDemandForecasts((prevForecasts) => prevForecasts.map((forecast) => { // Simulate an actual quantity, e.g., +/- 20% of the forecast - const randomFactor = 0.8 + Math.random() * 0.4; // between 0.8 and 1.2 - const actualQuantity = Math.round( - forecast.forecastQuantity * randomFactor - ); + const randomFactor = 0.8 + Math.random() * 0.4 // between 0.8 and 1.2 + const actualQuantity = Math.round(forecast.forecastQuantity * randomFactor) // Calculate accuracy: 100 - |(actual - forecast) / forecast| * 100 const accuracy = forecast.forecastQuantity > 0 ? 100 - - (Math.abs(actualQuantity - forecast.forecastQuantity) / - forecast.forecastQuantity) * + (Math.abs(actualQuantity - forecast.forecastQuantity) / forecast.forecastQuantity) * 100 - : 0; + : 0 return { ...forecast, actualQuantity, accuracy: Math.max(0, accuracy), // Ensure accuracy is not negative lastModificationTime: new Date(), - }; - }) - ); - alert("Talep ve doğruluk oranları başarıyla hesaplandı!"); - }; + } + }), + ) + alert('Talep ve doğruluk oranları başarıyla hesaplandı!') + } const handleGenerateRequirements = () => { if ( !window.confirm( - "Mevcut tahminlerden yeni malzeme ihtiyaçları oluşturulacaktır. Devam etmek istiyor musunuz?" + 'Mevcut tahminlerden yeni malzeme ihtiyaçları oluşturulacaktır. Devam etmek istiyor musunuz?', ) ) { - return; + return } const newRequirements: MrpMaterialRequirement[] = demandForecasts .filter( - (forecast) => - !materialRequirements.some( - (req) => req.sourceDocumentId === forecast.id - ) + (forecast) => !materialRequirements.some((req) => req.sourceDocumentId === forecast.id), ) // Henüz ihtiyacı oluşturulmamış olanları filtrele .map((forecast, index) => { - const grossRequirement = forecast.forecastQuantity; + const grossRequirement = forecast.forecastQuantity // Mock projected available stock and scheduled receipts - const projectedAvailable = Math.round(Math.random() * 500); - const scheduledReceipts = Math.round(Math.random() * 200); + const projectedAvailable = Math.round(Math.random() * 500) + const scheduledReceipts = Math.round(Math.random() * 200) const netRequirement = Math.max( 0, - grossRequirement - projectedAvailable - scheduledReceipts - ); + grossRequirement - projectedAvailable - scheduledReceipts, + ) return { id: `mr-${Date.now()}-${index}-${forecast.materialId}`, @@ -226,127 +197,111 @@ const DemandPlanning: React.FC = () => { requirementDate: forecast.startDate, plannedReceiptDate: forecast.startDate, plannedReleaseDate: new Date( - new Date(forecast.startDate).setDate( - forecast.startDate.getDate() - 14 - ) + new Date(forecast.startDate).setDate(forecast.startDate.getDate() - 14), ), // 2 hafta önce creationTime: new Date(), lastModificationTime: new Date(), - }; - }); + } + }) if (newRequirements.length > 0) { - setMaterialRequirements((prev) => [...prev, ...newRequirements]); - alert( - `${newRequirements.length} adet yeni malzeme ihtiyacı başarıyla oluşturuldu!` - ); - setActiveTab("requirements"); // Kullanıcının sonucu görmesi için sekmeyi değiştir + setMaterialRequirements((prev) => [...prev, ...newRequirements]) + alert(`${newRequirements.length} adet yeni malzeme ihtiyacı başarıyla oluşturuldu!`) + setActiveTab('requirements') // Kullanıcının sonucu görmesi için sekmeyi değiştir } else { alert( - "Mevcut tahminler için zaten malzeme ihtiyaçları oluşturulmuş veya yeni tahmin bulunmuyor." - ); + 'Mevcut tahminler için zaten malzeme ihtiyaçları oluşturulmuş veya yeni tahmin bulunmuyor.', + ) } - }; + } const filteredForecasts = demandForecasts.filter((forecast) => { if ( searchTerm && - !forecast.material?.name - ?.toLowerCase() - .includes(searchTerm.toLowerCase()) && + !forecast.material?.name?.toLowerCase().includes(searchTerm.toLowerCase()) && !forecast.forecastPeriod.toLowerCase().includes(searchTerm.toLowerCase()) ) { - return false; + return false } - if ( - selectedMethod !== "all" && - forecast.forecastMethod !== selectedMethod - ) { - return false; + if (selectedMethod !== 'all' && forecast.forecastMethod !== selectedMethod) { + return false } - return true; - }); + return true + }) const filteredRequirements = materialRequirements.filter((req) => { - if ( - searchTerm && - !req.material?.name?.toLowerCase().includes(searchTerm.toLowerCase()) - ) { - return false; + if (searchTerm && !req.material?.name?.toLowerCase().includes(searchTerm.toLowerCase())) { + return false } - return true; - }); + return true + }) const getMethodLabel = (method: ForecastMethodEnum) => { const methodLabels = { - [ForecastMethodEnum.MovingAverage]: "Hareketli Ortalama", - [ForecastMethodEnum.ExponentialSmoothing]: "Üstel Yumuşatma", - [ForecastMethodEnum.LinearRegression]: "Doğrusal Regresyon", - [ForecastMethodEnum.Seasonal]: "Mevsimsel", - }; - return methodLabels[method]; - }; + [ForecastMethodEnum.MovingAverage]: 'Hareketli Ortalama', + [ForecastMethodEnum.ExponentialSmoothing]: 'Üstel Yumuşatma', + [ForecastMethodEnum.LinearRegression]: 'Doğrusal Regresyon', + [ForecastMethodEnum.Seasonal]: 'Mevsimsel', + } + return methodLabels[method] + } const getSourceTypeLabel = (sourceType: RequirementSourceTypeEnum) => { const sourceLabels = { - [RequirementSourceTypeEnum.SalesOrder]: "Satış Siparişi", - [RequirementSourceTypeEnum.Forecast]: "Tahmin", - [RequirementSourceTypeEnum.SafetyStock]: "Güvenlik Stoku", - [RequirementSourceTypeEnum.ProductionOrder]: "Üretim Emri", - }; - return sourceLabels[sourceType]; - }; + [RequirementSourceTypeEnum.SalesOrder]: 'Satış Siparişi', + [RequirementSourceTypeEnum.Forecast]: 'Tahmin', + [RequirementSourceTypeEnum.SafetyStock]: 'Güvenlik Stoku', + [RequirementSourceTypeEnum.ProductionOrder]: 'Üretim Emri', + } + return sourceLabels[sourceType] + } const getSourceTypeColor = (sourceType: RequirementSourceTypeEnum) => { const sourceColors = { - [RequirementSourceTypeEnum.SalesOrder]: "bg-blue-100 text-blue-800", - [RequirementSourceTypeEnum.Forecast]: "bg-green-100 text-green-800", - [RequirementSourceTypeEnum.SafetyStock]: "bg-orange-100 text-orange-800", - [RequirementSourceTypeEnum.ProductionOrder]: - "bg-purple-100 text-purple-800", - }; - return sourceColors[sourceType]; - }; + [RequirementSourceTypeEnum.SalesOrder]: 'bg-blue-100 text-blue-800', + [RequirementSourceTypeEnum.Forecast]: 'bg-green-100 text-green-800', + [RequirementSourceTypeEnum.SafetyStock]: 'bg-orange-100 text-orange-800', + [RequirementSourceTypeEnum.ProductionOrder]: 'bg-purple-100 text-purple-800', + } + return sourceColors[sourceType] + } const getAccuracyColor = (accuracy: number) => { - if (accuracy >= 90) return "text-green-600"; - if (accuracy >= 75) return "text-yellow-600"; - return "text-red-600"; - }; + if (accuracy >= 90) return 'text-green-600' + if (accuracy >= 75) return 'text-yellow-600' + return 'text-red-600' + } const forecastColumns: Column[] = [ { - key: "material", - header: "Malzeme", + key: 'material', + header: 'Malzeme', sortable: true, render: (forecast: MrpDemandForecast) => (
- {forecast.material?.name || - `Material-${forecast.materialId.substring(0, 8)}`} + {forecast.material?.name || `Material-${forecast.materialId.substring(0, 8)}`}
{forecast.material?.code}
), }, { - key: "period", - header: "Dönem", + key: 'period', + header: 'Dönem', render: (forecast: MrpDemandForecast) => (
-
- {forecast.forecastPeriod} -
+
{forecast.forecastPeriod}
- {new Date(forecast.startDate).toLocaleDateString("tr-TR")} - - {new Date(forecast.endDate).toLocaleDateString("tr-TR")} + {new Date(forecast.startDate).toLocaleDateString('tr-TR')} - + {new Date(forecast.endDate).toLocaleDateString('tr-TR')}
), }, { - key: "method", - header: "Yöntem", + key: 'method', + header: 'Yöntem', render: (forecast: MrpDemandForecast) => (
@@ -355,36 +310,30 @@ const DemandPlanning: React.FC = () => { ), }, { - key: "quantities", - header: "Miktarlar", + key: 'quantities', + header: 'Miktarlar', render: (forecast: MrpDemandForecast) => (
- Tahmin:{" "} - - {forecast.forecastQuantity.toLocaleString()} - + Tahmin:{' '} + {forecast.forecastQuantity.toLocaleString()}
{forecast.actualQuantity !== undefined && (
- Gerçek:{" "} - - {forecast.actualQuantity.toLocaleString()} - + Gerçek:{' '} + {forecast.actualQuantity.toLocaleString()}
)}
), }, { - key: "accuracy", - header: "Doğruluk", + key: 'accuracy', + header: 'Doğruluk', render: (forecast: MrpDemandForecast) => (
{forecast.accuracy !== undefined ? ( -
+
{forecast.accuracy.toFixed(1)}%
) : ( @@ -394,22 +343,20 @@ const DemandPlanning: React.FC = () => { ), }, { - key: "factors", - header: "Faktörler", + key: 'factors', + header: 'Faktörler', render: (forecast: MrpDemandForecast) => (
{forecast.seasonalityFactor && (
Mevsimsellik: {forecast.seasonalityFactor.toFixed(2)}
)} - {forecast.trendFactor && ( -
Trend: {forecast.trendFactor.toFixed(2)}
- )} + {forecast.trendFactor &&
Trend: {forecast.trendFactor.toFixed(2)}
}
), }, { - key: "actions", - header: "İşlemler", + key: 'actions', + header: 'İşlemler', render: (forecast: MrpDemandForecast) => (
), }, - ]; + ] const requirementColumns: Column[] = [ { - key: "material", - header: "Malzeme", + key: 'material', + header: 'Malzeme', sortable: true, render: (req: MrpMaterialRequirement) => (
@@ -446,12 +393,12 @@ const DemandPlanning: React.FC = () => { ), }, { - key: "sourceType", - header: "Kaynak", + key: 'sourceType', + header: 'Kaynak', render: (req: MrpMaterialRequirement) => ( {getSourceTypeLabel(req.sourceType)} @@ -459,63 +406,46 @@ const DemandPlanning: React.FC = () => { ), }, { - key: "requirements", - header: "İhtiyaçlar", + key: 'requirements', + header: 'İhtiyaçlar', render: (req: MrpMaterialRequirement) => (
- Brüt:{" "} - - {req.grossRequirement.toLocaleString()} - + Brüt: {req.grossRequirement.toLocaleString()}
- Net:{" "} - - {req.netRequirement.toLocaleString()} - + Net: {req.netRequirement.toLocaleString()}
), }, { - key: "planned", - header: "Planlanan", + key: 'planned', + header: 'Planlanan', render: (req: MrpMaterialRequirement) => (
- Giriş:{" "} - - {req.plannedOrderReceipt.toLocaleString()} - + Giriş: {req.plannedOrderReceipt.toLocaleString()}
- Çıkış:{" "} - - {req.plannedOrderRelease.toLocaleString()} - + Çıkış: {req.plannedOrderRelease.toLocaleString()}
), }, { - key: "dates", - header: "Tarihler", + key: 'dates', + header: 'Tarihler', render: (req: MrpMaterialRequirement) => (
-
- İhtiyaç: {new Date(req.requirementDate).toLocaleDateString("tr-TR")} -
-
- Plan Giriş:{" "} - {new Date(req.plannedReceiptDate).toLocaleDateString("tr-TR")} -
+
İhtiyaç: {new Date(req.requirementDate).toLocaleDateString('tr-TR')}
+
Plan Giriş: {new Date(req.plannedReceiptDate).toLocaleDateString('tr-TR')}
), }, { - key: "projected", - header: "Mevcut Stok", + key: 'projected', + header: 'Mevcut Stok', render: (req: MrpMaterialRequirement) => (
@@ -525,8 +455,8 @@ const DemandPlanning: React.FC = () => { ), }, { - key: "actions", - header: "İşlemler", + key: 'actions', + header: 'İşlemler', render: (req: MrpMaterialRequirement) => (
), }, - ]; + ] // Calculate statistics - const totalForecasts = demandForecasts.length; + const totalForecasts = demandForecasts.length const averageAccuracy = demandForecasts .filter((f) => f.accuracy !== undefined) .reduce((sum, f) => sum + (f.accuracy || 0), 0) / - demandForecasts.filter((f) => f.accuracy !== undefined).length || 0; + demandForecasts.filter((f) => f.accuracy !== undefined).length || 0 - const totalRequirements = materialRequirements.length; + const totalRequirements = materialRequirements.length const criticalRequirements = materialRequirements.filter( - (r) => r.netRequirement > 0 && r.projectedAvailable < r.grossRequirement - ).length; + (r) => r.netRequirement > 0 && r.projectedAvailable < r.grossRequirement, + ).length // Method distribution - const methodDistribution = Object.values(ForecastMethodEnum).map( - (method) => ({ - method, - count: demandForecasts.filter((f) => f.forecastMethod === method).length, - accuracy: - demandForecasts - .filter( - (f) => f.forecastMethod === method && f.accuracy !== undefined - ) - .reduce((sum, f) => sum + (f.accuracy || 0), 0) / - demandForecasts.filter( - (f) => f.forecastMethod === method && f.accuracy !== undefined - ).length || 0, - }) - ); + const methodDistribution = Object.values(ForecastMethodEnum).map((method) => ({ + method, + count: demandForecasts.filter((f) => f.forecastMethod === method).length, + accuracy: + demandForecasts + .filter((f) => f.forecastMethod === method && f.accuracy !== undefined) + .reduce((sum, f) => sum + (f.accuracy || 0), 0) / + demandForecasts.filter((f) => f.forecastMethod === method && f.accuracy !== undefined) + .length || 0, + })) // Source type distribution - const sourceDistribution = Object.values(RequirementSourceTypeEnum).map( - (sourceType) => ({ - sourceType, - count: materialRequirements.filter((r) => r.sourceType === sourceType) - .length, - totalRequirement: materialRequirements - .filter((r) => r.sourceType === sourceType) - .reduce((sum, r) => sum + r.grossRequirement, 0), - }) - ); + const sourceDistribution = Object.values(RequirementSourceTypeEnum).map((sourceType) => ({ + sourceType, + count: materialRequirements.filter((r) => r.sourceType === sourceType).length, + totalRequirement: materialRequirements + .filter((r) => r.sourceType === sourceType) + .reduce((sum, r) => sum + r.grossRequirement, 0), + })) return ( -
- {/* Header */} -
-
-

Talep Planlama

-

- Talep tahmini ve malzeme ihtiyaç hesaplama -

-
-
- - - -
-
- - {/* Stats Cards */} -
- - - - - - - -
- -
- {/* Method Distribution */} -
-

- Tahmin Yöntemi Dağılımı -

-
- {methodDistribution.map(({ method, count, accuracy }) => ( -
-
- - - {getMethodLabel(method)} - -
-
- {count} -
-
- {accuracy > 0 - ? `${accuracy.toFixed(1)}% Doğruluk` - : "Doğruluk Yok"} -
-
- ))} + +
+ {/* Header */} +
+
+

Talep Planlama

+

+ Talep tahmini ve malzeme ihtiyaç hesaplama +

+
+
+ + +
- {/* Source Distribution */} -
-

- İhtiyaç Kaynağı Dağılımı -

-
- {sourceDistribution.map( - ({ sourceType, count, totalRequirement }) => ( -
+ {/* Stats Cards */} +
+ + + + + + + +
+ +
+ {/* Method Distribution */} +
+

Tahmin Yöntemi Dağılımı

+
+ {methodDistribution.map(({ method, count, accuracy }) => ( +
+
+ + + {getMethodLabel(method)} + +
+
{count}
+
+ {accuracy > 0 ? `${accuracy.toFixed(1)}% Doğruluk` : 'Doğruluk Yok'} +
+
+ ))} +
+
+ + {/* Source Distribution */} +
+

İhtiyaç Kaynağı Dağılımı

+
+ {sourceDistribution.map(({ sourceType, count, totalRequirement }) => ( +
{getSourceTypeLabel(sourceType)}
-
- {count} -
+
{count}
{totalRequirement.toLocaleString()} Miktar
- ) - )} + ))} +
-
- {/* Tabs */} -
- - -
- - {/* Filters */} -
-
- setSearchTerm(e.target.value)} - className="w-full px-2 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" - /> -
- - {activeTab === "forecasts" && ( - - )} -
- - {/* Data Table */} -
- {activeTab === "forecasts" ? ( - - ) : ( - - )} -
- - {/* Empty State */} - {((activeTab === "forecasts" && filteredForecasts.length === 0) || - (activeTab === "requirements" && - filteredRequirements.length === 0)) && ( -
- {activeTab === "forecasts" ? ( - - ) : ( - - )} -

- {activeTab === "forecasts" - ? "Tahmin bulunamadı" - : "İhtiyaç bulunamadı"} -

-

- Arama kriterlerinizi değiştirmeyi deneyin. -

+
+ + Talep Tahminleri +
+ +
- )} + + {/* Filters */} +
+
+ setSearchTerm(e.target.value)} + className="w-full px-2 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" + /> +
+ + {activeTab === 'forecasts' && ( + + )} +
+ + {/* Data Table */} +
+ {activeTab === 'forecasts' ? ( + + ) : ( + + )} +
+ + {/* Empty State */} + {((activeTab === 'forecasts' && filteredForecasts.length === 0) || + (activeTab === 'requirements' && filteredRequirements.length === 0)) && ( +
+ {activeTab === 'forecasts' ? ( + + ) : ( + + )} +

+ {activeTab === 'forecasts' ? 'Tahmin bulunamadı' : 'İhtiyaç bulunamadı'} +

+

Arama kriterlerinizi değiştirmeyi deneyin.

+
+ )} +
{/* Modals */} { onSave={handleSaveRequirement} initialData={editingRequirement} /> -
- ); -}; + + ) +} -export default DemandPlanning; +export default DemandPlanning diff --git a/ui/src/views/mrp/components/OperationDefinitions.tsx b/ui/src/views/mrp/components/OperationDefinitions.tsx index 59deae9d..06f28b50 100644 --- a/ui/src/views/mrp/components/OperationDefinitions.tsx +++ b/ui/src/views/mrp/components/OperationDefinitions.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState } from 'react' import { FaPlus, FaSearch, @@ -11,402 +11,363 @@ import { FaWrench, FaTh, FaList, -} from "react-icons/fa"; -import { MrpOperation } from "../../../types/mrp"; -import OperationFormModal from "./OperationFormModal"; -import { mockOperations } from "../../../mocks/mockOperations"; +} from 'react-icons/fa' +import { MrpOperation } from '../../../types/mrp' +import OperationFormModal from './OperationFormModal' +import { mockOperations } from '../../../mocks/mockOperations' +import { Container } from '@/components/shared' const OperationDefinitions: React.FC = () => { - const [searchTerm, setSearchTerm] = useState(""); - const [showModal, setShowModal] = useState(false); - const [editingOperation, setEditingOperation] = useState( - null - ); - const [viewMode, setViewMode] = useState<"card" | "list">("card"); + const [searchTerm, setSearchTerm] = useState('') + const [showModal, setShowModal] = useState(false) + const [editingOperation, setEditingOperation] = useState(null) + const [viewMode, setViewMode] = useState<'card' | 'list'>('card') const getTotalCost = (operation: MrpOperation) => { - return operation.laborCost + operation.machineCost + operation.overheadCost; - }; + return operation.laborCost + operation.machineCost + operation.overheadCost + } // Mock data - replace with actual API calls - const [operations, setOperations] = useState(mockOperations); + const [operations, setOperations] = useState(mockOperations) const filteredOperations = operations.filter( (operation) => operation.name.toLowerCase().includes(searchTerm.toLowerCase()) || operation.code.toLowerCase().includes(searchTerm.toLowerCase()) || - operation.workCenter?.name - .toLowerCase() - .includes(searchTerm.toLowerCase()) - ); + operation.workCenter?.name.toLowerCase().includes(searchTerm.toLowerCase()), + ) const handleEdit = (operation: MrpOperation) => { - setEditingOperation(operation); - setShowModal(true); - }; + setEditingOperation(operation) + setShowModal(true) + } const handleAddNew = () => { - setEditingOperation(null); - setShowModal(true); - }; + setEditingOperation(null) + setShowModal(true) + } const handleSave = (op: MrpOperation) => { setOperations((prev) => { - const existing = prev.find((p) => p.id === op.id); - if (existing) return prev.map((p) => (p.id === op.id ? op : p)); - return [...prev, { ...op, id: op.id || String(Date.now()) }]; - }); - setShowModal(false); - }; + const existing = prev.find((p) => p.id === op.id) + if (existing) return prev.map((p) => (p.id === op.id ? op : p)) + return [...prev, { ...op, id: op.id || String(Date.now()) }] + }) + setShowModal(false) + } return ( -
- {/* Header */} -
-
-

- Operasyon Tanımları -

-

- İş merkezlerinde gerçekleştirilen operasyonları tanımlayın -

-
-
- {/* View Toggle */} -
+ +
+ {/* Header */} +
+
+

Operasyon Tanımları

+

+ İş merkezlerinde gerçekleştirilen operasyonları tanımlayın +

+
+
+ {/* View Toggle */} +
+ + +
-
-
-
- {/* Search Bar */} -
- - setSearchTerm(e.target.value)} - className="w-full pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" - /> -
- - {/* Operations Display */} - {viewMode === "card" ? ( - /* Card View */ -
- {filteredOperations.map((operation) => ( -
-
-
-
-

- {operation.name} -

- - {operation.operationType?.code} - -
-

{operation.code}

- {operation.description && ( -

- {operation.description} -

- )} -
-
- - -
-
- - {/* Work Center Info */} -
-
- - İş Merkezi -
-

- {operation.workCenter?.name} -

-

- {operation.workCenter?.code} -

-
- -
-
-
- - - Standart Süre - - - {operation.standardTime} dk - -
- -
- - - Hazırlık Süresi - - - {operation.setupTime} dk - -
- -
- - - İşçilik - - ₺{operation.laborCost} -
-
- -
-
- Makine Maliyeti - - ₺{operation.machineCost} - -
- -
- Genel Gider - - ₺{operation.overheadCost} - -
- -
- - - Toplam Maliyet - - - ₺{getTotalCost(operation)} - -
-
-
- - {operation.instructions && ( -
-

- Talimatlar -

-

- {operation.instructions} -

-
- )} - -
-
- - {operation.isActive ? "Aktif" : "Pasif"} - - - {operation.qualityCheckRequired - ? "Kalite Kontrolü Gerekli" - : "Kalite Kontrolü İsteğe Bağlı"} - -
- - {operation.lastModificationTime.toLocaleDateString("tr-TR")} - -
-
- ))} + {/* Search Bar */} +
+ + setSearchTerm(e.target.value)} + className="w-full pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" + />
- ) : ( - /* List View */ -
- - - - - - - - - - - - - - {filteredOperations.map((operation) => ( - - - - - - - - - - ))} - -
- Operasyon - - İş Merkezi - - Tür - - Süre (dk) - - Maliyet (₺) - - Durum - - İşlemler -
-
-
- {operation.name} -
-
- {operation.code} -
- {operation.description && ( -
- {operation.description} -
- )} + + {/* Operations Display */} + {viewMode === 'card' ? ( + /* Card View */ +
+ {filteredOperations.map((operation) => ( +
+
+
+
+

{operation.name}

+ + {operation.operationType?.code} +
-
-
- {operation.workCenter?.name} -
-
- {operation.workCenter?.code} -
-
- {operation.code}

+ {operation.description && ( +

{operation.description}

+ )} + +
+
-
-
- - Standart: {operation.standardTime} -
-
- - Hazırlık: {operation.setupTime} -
-
-
-
-
İşçilik: ₺{operation.laborCost}
-
Makine: ₺{operation.machineCost}
-
- Toplam: ₺{getTotalCost(operation)} -
-
-
-
- - {operation.isActive ? "Aktif" : "Pasif"} - - - {operation.qualityCheckRequired - ? "Kalite Gerekli" - : "Kalite İsteğe Bağlı"} - -
-
-
- - -
-
-
- )} + + + +
+
- {filteredOperations.length === 0 && ( -
- -

- Operasyon bulunamadı -

-

- Arama kriterlerinizi değiştirin veya yeni bir operasyon ekleyin. -

-
- )} + {/* Work Center Info */} +
+
+ + İş Merkezi +
+

{operation.workCenter?.name}

+

{operation.workCenter?.code}

+
+ +
+
+
+ + + Standart Süre + + {operation.standardTime} dk +
+ +
+ + + Hazırlık Süresi + + {operation.setupTime} dk +
+ +
+ + + İşçilik + + ₺{operation.laborCost} +
+
+ +
+
+ Makine Maliyeti + ₺{operation.machineCost} +
+ +
+ Genel Gider + ₺{operation.overheadCost} +
+ +
+ + + Toplam Maliyet + + ₺{getTotalCost(operation)} +
+
+
+ + {operation.instructions && ( +
+

Talimatlar

+

{operation.instructions}

+
+ )} + +
+
+ + {operation.isActive ? 'Aktif' : 'Pasif'} + + + {operation.qualityCheckRequired + ? 'Kalite Kontrolü Gerekli' + : 'Kalite Kontrolü İsteğe Bağlı'} + +
+ + {operation.lastModificationTime.toLocaleDateString('tr-TR')} + +
+
+ ))} +
+ ) : ( + /* List View */ +
+ + + + + + + + + + + + + + {filteredOperations.map((operation) => ( + + + + + + + + + + ))} + +
+ Operasyon + + İş Merkezi + + Tür + + Süre (dk) + + Maliyet (₺) + + Durum + + İşlemler +
+
+
{operation.name}
+
{operation.code}
+ {operation.description && ( +
{operation.description}
+ )} +
+
+
{operation.workCenter?.name}
+
{operation.workCenter?.code}
+
+ + {operation.operationType?.code} + + +
+
+ + Standart: {operation.standardTime} +
+
+ + Hazırlık: {operation.setupTime} +
+
+
+
+
İşçilik: ₺{operation.laborCost}
+
Makine: ₺{operation.machineCost}
+
+ Toplam: ₺{getTotalCost(operation)} +
+
+
+
+ + {operation.isActive ? 'Aktif' : 'Pasif'} + + + {operation.qualityCheckRequired + ? 'Kalite Gerekli' + : 'Kalite İsteğe Bağlı'} + +
+
+
+ + +
+
+
+ )} + + {filteredOperations.length === 0 && ( +
+ +

Operasyon bulunamadı

+

+ Arama kriterlerinizi değiştirin veya yeni bir operasyon ekleyin. +

+
+ )} +
{/* Modal for Add/Edit */} { onSave={handleSave} onClose={() => setShowModal(false)} /> -
- ); -}; +
+ ) +} -export default OperationDefinitions; +export default OperationDefinitions diff --git a/ui/src/views/mrp/components/OperationForm.tsx b/ui/src/views/mrp/components/OperationForm.tsx index da6fb663..0446bf68 100644 --- a/ui/src/views/mrp/components/OperationForm.tsx +++ b/ui/src/views/mrp/components/OperationForm.tsx @@ -176,7 +176,7 @@ const OperationForm: React.FC = () => { } return ( -
+
{/* Header */}
diff --git a/ui/src/views/mrp/components/OperationFormModal.tsx b/ui/src/views/mrp/components/OperationFormModal.tsx index 62fca7d3..8f24d644 100644 --- a/ui/src/views/mrp/components/OperationFormModal.tsx +++ b/ui/src/views/mrp/components/OperationFormModal.tsx @@ -56,7 +56,7 @@ const OperationFormModal: React.FC = ({ {form.id ? "Operasyonu Düzenle" : "Yeni Operasyon"} -
+
{/* First Row - Code and Name */}
diff --git a/ui/src/views/mrp/components/OperationTypes.tsx b/ui/src/views/mrp/components/OperationTypes.tsx index 6c83c004..b2cdc953 100644 --- a/ui/src/views/mrp/components/OperationTypes.tsx +++ b/ui/src/views/mrp/components/OperationTypes.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState } from 'react' import { FaPlus, FaSearch, @@ -9,353 +9,335 @@ import { FaCheckCircle, FaTh, FaList, -} from "react-icons/fa"; -import { MrpOperationTypeDefinition } from "../../../types/mrp"; -import OperationTypeFormModal from "./OperationTypeFormModal"; -import { mockOperationTypes } from "../../../mocks/mockOperationTypes"; +} from 'react-icons/fa' +import { MrpOperationTypeDefinition } from '../../../types/mrp' +import OperationTypeFormModal from './OperationTypeFormModal' +import { mockOperationTypes } from '../../../mocks/mockOperationTypes' import { getOperationCategoryColor, getOperationTypeColor, getOperationTypeText, getSkillLevelText, -} from "../../../utils/erp"; +} from '../../../utils/erp' +import { Container } from '@/components/shared' const OperationTypes: React.FC = () => { - const [searchTerm, setSearchTerm] = useState(""); - const [showModal, setShowModal] = useState(false); - const [editingType, setEditingType] = - useState(null); - const [viewMode, setViewMode] = useState<"card" | "list">("card"); + const [searchTerm, setSearchTerm] = useState('') + const [showModal, setShowModal] = useState(false) + const [editingType, setEditingType] = useState(null) + const [viewMode, setViewMode] = useState<'card' | 'list'>('card') - const [operationTypes] = - useState(mockOperationTypes); + const [operationTypes] = useState(mockOperationTypes) const filteredTypes = operationTypes.filter( (type) => type.name.toLowerCase().includes(searchTerm.toLowerCase()) || type.code.toLowerCase().includes(searchTerm.toLowerCase()) || - type.category.toLowerCase().includes(searchTerm.toLowerCase()) - ); + type.category.toLowerCase().includes(searchTerm.toLowerCase()), + ) const handleEdit = (type: MrpOperationTypeDefinition) => { - setEditingType(type); - setShowModal(true); - }; + setEditingType(type) + setShowModal(true) + } const handleAddNew = () => { - setEditingType(null); - setShowModal(true); - }; + setEditingType(null) + setShowModal(true) + } return ( -
- {/* Header */} -
-
-

Operasyon Türleri

-

- İş merkezlerinde kullanılacak operasyon türlerini tanımlayın -

-
-
- {/* View Toggle */} -
+ +
+ {/* Header */} +
+
+

Operasyon Türleri

+

+ İş merkezlerinde kullanılacak operasyon türlerini tanımlayın +

+
+
+ {/* View Toggle */} +
+ + +
-
-
-
- {/* Search Bar */} -
- - setSearchTerm(e.target.value)} - className="w-full pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" - /> -
+ {/* Search Bar */} +
+ + setSearchTerm(e.target.value)} + className="w-full pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" + /> +
- {/* Operation Types Display */} - {viewMode === "card" ? ( - /* Card View */ -
- {filteredTypes.map((type) => ( -
-
-
-
-

- {type.name} -

- + {filteredTypes.map((type) => ( +
+
+
+
+

{type.name}

+ + {getOperationTypeText(type.category)} + +
+

{type.code}

+ {type.description && ( +

{type.description}

+ )} +
+
+ + +
+
+ +
+
+ + + Varsayılan Süre + + {type.defaultDuration} dk +
+ +
+ Beceri Seviyesi + + {getSkillLevelText(type.skillLevelRequired)} + +
+ +
+ + + Hazırlık Gerekli + + + {type.requiresSetup ? 'Evet' : 'Hayır'} + +
+ +
+ Paralel İşlem + + {type.allowsParallelOperation ? 'Evet' : 'Hayır'} + +
+ +
+ + + Kalite Kontrolü + + + {type.qualityCheckRequired ? 'Gerekli' : 'İsteğe Bağlı'}
-

{type.code}

- {type.description && ( -

- {type.description} -

- )}
-
- - + +
+
+ + {type.isActive ? 'Aktif' : 'Pasif'} + + + {type.lastModificationTime.toLocaleDateString('tr-TR')} + +
- -
-
- - - Varsayılan Süre - - {type.defaultDuration} dk -
- -
- Beceri Seviyesi - - {getSkillLevelText(type.skillLevelRequired)} - -
- -
- - - Hazırlık Gerekli - - - {type.requiresSetup ? "Evet" : "Hayır"} - -
- -
- Paralel İşlem - - {type.allowsParallelOperation ? "Evet" : "Hayır"} - -
- -
- - + ))} +
+ ) : ( + /* List View */ +
+ + + + + + + + + + + {filteredTypes.map((type) => ( + + + + + + + + + + + ))} + +
+ Operasyon Türü + + Kategori + + Süre + + Beceri Seviyesi + + Hazırlık + Kalite Kontrolü - - - {type.qualityCheckRequired ? "Gerekli" : "İsteğe Bağlı"} - - - - -
-
- - {type.isActive ? "Aktif" : "Pasif"} - - - {type.lastModificationTime.toLocaleDateString("tr-TR")} - -
-
- - ))} - - ) : ( - /* List View */ -
- - - - - - - - - - - - - - - {filteredTypes.map((type) => ( - - - - - - - - - + + + - ))} - -
- Operasyon Türü - - Kategori - - Süre - - Beceri Seviyesi - - Hazırlık - - Kalite Kontrolü - - Durum - - İşlemler -
-
-
- {type.name} -
-
{type.code}
- {type.description && ( -
- {type.description} -
- )} -
-
- - {type.category} - - -
- - {type.defaultDuration} dk -
-
- {getSkillLevelText(type.skillLevelRequired)} - - - {type.requiresSetup ? "Gerekli" : "Gerekli Değil"} - - - - {type.qualityCheckRequired ? "Gerekli" : "İsteğe Bağlı"} - - - - {type.isActive ? "Aktif" : "Pasif"} - - -
- - -
-
+ Durum + + İşlemler +
-
- )} +
+
+
{type.name}
+
{type.code}
+ {type.description && ( +
{type.description}
+ )} +
+
+ + {type.category} + + +
+ + {type.defaultDuration} dk +
+
+ {getSkillLevelText(type.skillLevelRequired)} + + + {type.requiresSetup ? 'Gerekli' : 'Gerekli Değil'} + + + + {type.qualityCheckRequired ? 'Gerekli' : 'İsteğe Bağlı'} + + + + {type.isActive ? 'Aktif' : 'Pasif'} + + +
+ + +
+
+
+ )} - {filteredTypes.length === 0 && ( -
- -

- Operasyon türü bulunamadı -

-

- Arama kriterlerinizi değiştirin veya yeni bir operasyon türü - ekleyin. -

-
- )} + {filteredTypes.length === 0 && ( +
+ +

Operasyon türü bulunamadı

+

+ Arama kriterlerinizi değiştirin veya yeni bir operasyon türü ekleyin. +

+
+ )} +
{/* Modal for Add/Edit - Placeholder */} { onClose={() => setShowModal(false)} onSave={(data) => { // TODO: persist to API; for now just close modal - console.log("Saved operation type:", data); - setShowModal(false); + console.log('Saved operation type:', data) + setShowModal(false) }} /> -
- ); -}; + + ) +} -export default OperationTypes; +export default OperationTypes diff --git a/ui/src/views/mrp/components/PlanningGantt.tsx b/ui/src/views/mrp/components/PlanningGantt.tsx index 01399f69..20b54037 100644 --- a/ui/src/views/mrp/components/PlanningGantt.tsx +++ b/ui/src/views/mrp/components/PlanningGantt.tsx @@ -16,12 +16,13 @@ import { getProductionOrderStatus, getWorkOrderStatus, } from "../../../utils/erp"; +import { Container } from "@/components/shared"; interface PlanningGanttProps { workCenterId?: string; } -export const PlanningGantt: React.FC = ({ +const PlanningGantt: React.FC = ({ workCenterId, }) => { const getInitialExpandedItems = () => { @@ -502,8 +503,8 @@ export const PlanningGantt: React.FC = ({ }; return ( - <> -
+ +

@@ -618,6 +619,8 @@ export const PlanningGantt: React.FC = ({ {filteredData.map((task) => renderTask(task))}

- + ); }; + +export default PlanningGantt; \ No newline at end of file diff --git a/ui/src/views/mrp/components/ProductionOrderForm.tsx b/ui/src/views/mrp/components/ProductionOrderForm.tsx index 82be854f..f2202ebb 100644 --- a/ui/src/views/mrp/components/ProductionOrderForm.tsx +++ b/ui/src/views/mrp/components/ProductionOrderForm.tsx @@ -1,13 +1,13 @@ -import React, { useEffect, useState } from "react"; -import { useParams, useNavigate } from "react-router-dom"; -import { useQuery } from "@tanstack/react-query"; -import { mockProductionOrders } from "../../../mocks/mockProductionOrders"; +import React, { useEffect, useState } from 'react' +import { useParams, useNavigate } from 'react-router-dom' +import { useQuery } from '@tanstack/react-query' +import { mockProductionOrders } from '../../../mocks/mockProductionOrders' import { MrpProductionOrder, ProductionOrderStatusEnum, MrpProductionOrderMaterial, ProductionOrderTypeEnum, -} from "../../../types/mrp"; +} from '../../../types/mrp' import { FaPlus, FaTimes, @@ -21,28 +21,27 @@ import { FaTruck, FaCheckCircle, FaExclamationTriangle, -} from "react-icons/fa"; -import { mockMaterials } from "../../../mocks/mockMaterials"; -import { PriorityEnum } from "../../../types/common"; +} from 'react-icons/fa' +import { mockMaterials } from '../../../mocks/mockMaterials' +import { PriorityEnum } from '../../../types/common' +import { Container } from '@/components/shared' const ProductionOrderForm: React.FC = () => { - const { id } = useParams(); - const navigate = useNavigate(); + const { id } = useParams() + const navigate = useNavigate() const { data: productionOrder, isLoading } = useQuery({ - queryKey: ["production-order", id], + queryKey: ['production-order', id], queryFn: async () => { - await new Promise((r) => setTimeout(r, 200)); - return mockProductionOrders.find((p) => p.id === id) as - | MrpProductionOrder - | undefined; + await new Promise((r) => setTimeout(r, 200)) + return mockProductionOrders.find((p) => p.id === id) as MrpProductionOrder | undefined }, - enabled: !!id && id !== "new", - }); + enabled: !!id && id !== 'new', + }) // Form state const [formData, setFormData] = useState>({ - orderNumber: "", + orderNumber: '', orderType: ProductionOrderTypeEnum.Standard, status: ProductionOrderStatusEnum.Created, priority: PriorityEnum.Normal, @@ -50,28 +49,26 @@ const ProductionOrderForm: React.FC = () => { confirmedQuantity: 0, requiredQuantity: 0, scrapQuantity: 0, - unitId: "ADET", + unitId: 'ADET', plannedCost: 0, actualCost: 0, - currency: "TRY", + currency: 'TRY', plannedStartDate: new Date(), plannedEndDate: new Date(new Date().setDate(new Date().getDate() + 14)), materials: [], - }); + }) // Materials management - const [materials, setMaterials] = useState([]); - const [showNewMaterialForm, setShowNewMaterialForm] = useState(false); - const [newMaterial, setNewMaterial] = useState< - Partial - >({ - materialId: "", + const [materials, setMaterials] = useState([]) + const [showNewMaterialForm, setShowNewMaterialForm] = useState(false) + const [newMaterial, setNewMaterial] = useState>({ + materialId: '', plannedQuantity: 0, confirmedQuantity: 0, requiredQuantity: 0, scrapQuantity: 0, - unitId: "ADET", - }); + unitId: 'ADET', + }) // Initialize form with data when available useEffect(() => { @@ -82,110 +79,106 @@ const ProductionOrderForm: React.FC = () => { plannedEndDate: productionOrder.plannedEndDate, actualStartDate: productionOrder.actualStartDate, actualEndDate: productionOrder.actualEndDate, - }); - setMaterials(productionOrder.materials || []); + }) + setMaterials(productionOrder.materials || []) } - }, [productionOrder]); + }, [productionOrder]) // Handle form field changes const handleChange = ( - e: React.ChangeEvent< - HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement - > + e: React.ChangeEvent, ) => { - const { name, value, type } = e.target; + const { name, value, type } = e.target - if (type === "number") { + if (type === 'number') { setFormData({ ...formData, [name]: parseFloat(value) || 0, - }); - } else if (type === "date") { + }) + } else if (type === 'date') { setFormData({ ...formData, [name]: new Date(value), - }); + }) } else { setFormData({ ...formData, [name]: value, - }); + }) } - }; + } // Handle new material form changes - const handleNewMaterialChange = ( - e: React.ChangeEvent - ) => { - const { name, value, type } = e.target; + const handleNewMaterialChange = (e: React.ChangeEvent) => { + const { name, value, type } = e.target - if (type === "number") { + if (type === 'number') { setNewMaterial({ ...newMaterial, [name]: parseFloat(value) || 0, - }); + }) } else { setNewMaterial({ ...newMaterial, [name]: value, - }); + }) } - }; + } // Add new material to the list const handleAddMaterial = () => { if (!newMaterial.materialId) { - alert("Lütfen malzeme seçiniz"); - return; + alert('Lütfen malzeme seçiniz') + return } const newMaterialComplete: MrpProductionOrderMaterial = { id: Date.now().toString(), // Temporary ID for UI - productionOrderId: id || "new", - materialId: newMaterial.materialId || "", + productionOrderId: id || 'new', + materialId: newMaterial.materialId || '', plannedQuantity: newMaterial.plannedQuantity || 0, confirmedQuantity: newMaterial.confirmedQuantity || 0, requiredQuantity: newMaterial.requiredQuantity || 0, scrapQuantity: newMaterial.scrapQuantity || 0, - unitId: newMaterial.unitId || "ADET", - }; + unitId: newMaterial.unitId || 'ADET', + } - setMaterials([...materials, newMaterialComplete]); + setMaterials([...materials, newMaterialComplete]) setNewMaterial({ - materialId: "", + materialId: '', plannedQuantity: 0, confirmedQuantity: 0, requiredQuantity: 0, scrapQuantity: 0, - unitId: "ADET", - }); - setShowNewMaterialForm(false); - }; + unitId: 'ADET', + }) + setShowNewMaterialForm(false) + } // Remove material from the list const handleRemoveMaterial = (materialId: string) => { - setMaterials(materials.filter((m) => m.id !== materialId)); - }; + setMaterials(materials.filter((m) => m.id !== materialId)) + } // Save the production order const handleSave = () => { const completeFormData: Partial = { ...formData, materials: materials, - }; + } - console.log("Saving production order:", completeFormData); + console.log('Saving production order:', completeFormData) // Here you would normally call an API to save the data - navigate(`/admin/mrp/production-orders/${id || "new"}`); - }; + navigate(`/admin/mrp/production-orders/${id || 'new'}`) + } // Format date for input fields const formatDateForInput = (date: Date | undefined) => { - if (!date) return ""; - const d = new Date(date); - return d.toISOString().split("T")[0]; - }; + if (!date) return '' + const d = new Date(date) + return d.toISOString().split('T')[0] + } if (isLoading) { return ( @@ -195,524 +188,467 @@ const ProductionOrderForm: React.FC = () => {

Üretim emri yükleniyor...

- ); + ) } return ( -
- {/* Header */} -
-
-
- -
-

- {id === "new" ? "Yeni Üretim Emri" : "Üretim Emri Düzenle"} -

-

- {id === "new" - ? "Yeni üretim emri oluşturun" - : `${formData.orderNumber} düzenleniyor`} -

-
-
- -
-
- -
- {/* Left: Main form */} -
- {/* Basic Information */} -
-
-
- -
-

- Temel Bilgiler -

-
- -
-
- - -
- -
- - -
- -
- - -
- -
- - -
-
-
- - {/* Quantity Information */} -
-
-
- -
-

- Miktar Bilgileri -

-
- -
-
- - -
- -
- - -
- -
- - -
- -
- - -
-
-
- - {/* Schedule Information */} -
-
-
- -
-

Zamanlama

-
- -
-
- - -
- -
- - -
- -
- - -
- -
- - -
-
-
- - {/* Cost Information */} -
-
-
- -
-

- Maliyet Bilgileri -

-
- -
-
- - -
- -
- - -
- -
- - -
-
-
- - {/* Customer Requirement */} -
-
-
- -
-

- Müşteri Talebi -

-
- -