"use client"; import React, { useState, useEffect } from "react"; import { Check, X, Phone, MapPin, Package, Clock, AlertCircle } from "lucide-react"; interface BookingRequest { id: string; customerName: string; customerPhone: string; pickupLocation: string; dropoffLocation: string; scheduledTime: string; vehicleType: "truck" | "van" | "car"; cargoType?: string; weight?: number; status: "pending" | "accepted" | "rejected" | "completed"; priority: "normal" | "urgent"; createdAt: string; estimatedCost?: number; } export default function BookingAlertWidget() { const [bookings, setBookings] = useState([]); const [newCount, setNewCount] = useState(0); const [loading, setLoading] = useState(true); const [filter, setFilter] = useState<"all" | "pending" | "accepted">("pending"); const [showNotification, setShowNotification] = useState(false); useEffect(() => { fetchBookings(); const interval = setInterval(fetchBookings, 10000); // 10초마다 갱신 return () => clearInterval(interval); }, [filter]); const fetchBookings = async () => { try { const token = localStorage.getItem("authToken"); const filterParam = filter !== "all" ? `?status=${filter}` : ""; const response = await fetch(`http://localhost:9771/api/bookings${filterParam}`, { headers: { Authorization: `Bearer ${token}`, }, }); if (response.ok) { const result = await response.json(); const newBookings = result.data || []; // 신규 예약이 있으면 알림 표시 if (result.newCount > 0 && newBookings.length > bookings.length) { setShowNotification(true); setTimeout(() => setShowNotification(false), 5000); } setBookings(newBookings); setNewCount(result.newCount); } } catch (error) { // console.error("예약 로딩 오류:", error); } finally { setLoading(false); } }; const handleAccept = async (id: string) => { if (!confirm("이 예약을 수락하시겠습니까?")) return; try { const token = localStorage.getItem("authToken"); const response = await fetch(`http://localhost:9771/api/bookings/${id}/accept`, { method: "POST", headers: { Authorization: `Bearer ${token}`, }, }); if (response.ok) { fetchBookings(); } } catch (error) { // console.error("예약 수락 오류:", error); } }; const handleReject = async (id: string) => { const reason = prompt("거절 사유를 입력하세요:"); if (!reason) return; try { const token = localStorage.getItem("authToken"); const response = await fetch(`http://localhost:9771/api/bookings/${id}/reject`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: JSON.stringify({ reason }), }); if (response.ok) { fetchBookings(); } } catch (error) { // console.error("예약 거절 오류:", error); } }; const getVehicleIcon = (type: string) => { switch (type) { case "truck": return "🚚"; case "van": return "🚐"; case "car": return "🚗"; default: return "🚗"; } }; const getTimeStatus = (scheduledTime: string) => { const now = new Date(); const scheduled = new Date(scheduledTime); const diff = scheduled.getTime() - now.getTime(); const hours = Math.floor(diff / (1000 * 60 * 60)); if (hours < 0) return { text: "⏰ 시간 초과", color: "text-red-600" }; if (hours < 2) return { text: `⏱️ ${hours}시간 후`, color: "text-red-600" }; if (hours < 4) return { text: `⏱️ ${hours}시간 후`, color: "text-orange-600" }; return { text: `📅 ${hours}시간 후`, color: "text-gray-600" }; }; const isNew = (createdAt: string) => { const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000); return new Date(createdAt) > fiveMinutesAgo; }; if (loading) { return (
로딩 중...
); } return (
{/* 신규 알림 배너 */} {showNotification && newCount > 0 && (
🔔 새로운 예약 {newCount}건이 도착했습니다!
)} {/* 헤더 */}

🔔 예약 요청 알림

{newCount > 0 && ( {newCount} )}
{/* 필터 */}
{(["pending", "accepted", "all"] as const).map((f) => ( ))}
{/* 예약 리스트 */}
{bookings.length === 0 ? (
📭
예약 요청이 없습니다
) : (
{bookings.map((booking) => (
{/* NEW 뱃지 */} {isNew(booking.createdAt) && booking.status === "pending" && (
🆕
)} {/* 우선순위 표시 */} {booking.priority === "urgent" && (
긴급 예약
)} {/* 고객 정보 */}
{getVehicleIcon(booking.vehicleType)}
{booking.customerName}
{booking.customerPhone}
{booking.status === "pending" && (
)} {booking.status === "accepted" && ( ✓ 수락됨 )}
{/* 경로 정보 */}
출발지
{booking.pickupLocation}
도착지
{booking.dropoffLocation}
{/* 상세 정보 */}
{booking.cargoType} ({booking.weight}kg)
{getTimeStatus(booking.scheduledTime).text}
{booking.estimatedCost && (
예상 비용: {booking.estimatedCost.toLocaleString()}원
)}
))}
)}
); }