From 7e38f82d0cd3eac07ec1e470bc46fcef4d52b00b Mon Sep 17 00:00:00 2001 From: leeheejin Date: Wed, 15 Oct 2025 18:25:16 +0900 Subject: [PATCH] =?UTF-8?q?=ED=95=84=EC=9A=94=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=EC=A2=85=EB=A5=98=20=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EB=8C=80?= =?UTF-8?q?=EC=8B=9C=EB=B3=B4=EB=93=9C=20=EC=9D=B4=EC=A0=A0=20=EB=A0=8C?= =?UTF-8?q?=EB=8D=94=EB=A7=81=20=EB=90=98=EA=B3=A0=20=EB=AA=A8=EB=93=A0=20?= =?UTF-8?q?=EC=9C=84=EC=A0=AF=EB=93=A4=20=EC=9D=B4=EB=A6=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EA=B0=80=EB=8A=A5=ED=95=98=EA=B2=8C=20=ED=95=B4?= =?UTF-8?q?=EB=8B=AC=EB=9D=BC=EA=B3=A0=20=ED=96=88=EB=8A=94=EB=8D=B0=20?= =?UTF-8?q?=EC=A7=80=EA=B8=88=EC=9D=80=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=EC=97=B0=EA=B2=B0=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B2=83=EB=A7=8C=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=9D=B4=20=EB=90=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/dashboard/DashboardSidebar.tsx | 8 +- .../admin/dashboard/ElementConfigModal.tsx | 96 +++++++++----- frontend/components/admin/dashboard/types.ts | 1 + .../components/dashboard/DashboardViewer.tsx | 16 +-- .../dashboard/widgets/BookingAlertWidget.tsx | 9 +- .../dashboard/widgets/CalculatorWidget.tsx | 9 +- .../dashboard/widgets/DocumentWidget.tsx | 122 +++++++++--------- .../dashboard/widgets/ExchangeWidget.tsx | 5 +- .../dashboard/widgets/MaintenanceWidget.tsx | 87 +++++++------ .../dashboard/widgets/MapSummaryWidget.tsx | 9 +- .../dashboard/widgets/RiskAlertWidget.tsx | 9 +- .../dashboard/widgets/StatusSummaryWidget.tsx | 3 +- .../dashboard/widgets/TodoWidget.tsx | 9 +- .../widgets/VehicleMapOnlyWidget.tsx | 6 +- .../dashboard/widgets/WeatherWidget.tsx | 8 +- 15 files changed, 229 insertions(+), 168 deletions(-) diff --git a/frontend/components/admin/dashboard/DashboardSidebar.tsx b/frontend/components/admin/dashboard/DashboardSidebar.tsx index cc34feb4..6c03b398 100644 --- a/frontend/components/admin/dashboard/DashboardSidebar.tsx +++ b/frontend/components/admin/dashboard/DashboardSidebar.tsx @@ -220,13 +220,7 @@ export function DashboardSidebar() { subtype="booking-alert" onDragStart={handleDragStart} /> - + {/* ์ •๋น„ ์ผ์ • ๊ด€๋ฆฌ ์œ„์ ฏ ์ œ๊ฑฐ - ์ปค์Šคํ…€ ๋ชฉ๋ก ์นด๋“œ๋กœ ๋Œ€์ฒด ๊ฐ€๋Šฅ */} (element.chartConfig || {}); const [queryResult, setQueryResult] = useState(null); const [currentStep, setCurrentStep] = useState<1 | 2>(1); + const [customTitle, setCustomTitle] = useState(element.customTitle || ""); // ์ฐจํŠธ ์„ค์ •์ด ํ•„์š” ์—†๋Š” ์œ„์ ฏ (์ฟผ๋ฆฌ/API๋งŒ ํ•„์š”) const isSimpleWidget = @@ -56,6 +57,7 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave }: Element setChartConfig(element.chartConfig || {}); setQueryResult(null); setCurrentStep(1); + setCustomTitle(element.customTitle || ""); } }, [isOpen, element]); @@ -119,13 +121,14 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave }: Element ...element, dataSource, chartConfig, + customTitle: customTitle.trim() || undefined, // ๋นˆ ๋ฌธ์ž์—ด์ด๋ฉด undefined }; console.log(" ์ €์žฅํ•  element:", updatedElement); onSave(updatedElement); onClose(); - }, [element, dataSource, chartConfig, onSave, onClose]); + }, [element, dataSource, chartConfig, customTitle, onSave, onClose]); // ๋ชจ๋‹ฌ์ด ์—ด๋ ค์žˆ์ง€ ์•Š์œผ๋ฉด ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Œ if (!isOpen) return null; @@ -147,28 +150,32 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave }: Element chartConfig.yAxis && (typeof chartConfig.yAxis === "string" || (Array.isArray(chartConfig.yAxis) && chartConfig.yAxis.length > 0)); - const canSave = isSimpleWidget - ? // ๊ฐ„๋‹จํ•œ ์œ„์ ฏ: 2๋‹จ๊ณ„์—์„œ ์ฟผ๋ฆฌ ํ…Œ์ŠคํŠธ ํ›„ ์ €์žฅ ๊ฐ€๋Šฅ - currentStep === 2 && queryResult && queryResult.rows.length > 0 - : isMapWidget - ? // ์ง€๋„ ์œ„์ ฏ: ์œ„๋„/๊ฒฝ๋„ ๋งคํ•‘ ํ•„์š” - currentStep === 2 && - queryResult && - queryResult.rows.length > 0 && - chartConfig.latitudeColumn && - chartConfig.longitudeColumn - : // ์ฐจํŠธ: ๊ธฐ์กด ๋กœ์ง (2๋‹จ๊ณ„์—์„œ ์ฐจํŠธ ์„ค์ • ํ•„์š”) - currentStep === 2 && - queryResult && - queryResult.rows.length > 0 && - chartConfig.xAxis && - (isPieChart || isApiSource - ? // ํŒŒ์ด/๋„๋„› ์ฐจํŠธ ๋˜๋Š” REST API - chartConfig.aggregation === "count" - ? true // count๋Š” Y์ถ• ์—†์–ด๋„ ๋จ - : hasYAxis // ๋‹ค๋ฅธ ์ง‘๊ณ„(sum, avg, max, min) ๋˜๋Š” ์ง‘๊ณ„ ์—†์Œ โ†’ Y์ถ• ํ•„์ˆ˜ - : // ์ผ๋ฐ˜ ์ฐจํŠธ (DB): Y์ถ• ํ•„์ˆ˜ - hasYAxis); + // customTitle์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ + const isTitleChanged = customTitle.trim() !== (element.customTitle || ""); + + const canSave = isTitleChanged || // ์ œ๋ชฉ๋งŒ ๋ณ€๊ฒฝํ•ด๋„ ์ €์žฅ ๊ฐ€๋Šฅ + (isSimpleWidget + ? // ๊ฐ„๋‹จํ•œ ์œ„์ ฏ: 2๋‹จ๊ณ„์—์„œ ์ฟผ๋ฆฌ ํ…Œ์ŠคํŠธ ํ›„ ์ €์žฅ ๊ฐ€๋Šฅ + currentStep === 2 && queryResult && queryResult.rows.length > 0 + : isMapWidget + ? // ์ง€๋„ ์œ„์ ฏ: ์œ„๋„/๊ฒฝ๋„ ๋งคํ•‘ ํ•„์š” + currentStep === 2 && + queryResult && + queryResult.rows.length > 0 && + chartConfig.latitudeColumn && + chartConfig.longitudeColumn + : // ์ฐจํŠธ: ๊ธฐ์กด ๋กœ์ง (2๋‹จ๊ณ„์—์„œ ์ฐจํŠธ ์„ค์ • ํ•„์š”) + currentStep === 2 && + queryResult && + queryResult.rows.length > 0 && + chartConfig.xAxis && + (isPieChart || isApiSource + ? // ํŒŒ์ด/๋„๋„› ์ฐจํŠธ ๋˜๋Š” REST API + chartConfig.aggregation === "count" + ? true // count๋Š” Y์ถ• ์—†์–ด๋„ ๋จ + : hasYAxis // ๋‹ค๋ฅธ ์ง‘๊ณ„(sum, avg, max, min) ๋˜๋Š” ์ง‘๊ณ„ ์—†์Œ โ†’ Y์ถ• ํ•„์ˆ˜ + : // ์ผ๋ฐ˜ ์ฐจํŠธ (DB): Y์ถ• ํ•„์ˆ˜ + hasYAxis)); return (
@@ -178,20 +185,39 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave }: Element }`} > {/* ๋ชจ๋‹ฌ ํ—ค๋” */} -
-
-

{element.title} ์„ค์ •

-

- {isSimpleWidget - ? "๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์„ค์ •ํ•˜์„ธ์š”" - : currentStep === 1 - ? "๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์„ ํƒํ•˜์„ธ์š”" - : "์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์ฐจํŠธ๋ฅผ ์„ค์ •ํ•˜์„ธ์š”"} +

+
+
+

{element.title} ์„ค์ •

+

+ {isSimpleWidget + ? "๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์„ค์ •ํ•˜์„ธ์š”" + : currentStep === 1 + ? "๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์„ ํƒํ•˜์„ธ์š”" + : "์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์ฐจํŠธ๋ฅผ ์„ค์ •ํ•˜์„ธ์š”"} +

+
+ +
+ + {/* ์ปค์Šคํ…€ ์ œ๋ชฉ ์ž…๋ ฅ */} +
+ + setCustomTitle(e.target.value)} + placeholder={`์˜ˆ: ์ •๋น„ ์ผ์ • ๋ชฉ๋ก, ์ฐฝ๊ณ  ์œ„์น˜ ํ˜„ํ™ฉ ๋“ฑ (๋น„์›Œ๋‘๋ฉด ์ž๋™ ์ƒ์„ฑ)`} + className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary" + /> +

+ ๐Ÿ’ก ๋น„์›Œ๋‘๋ฉด ํ…Œ์ด๋ธ”๋ช…์œผ๋กœ ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค (์˜ˆ: "maintenance_schedules ๋ชฉ๋ก")

-
{/* ์ง„ํ–‰ ์ƒํ™ฉ ํ‘œ์‹œ - ๊ฐ„๋‹จํ•œ ์œ„์ ฏ์€ ํ‘œ์‹œ ์•ˆ ํ•จ */} diff --git a/frontend/components/admin/dashboard/types.ts b/frontend/components/admin/dashboard/types.ts index 833c033a..cdf70550 100644 --- a/frontend/components/admin/dashboard/types.ts +++ b/frontend/components/admin/dashboard/types.ts @@ -54,6 +54,7 @@ export interface DashboardElement { position: Position; size: Size; title: string; + customTitle?: string; // ์‚ฌ์šฉ์ž ์ •์˜ ์ œ๋ชฉ (์˜ต์…˜) content: string; dataSource?: ChartDataSource; // ๋ฐ์ดํ„ฐ ์†Œ์Šค ์„ค์ • chartConfig?: ChartConfig; // ์ฐจํŠธ ์„ค์ • diff --git a/frontend/components/dashboard/DashboardViewer.tsx b/frontend/components/dashboard/DashboardViewer.tsx index 5598d943..c6e941e3 100644 --- a/frontend/components/dashboard/DashboardViewer.tsx +++ b/frontend/components/dashboard/DashboardViewer.tsx @@ -37,11 +37,11 @@ function renderWidget(element: DashboardElement) { // === ์œ„์ ฏ ์ข…๋ฅ˜ === case "exchange": - return ; + return ; case "weather": - return ; + return ; case "calculator": - return ; + return ; case "clock": return (
@@ -56,7 +56,7 @@ function renderWidget(element: DashboardElement) { case "list-summary": return ; case "risk-alert": - return ; + return ; case "calendar": return ; case "status-summary": @@ -64,13 +64,13 @@ function renderWidget(element: DashboardElement) { // === ์šด์˜/์ž‘์—… ์ง€์› === case "todo": - return ; + return ; case "booking-alert": - return ; + return ; case "maintenance": - return ; + return ; case "document": - return ; + return ; case "list": return ; diff --git a/frontend/components/dashboard/widgets/BookingAlertWidget.tsx b/frontend/components/dashboard/widgets/BookingAlertWidget.tsx index 4c600079..b47f0fb4 100644 --- a/frontend/components/dashboard/widgets/BookingAlertWidget.tsx +++ b/frontend/components/dashboard/widgets/BookingAlertWidget.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react"; import { Check, X, Phone, MapPin, Package, Clock, AlertCircle } from "lucide-react"; +import { DashboardElement } from "@/components/admin/dashboard/types"; interface BookingRequest { id: string; @@ -19,7 +20,11 @@ interface BookingRequest { estimatedCost?: number; } -export default function BookingAlertWidget() { +interface BookingAlertWidgetProps { + element?: DashboardElement; +} + +export default function BookingAlertWidget({ element }: BookingAlertWidgetProps) { const [bookings, setBookings] = useState([]); const [newCount, setNewCount] = useState(0); const [loading, setLoading] = useState(true); @@ -156,7 +161,7 @@ export default function BookingAlertWidget() {
-

๐Ÿ”” ์˜ˆ์•ฝ ์š”์ฒญ ์•Œ๋ฆผ

+

๐Ÿ”” {element?.customTitle || "์˜ˆ์•ฝ ์š”์ฒญ ์•Œ๋ฆผ"}

{newCount > 0 && ( {newCount} diff --git a/frontend/components/dashboard/widgets/CalculatorWidget.tsx b/frontend/components/dashboard/widgets/CalculatorWidget.tsx index 6e7aad4d..b8816bbc 100644 --- a/frontend/components/dashboard/widgets/CalculatorWidget.tsx +++ b/frontend/components/dashboard/widgets/CalculatorWidget.tsx @@ -9,12 +9,14 @@ import React, { useState } from 'react'; import { Button } from '@/components/ui/button'; +import { DashboardElement } from '@/components/admin/dashboard/types'; interface CalculatorWidgetProps { + element?: DashboardElement; className?: string; } -export default function CalculatorWidget({ className = '' }: CalculatorWidgetProps) { +export default function CalculatorWidget({ element, className = '' }: CalculatorWidgetProps) { const [display, setDisplay] = useState('0'); const [previousValue, setPreviousValue] = useState(null); const [operation, setOperation] = useState(null); @@ -117,7 +119,10 @@ export default function CalculatorWidget({ className = '' }: CalculatorWidgetPro return (
-
+
+ {/* ์ œ๋ชฉ */} +

๐Ÿงฎ {element?.customTitle || "๊ณ„์‚ฐ๊ธฐ"}

+ {/* ๋””์Šคํ”Œ๋ ˆ์ด */}
diff --git a/frontend/components/dashboard/widgets/DocumentWidget.tsx b/frontend/components/dashboard/widgets/DocumentWidget.tsx index 7a85a556..6a15cce1 100644 --- a/frontend/components/dashboard/widgets/DocumentWidget.tsx +++ b/frontend/components/dashboard/widgets/DocumentWidget.tsx @@ -2,6 +2,7 @@ import React, { useState } from "react"; import { FileText, Download, Calendar, Folder, Search } from "lucide-react"; +import { DashboardElement } from "@/components/admin/dashboard/types"; interface Document { id: string; @@ -13,64 +14,69 @@ interface Document { description?: string; } -// ๋ชฉ ๋ฐ์ดํ„ฐ -const mockDocuments: Document[] = [ - { - id: "1", - name: "2025๋…„ 1์›” ์„ธ๊ธˆ๊ณ„์‚ฐ์„œ.pdf", - category: "์„ธ๊ธˆ๊ณ„์‚ฐ์„œ", - size: "1.2 MB", - uploadDate: "2025-01-05", - url: "/documents/tax-invoice-202501.pdf", - description: "1์›” ๋งค์ถœ ์„ธ๊ธˆ๊ณ„์‚ฐ์„œ", - }, - { - id: "2", - name: "์ฐจ๋Ÿ‰๋ณดํ—˜์ฆ๊ถŒ_์„œ์šธ12๊ฐ€3456.pdf", - category: "๋ณดํ—˜", - size: "856 KB", - uploadDate: "2024-12-20", - url: "/documents/insurance-vehicle-1.pdf", - description: "1ํ†ค ํŠธ๋Ÿญ ์ข…ํ•ฉ๋ณดํ—˜", - }, - { - id: "3", - name: "์šด์†ก๊ณ„์•ฝ์„œ_ABC๋ฌผ๋ฅ˜.pdf", - category: "๊ณ„์•ฝ์„œ", - size: "2.4 MB", - uploadDate: "2024-12-15", - url: "/documents/contract-abc-logistics.pdf", - description: "ABC๋ฌผ๋ฅ˜ ์—ฐ๊ฐ„ ์šด์†ก ๊ณ„์•ฝ", - }, - { - id: "4", - name: "2024๋…„ 12์›” ์„ธ๊ธˆ๊ณ„์‚ฐ์„œ.pdf", - category: "์„ธ๊ธˆ๊ณ„์‚ฐ์„œ", - size: "1.1 MB", - uploadDate: "2024-12-05", - url: "/documents/tax-invoice-202412.pdf", - }, - { - id: "5", - name: "ํ™”๋ฌผ๋ฐฐ์ƒ์ฑ…์ž„๋ณดํ—˜์ฆ๊ถŒ.pdf", - category: "๋ณดํ—˜", - size: "720 KB", - uploadDate: "2024-11-30", - url: "/documents/cargo-insurance.pdf", - description: "ํ™”๋ฌผ ๋ฐฐ์ƒ์ฑ…์ž„๋ณดํ—˜", - }, - { - id: "6", - name: "์ฐจ๊ณ ์ง€ ์ž„๋Œ€๊ณ„์•ฝ์„œ.pdf", - category: "๊ณ„์•ฝ์„œ", - size: "1.8 MB", - uploadDate: "2024-11-15", - url: "/documents/garage-lease-contract.pdf", - }, -]; +// ๋ชฉ ๋ฐ์ดํ„ฐ (ํ•˜๋“œ์ฝ”๋”ฉ - ์ฃผ์„์ฒ˜๋ฆฌ๋จ) +// const mockDocuments: Document[] = [ +// { +// id: "1", +// name: "2025๋…„ 1์›” ์„ธ๊ธˆ๊ณ„์‚ฐ์„œ.pdf", +// category: "์„ธ๊ธˆ๊ณ„์‚ฐ์„œ", +// size: "1.2 MB", +// uploadDate: "2025-01-05", +// url: "/documents/tax-invoice-202501.pdf", +// description: "1์›” ๋งค์ถœ ์„ธ๊ธˆ๊ณ„์‚ฐ์„œ", +// }, +// { +// id: "2", +// name: "์ฐจ๋Ÿ‰๋ณดํ—˜์ฆ๊ถŒ_์„œ์šธ12๊ฐ€3456.pdf", +// category: "๋ณดํ—˜", +// size: "856 KB", +// uploadDate: "2024-12-20", +// url: "/documents/insurance-vehicle-1.pdf", +// description: "1ํ†ค ํŠธ๋Ÿญ ์ข…ํ•ฉ๋ณดํ—˜", +// }, +// { +// id: "3", +// name: "์šด์†ก๊ณ„์•ฝ์„œ_ABC๋ฌผ๋ฅ˜.pdf", +// category: "๊ณ„์•ฝ์„œ", +// size: "2.4 MB", +// uploadDate: "2024-12-15", +// url: "/documents/contract-abc-logistics.pdf", +// description: "ABC๋ฌผ๋ฅ˜ ์—ฐ๊ฐ„ ์šด์†ก ๊ณ„์•ฝ", +// }, +// { +// id: "4", +// name: "2024๋…„ 12์›” ์„ธ๊ธˆ๊ณ„์‚ฐ์„œ.pdf", +// category: "์„ธ๊ธˆ๊ณ„์‚ฐ์„œ", +// size: "1.1 MB", +// uploadDate: "2024-12-05", +// url: "/documents/tax-invoice-202412.pdf", +// }, +// { +// id: "5", +// name: "ํ™”๋ฌผ๋ฐฐ์ƒ์ฑ…์ž„๋ณดํ—˜์ฆ๊ถŒ.pdf", +// category: "๋ณดํ—˜", +// size: "720 KB", +// uploadDate: "2024-11-30", +// url: "/documents/cargo-insurance.pdf", +// description: "ํ™”๋ฌผ ๋ฐฐ์ƒ์ฑ…์ž„๋ณดํ—˜", +// }, +// { +// id: "6", +// name: "์ฐจ๊ณ ์ง€ ์ž„๋Œ€๊ณ„์•ฝ์„œ.pdf", +// category: "๊ณ„์•ฝ์„œ", +// size: "1.8 MB", +// uploadDate: "2024-11-15", +// url: "/documents/garage-lease-contract.pdf", +// }, +// ]; -export default function DocumentWidget() { - const [documents] = useState(mockDocuments); +interface DocumentWidgetProps { + element?: DashboardElement; +} + +export default function DocumentWidget({ element }: DocumentWidgetProps) { + // TODO: ์‹ค์ œ API ์—ฐ๋™ ํ•„์š” + const [documents] = useState([]); const [filter, setFilter] = useState<"all" | Document["category"]>("all"); const [searchTerm, setSearchTerm] = useState(""); @@ -126,7 +132,7 @@ export default function DocumentWidget() { {/* ํ—ค๋” */}
-

๐Ÿ“‚ ๋ฌธ์„œ ๊ด€๋ฆฌ

+

๐Ÿ“‚ {element?.customTitle || "๋ฌธ์„œ ๊ด€๋ฆฌ"}

diff --git a/frontend/components/dashboard/widgets/ExchangeWidget.tsx b/frontend/components/dashboard/widgets/ExchangeWidget.tsx index 946363d4..86743326 100644 --- a/frontend/components/dashboard/widgets/ExchangeWidget.tsx +++ b/frontend/components/dashboard/widgets/ExchangeWidget.tsx @@ -12,14 +12,17 @@ import { TrendingUp, TrendingDown, RefreshCw, ArrowRightLeft } from 'lucide-reac import { Button } from '@/components/ui/button'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Input } from '@/components/ui/input'; +import { DashboardElement } from '@/components/admin/dashboard/types'; interface ExchangeWidgetProps { + element?: DashboardElement; baseCurrency?: string; targetCurrency?: string; refreshInterval?: number; // ์ƒˆ๋กœ๊ณ ์นจ ๊ฐ„๊ฒฉ (ms), ๊ธฐ๋ณธ๊ฐ’: 600000 (10๋ถ„) } export default function ExchangeWidget({ + element, baseCurrency = 'KRW', targetCurrency = 'USD', refreshInterval = 600000, @@ -136,7 +139,7 @@ export default function ExchangeWidget({ {/* ํ—ค๋” */}
-

๐Ÿ’ฑ ํ™˜์œจ

+

๐Ÿ’ฑ {element?.customTitle || "ํ™˜์œจ"}

{lastUpdated ? `์—…๋ฐ์ดํŠธ: ${lastUpdated.toLocaleTimeString('ko-KR', { diff --git a/frontend/components/dashboard/widgets/MaintenanceWidget.tsx b/frontend/components/dashboard/widgets/MaintenanceWidget.tsx index 634b8df8..361b7710 100644 --- a/frontend/components/dashboard/widgets/MaintenanceWidget.tsx +++ b/frontend/components/dashboard/widgets/MaintenanceWidget.tsx @@ -14,51 +14,52 @@ interface MaintenanceSchedule { estimatedCost?: number; } -// ๋ชฉ ๋ฐ์ดํ„ฐ -const mockSchedules: MaintenanceSchedule[] = [ - { - id: "1", - vehicleNumber: "์„œ์šธ12๊ฐ€3456", - vehicleType: "1ํ†ค ํŠธ๋Ÿญ", - maintenanceType: "์ •๊ธฐ์ ๊ฒ€", - scheduledDate: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000).toISOString(), - status: "scheduled", - notes: "6๊ฐœ์›” ์ •๊ธฐ์ ๊ฒ€", - estimatedCost: 300000, - }, - { - id: "2", - vehicleNumber: "๊ฒฝ๊ธฐ34๋‚˜5678", - vehicleType: "2.5ํ†ค ํŠธ๋Ÿญ", - maintenanceType: "์˜ค์ผ๊ตํ™˜", - scheduledDate: new Date(Date.now() + 1 * 24 * 60 * 60 * 1000).toISOString(), - status: "scheduled", - estimatedCost: 150000, - }, - { - id: "3", - vehicleNumber: "์ธ์ฒœ56๋‹ค7890", - vehicleType: "๋ผ๋ณด", - maintenanceType: "ํƒ€์ด์–ด๊ต์ฒด", - scheduledDate: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(), - status: "overdue", - notes: "๊ธด๊ธ‰", - estimatedCost: 400000, - }, - { - id: "4", - vehicleNumber: "๋ถ€์‚ฐ78๋ผ1234", - vehicleType: "1ํ†ค ํŠธ๋Ÿญ", - maintenanceType: "์ˆ˜๋ฆฌ", - scheduledDate: new Date().toISOString(), - status: "in_progress", - notes: "์—”์ง„ ์ ๊ฒ€ ์ค‘", - estimatedCost: 800000, - }, -]; +// ๋ชฉ ๋ฐ์ดํ„ฐ (ํ•˜๋“œ์ฝ”๋”ฉ - ์ฃผ์„์ฒ˜๋ฆฌ๋จ) +// const mockSchedules: MaintenanceSchedule[] = [ +// { +// id: "1", +// vehicleNumber: "์„œ์šธ12๊ฐ€3456", +// vehicleType: "1ํ†ค ํŠธ๋Ÿญ", +// maintenanceType: "์ •๊ธฐ์ ๊ฒ€", +// scheduledDate: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000).toISOString(), +// status: "scheduled", +// notes: "6๊ฐœ์›” ์ •๊ธฐ์ ๊ฒ€", +// estimatedCost: 300000, +// }, +// { +// id: "2", +// vehicleNumber: "๊ฒฝ๊ธฐ34๋‚˜5678", +// vehicleType: "2.5ํ†ค ํŠธ๋Ÿญ", +// maintenanceType: "์˜ค์ผ๊ตํ™˜", +// scheduledDate: new Date(Date.now() + 1 * 24 * 60 * 60 * 1000).toISOString(), +// status: "scheduled", +// estimatedCost: 150000, +// }, +// { +// id: "3", +// vehicleNumber: "์ธ์ฒœ56๋‹ค7890", +// vehicleType: "๋ผ๋ณด", +// maintenanceType: "ํƒ€์ด์–ด๊ต์ฒด", +// scheduledDate: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(), +// status: "overdue", +// notes: "๊ธด๊ธ‰", +// estimatedCost: 400000, +// }, +// { +// id: "4", +// vehicleNumber: "๋ถ€์‚ฐ78๋ผ1234", +// vehicleType: "1ํ†ค ํŠธ๋Ÿญ", +// maintenanceType: "์ˆ˜๋ฆฌ", +// scheduledDate: new Date().toISOString(), +// status: "in_progress", +// notes: "์—”์ง„ ์ ๊ฒ€ ์ค‘", +// estimatedCost: 800000, +// }, +// ]; export default function MaintenanceWidget() { - const [schedules] = useState(mockSchedules); + // TODO: ์‹ค์ œ API ์—ฐ๋™ ํ•„์š” + const [schedules] = useState([]); const [filter, setFilter] = useState<"all" | MaintenanceSchedule["status"]>("all"); const [selectedDate, setSelectedDate] = useState(new Date()); diff --git a/frontend/components/dashboard/widgets/MapSummaryWidget.tsx b/frontend/components/dashboard/widgets/MapSummaryWidget.tsx index 53db0b8e..e91746a9 100644 --- a/frontend/components/dashboard/widgets/MapSummaryWidget.tsx +++ b/frontend/components/dashboard/widgets/MapSummaryWidget.tsx @@ -150,7 +150,8 @@ export default function MapSummaryWidget({ element }: MapSummaryWidgetProps) { } }; - const displayTitle = tableName ? `${translateTableName(tableName)} ์œ„์น˜` : "์œ„์น˜ ์ง€๋„"; + // customTitle์ด ์žˆ์œผ๋ฉด ์‚ฌ์šฉ, ์—†์œผ๋ฉด ํ…Œ์ด๋ธ”๋ช…์œผ๋กœ ์ž๋™ ์ƒ์„ฑ + const displayTitle = element.customTitle || (tableName ? `${translateTableName(tableName)} ์œ„์น˜` : "์œ„์น˜ ์ง€๋„"); return (

@@ -181,13 +182,15 @@ export default function MapSummaryWidget({ element }: MapSummaryWidgetProps) { )} {/* ์ง€๋„ (ํ•ญ์ƒ ํ‘œ์‹œ) */} -
+
{/* ๋ธŒ์ด์›”๋“œ ํƒ€์ผ๋งต */} ([]); const [isRefreshing, setIsRefreshing] = useState(false); const [filter, setFilter] = useState("all"); @@ -163,7 +168,7 @@ export default function RiskAlertWidget() {
-

๋ฆฌ์Šคํฌ / ์•Œ๋ฆผ

+

{element?.customTitle || "๋ฆฌ์Šคํฌ / ์•Œ๋ฆผ"}

{stats.high > 0 && ( ๊ธด๊ธ‰ {stats.high}๊ฑด )} diff --git a/frontend/components/dashboard/widgets/StatusSummaryWidget.tsx b/frontend/components/dashboard/widgets/StatusSummaryWidget.tsx index e9641eee..e5478cdb 100644 --- a/frontend/components/dashboard/widgets/StatusSummaryWidget.tsx +++ b/frontend/components/dashboard/widgets/StatusSummaryWidget.tsx @@ -349,7 +349,8 @@ export default function StatusSummaryWidget({ return name; }; - const displayTitle = tableName ? `${translateTableName(tableName)} ํ˜„ํ™ฉ` : title; + // customTitle์ด ์žˆ์œผ๋ฉด ์‚ฌ์šฉ, ์—†์œผ๋ฉด ํ…Œ์ด๋ธ”๋ช…์œผ๋กœ ์ž๋™ ์ƒ์„ฑ + const displayTitle = element.customTitle || (tableName ? `${translateTableName(tableName)} ํ˜„ํ™ฉ` : title); return (
diff --git a/frontend/components/dashboard/widgets/TodoWidget.tsx b/frontend/components/dashboard/widgets/TodoWidget.tsx index f2cf3625..f43ba325 100644 --- a/frontend/components/dashboard/widgets/TodoWidget.tsx +++ b/frontend/components/dashboard/widgets/TodoWidget.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react"; import { Plus, Check, X, Clock, AlertCircle, GripVertical, ChevronDown } from "lucide-react"; +import { DashboardElement } from "@/components/admin/dashboard/types"; interface TodoItem { id: string; @@ -27,7 +28,11 @@ interface TodoStats { overdue: number; } -export default function TodoWidget() { +interface TodoWidgetProps { + element?: DashboardElement; +} + +export default function TodoWidget({ element }: TodoWidgetProps) { const [todos, setTodos] = useState([]); const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); @@ -193,7 +198,7 @@ export default function TodoWidget() { {/* ํ—ค๋” */}
-

โœ… To-Do / ๊ธด๊ธ‰ ์ง€์‹œ

+

โœ… {element?.customTitle || "To-Do / ๊ธด๊ธ‰ ์ง€์‹œ"}