161 lines
6.4 KiB
JavaScript
161 lines
6.4 KiB
JavaScript
import React from "react";
|
||
import { Button } from "@/components/ui/button";
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogFooter,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from "@/components/ui/dialog";
|
||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||
import { Badge } from "@/components/ui/badge";
|
||
import { AlertTriangle, Clock, DollarSign, Calendar, Users } from "lucide-react";
|
||
import { format, differenceInHours } from "date-fns";
|
||
|
||
// Calculate if cancellation fee applies
|
||
export const calculateCancellationFee = (eventDate, eventStartTime, assignedCount) => {
|
||
const now = new Date();
|
||
|
||
// Combine event date and start time
|
||
const eventDateTime = new Date(`${eventDate}T${eventStartTime || '00:00'}`);
|
||
const hoursUntilEvent = differenceInHours(eventDateTime, now);
|
||
|
||
// Rule: 24+ hours = no fee, < 24 hours = 4-hour fee per worker
|
||
const feeApplies = hoursUntilEvent < 24;
|
||
const feeAmount = feeApplies ? assignedCount * 4 * 50 : 0; // Assuming $50/hour average
|
||
|
||
return {
|
||
feeApplies,
|
||
hoursUntilEvent,
|
||
feeAmount,
|
||
assignedCount
|
||
};
|
||
};
|
||
|
||
export default function CancellationFeeModal({
|
||
open,
|
||
onClose,
|
||
onConfirm,
|
||
event,
|
||
isSubmitting
|
||
}) {
|
||
if (!event) return null;
|
||
|
||
const eventStartTime = event.shifts?.[0]?.roles?.[0]?.start_time || '09:00';
|
||
const assignedCount = event.assigned_staff?.length || 0;
|
||
const feeData = calculateCancellationFee(event.date, eventStartTime, assignedCount);
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onClose}>
|
||
<DialogContent className="max-w-xl">
|
||
<DialogHeader>
|
||
<div className="flex items-center gap-3 mb-2">
|
||
<div className="w-12 h-12 bg-red-100 rounded-xl flex items-center justify-center">
|
||
<AlertTriangle className="w-6 h-6 text-red-600" />
|
||
</div>
|
||
<div>
|
||
<DialogTitle className="text-2xl font-bold text-red-700">
|
||
Confirm Order Cancellation
|
||
</DialogTitle>
|
||
<DialogDescription className="text-slate-600 mt-1">
|
||
{feeData.feeApplies
|
||
? "⚠️ Cancellation fee will apply"
|
||
: "✅ No cancellation fee"
|
||
}
|
||
</DialogDescription>
|
||
</div>
|
||
</div>
|
||
</DialogHeader>
|
||
|
||
<div className="space-y-4 py-4">
|
||
{/* Event Summary */}
|
||
<div className="bg-slate-50 border border-slate-200 rounded-xl p-4">
|
||
<h4 className="font-bold text-slate-900 mb-3">{event.event_name}</h4>
|
||
<div className="grid grid-cols-2 gap-3 text-sm">
|
||
<div className="flex items-center gap-2">
|
||
<Calendar className="w-4 h-4 text-blue-600" />
|
||
<span>{format(new Date(event.date), 'MMM d, yyyy')}</span>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<Clock className="w-4 h-4 text-blue-600" />
|
||
<span>{eventStartTime}</span>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<Users className="w-4 h-4 text-blue-600" />
|
||
<span>{assignedCount} Staff Assigned</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Time Until Event */}
|
||
<Alert className={feeData.feeApplies ? "bg-red-50 border-red-300" : "bg-green-50 border-green-300"}>
|
||
<AlertDescription>
|
||
<div className="flex items-center gap-2 mb-2">
|
||
<Clock className={`w-5 h-5 ${feeData.feeApplies ? 'text-red-600' : 'text-green-600'}`} />
|
||
<span className="font-bold text-slate-900">
|
||
{feeData.hoursUntilEvent} hours until event
|
||
</span>
|
||
</div>
|
||
<p className="text-sm text-slate-700">
|
||
{feeData.feeApplies
|
||
? "Canceling within 24 hours triggers a 4-hour minimum fee per assigned worker."
|
||
: "You're canceling more than 24 hours in advance - no penalty applies."
|
||
}
|
||
</p>
|
||
</AlertDescription>
|
||
</Alert>
|
||
|
||
{/* Fee Breakdown */}
|
||
{feeData.feeApplies && (
|
||
<div className="bg-gradient-to-r from-red-50 to-orange-50 border-2 border-red-300 rounded-xl p-5">
|
||
<div className="flex items-center gap-2 mb-4">
|
||
<DollarSign className="w-5 h-5 text-red-600" />
|
||
<h4 className="font-bold text-red-900">Cancellation Fee Breakdown</h4>
|
||
</div>
|
||
|
||
<div className="space-y-3">
|
||
<div className="flex items-center justify-between p-3 bg-white rounded-lg">
|
||
<span className="text-sm text-slate-700">Assigned Staff</span>
|
||
<span className="font-bold text-slate-900">{assignedCount} workers</span>
|
||
</div>
|
||
<div className="flex items-center justify-between p-3 bg-white rounded-lg">
|
||
<span className="text-sm text-slate-700">Minimum Charge</span>
|
||
<span className="font-bold text-slate-900">4 hours each</span>
|
||
</div>
|
||
<div className="flex items-center justify-between p-4 bg-red-100 rounded-lg border-2 border-red-300">
|
||
<span className="font-bold text-red-900">Total Cancellation Fee</span>
|
||
<span className="text-2xl font-bold text-red-700">
|
||
${feeData.feeAmount.toLocaleString()}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Warning Text */}
|
||
<Alert className="bg-yellow-50 border-yellow-300">
|
||
<AlertDescription className="text-sm text-yellow-900">
|
||
<strong>⚠️ This action cannot be undone.</strong> The vendor will be notified immediately,
|
||
and all assigned staff will be released from this event.
|
||
</AlertDescription>
|
||
</Alert>
|
||
</div>
|
||
|
||
<DialogFooter>
|
||
<Button variant="outline" onClick={onClose}>
|
||
Keep Order
|
||
</Button>
|
||
<Button
|
||
variant="destructive"
|
||
onClick={onConfirm}
|
||
disabled={isSubmitting}
|
||
className="bg-red-600 hover:bg-red-700"
|
||
>
|
||
{isSubmitting ? "Canceling..." : `Confirm Cancellation${feeData.feeApplies ? ` ($${feeData.feeAmount})` : ''}`}
|
||
</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
);
|
||
} |