convert this to vue 3
import React, { useState, useEffect } from 'react'
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Badge } from "@/components/ui/badge"
import { Textarea } from "@/components/ui/textarea"
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"
import { Check, Truck, Building, DollarSign, FileText, Search, Filter, Undo, Trash2, Printer, Download } from 'lucide-react'
// Mock data and functions (unchanged)
const mockOrderConfirmation = {
orderId: 'ORD-12345',
customerName: 'Acme Corp',
pickups: [
{ address: "123 Pickup St, City1", details: "2 pallets" },
{ address: "456 Pickup Ave, City2", details: "1 container" }
],
deliveries: [
{ address: "789 Delivery Rd, City3", details: "All items" }
],
specialInstructions: "Handle with care",
totalAmount: 1000,
freightDeclaredValue: 5000
}
const mockFleetTrucks = [
{ id: 'truck1', name: 'Truck 1' },
{ id: 'truck2', name: 'Truck 2' },
{ id: 'truck3', name: 'Truck 3' },
]
const mockThirdPartyCarriers = [
{ id: 'carrier1', name: 'Carrier A' },
{ id: 'carrier2', name: 'Carrier B' },
{ id: 'carrier3', name: 'Carrier C' },
]
const mockDrivers = [
{ id: 'driver1', name: 'John Doe' },
{ id: 'driver2', name: 'Jane Smith' },
{ id: 'driver3', name: 'Mike Johnson' },
]
interface OrderSegment {
id: string
pickupAddress: string
deliveryAddress: string
assignedVehicle: string
isThirdParty: boolean
driver: string
amount: number
state: 'Pending' | 'In Progress' | 'Delivered'
}
interface Order {
orderId: string
customerName: string
segments: OrderSegment[]
specialInstructions: string
totalAmount: number
freightDeclaredValue: number
commission: number
}
export default function SplitOrderHandling() {
const [currentStep, setCurrentStep] = useState(1)
const [order, setOrder] = useState<Order | null>(null)
const [isFinalized, setIsFinalized] = useState(false)
const [dispatchHistory, setDispatchHistory] = useState<OrderSegment[][]>([])
const [finalizeHistory, setFinalizeHistory] = useState<boolean[]>([])
const [invoiceGenerated, setInvoiceGenerated] = useState(false)
const [reportGenerated, setReportGenerated] = useState(false)
useEffect(() => {
// Simulate order confirmation upload
const initialOrder = {
orderId: mockOrderConfirmation.orderId,
customerName: mockOrderConfirmation.customerName,
segments: [
{
id: 'segment1',
pickupAddress: mockOrderConfirmation.pickups[0].address,
deliveryAddress: mockOrderConfirmation.deliveries[0].address,
assignedVehicle: '',
isThirdParty: false,
driver: '',
amount: mockOrderConfirmation.totalAmount * 0.9, // 90% of total amount, leaving 10% for commission
state: 'Pending'
}
],
specialInstructions: mockOrderConfirmation.specialInstructions,
totalAmount: mockOrderConfirmation.totalAmount,
freightDeclaredValue: mockOrderConfirmation.freightDeclaredValue,
commission: mockOrderConfirmation.totalAmount * 0.1 // 10% of total amount
}
setOrder(initialOrder)
setDispatchHistory([initialOrder.segments])
setFinalizeHistory([false])
}, [])
const handleNextStep = () => {
setCurrentStep(prev => Math.min(prev + 1, 7))
}
const handlePrevStep = () => {
setCurrentStep(prev => Math.max(prev - 1, 1))
}
const handleSplitDispatch = () => {
if (order) {
const newSegments = [
...order.segments,
{
id: `segment${order.segments.length + 1}`,
pickupAddress: mockOrderConfirmation.pickups[1].address,
deliveryAddress: mockOrderConfirmation.deliveries[0].address,
assignedVehicle: '',
isThirdParty: false,
driver: '',
amount: 0,
state: 'Pending'
}
]
setOrder({
...order,
segments: newSegments
})
setDispatchHistory([...dispatchHistory, newSegments])
}
}
const handleUndoDispatch = () => {
if (dispatchHistory.length > 1) {
const previousSegments = dispatchHistory[dispatchHistory.length - 2]
setOrder(prevOrder => ({
...prevOrder!,
segments: previousSegments
}))
setDispatchHistory(prevHistory => prevHistory.slice(0, -1))
}
}
const handleDeleteDispatch = (segmentId: string) => {
if (order && order.segments.length > 1) {
const newSegments = order.segments.filter(segment => segment.id !== segmentId)
setOrder({
...order,
segments: newSegments
})
setDispatchHistory([...dispatchHistory, newSegments])
}
}
const handleVehicleAssignment = (segmentId: string, vehicleId: string, isThirdParty: boolean) => {
if (order) {
setOrder({
...order,
segments: order.segments.map(segment =>
segment.id === segmentId
? { ...segment, assignedVehicle: vehicleId, isThirdParty, driver: isThirdParty ? '' : segment.driver }
: segment
)
})
}
}
const handleDriverAssignment = (segmentId: string, driverId: string) => {
if (order) {
setOrder({
...order,
segments: order.segments.map(segment =>
segment.id === segmentId
? { ...segment, driver: driverId }
: segment
)
})
}
}
const handleAmountChange = (segmentId: string, amount: number) => {
if (order) {
const otherSegmentsTotal = order.segments
.filter(s => s.id !== segmentId)
.reduce((sum, s) => sum + (isNaN(s.amount) ? 0 : s.amount), 0)
const maxAllowedAmount = order.totalAmount - otherSegmentsTotal - order.commission
const newAmount = isNaN(amount) ? 0 : Math.min(amount, maxAllowedAmount)
setOrder({
...order,
segments: order.segments.map(segment =>
segment.id === segmentId
? { ...segment, amount: newAmount }
: segment
)
})
}
}
const handleCommissionChange = (commission: number) => {
if (order) {
const segmentsTotal = order.segments.reduce((sum, segment) => sum + (isNaN(segment.amount) ? 0 : segment.amount), 0)
const maxAllowedCommission = order.totalAmount - segmentsTotal
const newCommission = isNaN(commission) ? 0 : Math.min(commission, maxAllowedCommission)
setOrder({
...order,
commission: newCommission
})
}
}
const handleMoveRemainingToCommission = () => {
if (order) {
const segmentsTotal = order.segments.reduce((sum, segment) => sum + (isNaN(segment.amount) ? 0 : segment.amount), 0)
const remainingAmount = order.totalAmount - segmentsTotal - order.commission
setOrder({
...order,
commission: order.commission + remainingAmount
})
}
}
const handleStateChange = (segmentId: string, newState: 'Pending' | 'In Progress' | 'Delivered') => {
if (order) {
setOrder({
...order,
segments: order.segments.map(segment =>
segment.id === segmentId
? { ...segment, state: newState }
: segment
)
})
}
}
const handleFinalize = () => {
setIsFinalized(true)
setFinalizeHistory([...finalizeHistory, true])
}
const handleUndoFinalize = () => {
if (finalizeHistory.length > 1) {
setIsFinalized(finalizeHistory[finalizeHistory.length - 2])
setFinalizeHistory(prevHistory => prevHistory.slice(0, -1))
}
}
const handleGenerateInvoice = () => {
setInvoiceGenerated(true)
}
const handleGenerateReport = () => {
setReportGenerated(true)
}
const renderStep = () => {
switch (currentStep) {
case 1:
return (
<Card>
<CardHeader>
<CardTitle>1. Order Confirmation</CardTitle>
</CardHeader>
<CardContent>
{order && (
<>
<div className="grid grid-cols-2 gap-4 mb-4">
<div>
<Label>Order ID</Label>
<Input value={order.orderId} readOnly />
</div>
<div>
<Label>Customer Name</Label>
<Input value={order.customerName} readOnly />
</div>
<div>
<Label>Total Amount</Label>
<Input value={`$${order.totalAmount.toFixed(2)}`} readOnly />
</div>
<div>
<Label>Freight Declared Value</Label>
<Input value={`$${order.freightDeclaredValue.toFixed(2)}`} readOnly />
</div>
</div>
<div className="mb-4">
<Label>Special Instructions</Label>
<Textarea value={order.specialInstructions} readOnly />
</div>
<div>
<Label>Segments</Label>
<Table>
<TableHeader>
<TableRow>
<TableHead>Pickup</TableHead>
<TableHead>Delivery</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{order.segments.map((segment, index) => (
<TableRow key={index}>
<TableCell>{segment.pickupAddress}</TableCell>
<TableCell>{segment.deliveryAddress}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</>
)}
</CardContent>
</Card>
)
case 2:
return (
<Card>
<CardHeader>
<CardTitle>2. Dispatch Creation</CardTitle>
</CardHeader>
<CardContent>
{order && (
<>
<div className="flex justify-end mb-4 space-x-2">
<Button variant="outline" size="sm" onClick={handleSplitDispatch}>
Split Dispatch
</Button>
<Button variant="outline" size="sm" onClick={handleUndoDispatch} disabled={dispatchHistory.length <= 1}>
<Undo className="w-4 h-4 mr-2" />
Undo
</Button>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead>Pickup</TableHead>
<TableHead>Delivery</TableHead>
<TableHead>Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{order.segments.map((segment, index) => (
<TableRow key={index}>
<TableCell>{segment.pickupAddress}</TableCell>
<TableCell>{segment.deliveryAddress}</TableCell>
<TableCell>
<Button
variant="ghost"
size="sm"
onClick={() => handleDeleteDispatch(segment.id)}
disabled={order.segments.length <= 1}
>
<Trash2 className="w-4 h-4" />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</>
)}
</CardContent>
</Card>
)
case 3:
return (
<Card>
<CardHeader>
<CardTitle>3. Dispatch List</CardTitle>
</CardHeader>
<CardContent>
{order && (
<>
<div className="mb-4">
<Label>Total Amount: ${order.totalAmount.toFixed(2)}</Label>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead>Pickup</TableHead>
<TableHead>Delivery</TableHead>
<TableHead>Vehicle</TableHead>
<TableHead>Driver</TableHead>
<TableHead>Amount</TableHead>
<TableHead>State</TableHead>
<TableHead>Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{order.segments.map((segment, index) => (
<TableRow key={index}>
<TableCell>{segment.pickupAddress}</TableCell>
<TableCell>{segment.deliveryAddress}</TableCell>
<TableCell>{segment.assignedVehicle || 'Not assigned'}</TableCell>
<TableCell>{segment.driver || 'Not assigned'}</TableCell>
<TableCell>
<Input
type="number"
value={isNaN(segment.amount) ? '' : segment.amount}
onChange={(e) => handleAmountChange(segment.id, parseFloat(e.target.value))}
className="w-24"
/>
</TableCell>
<TableCell>
<Badge className={
segment.state === 'Pending' ? 'bg-yellow-500' :
segment.state === 'In Progress' ? 'bg-blue-500' :
'bg-green-500'
}>
{segment.state}
</Badge>
</TableCell>
<TableCell>
<Select onValueChange={(value) => handleStateChange(segment.id, value as any)} value={segment.state}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Change state" />
</SelectTrigger>
<SelectContent>
<SelectItem value="Pending">Pending</SelectItem>
<SelectItem value="In Progress">In Progress</SelectItem>
<SelectItem value="Delivered">Delivered</SelectItem>
</SelectContent>
</Select>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<div className="mt-4 grid grid-cols-2 gap-4">
<div>
<Label>Total Split Amount: ${order.segments.reduce((sum, segment) => sum + (isNaN(segment.amount) ? 0 : segment.amount), 0).toFixed(2)}</Label>
</div>
<div>
<Label>$ Commission</Label>
<Input
type="number"
value={isNaN(order.commission) ? '' : order.commission}
onChange={(e) => handleCommissionChange(parseFloat(e.target.value))}
className="w-24"
/>
</div>
</div>
<div className="mt-2 flex justify-between items-center">
<Label>Remaining Amount: ${(order.totalAmount - order.segments.reduce((sum, segment) => sum + (isNaN(segment.amount) ? 0 : segment.amount), 0) - (isNaN(order.commission) ? 0 : order.commission)).toFixed(2)}</Label>
<Button onClick={handleMoveRemainingToCommission}>
Move Remaining to Commission
</Button>
</div>
</>
)}
</CardContent>
</Card>
)
case 4:
return (
<Card>
<CardHeader>
<CardTitle>4. Split Dispatch Assignment</CardTitle>
</CardHeader>
<CardContent>
{order && order.segments.map((segment, index) => (
<Card key={index} className="mb-4">
<CardHeader>
<CardTitle>Segment {index + 1}</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4 mb-4">
<div>
<Label>Pickup Address</Label>
<Input value={segment.pickupAddress} readOnly />
</div>
<div>
<Label>Delivery Address</Label>
<Input value={segment.deliveryAddress} readOnly />
</div>
</div>
<Tabs defaultValue="fleet" className="w-full mb-4">
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="fleet">Fleet Truck</TabsTrigger>
<TabsTrigger value="thirdparty">Third-Party Carrier</TabsTrigger>
</TabsList>
<TabsContent value="fleet">
<Select
onValueChange={(value) => handleVehicleAssignment(segment.id, value, false)}
value={!segment.isThirdParty ? segment.assignedVehicle : undefined}
>
<SelectTrigger>
<SelectValue placeholder="Select a truck" />
</SelectTrigger>
<SelectContent>
{mockFleetTrucks.map((truck) => (
<SelectItem key={truck.id} value={truck.id}>{truck.name}</SelectItem>
))}
</SelectContent>
</Select>
<div className="mt-4">
<Label>Driver</Label>
<Select
onValueChange={(value) => handleDriverAssignment(segment.id, value)}
value={segment.driver}
>
<SelectTrigger>
<SelectValue placeholder="Select a driver" />
</SelectTrigger>
<SelectContent>
{mockDrivers.map((driver) => (
<SelectItem key={driver.id} value={driver.id}>{driver.name}</SelectItem>
))}
</SelectContent>
</Select>
</div>
</TabsContent>
<TabsContent value="thirdparty">
<Select
onValueChange={(value) => handleVehicleAssignment(segment.id, value, true)}
value={segment.isThirdParty ? segment.assignedVehicle : undefined}
>
<SelectTrigger>
<SelectValue placeholder="Select a carrier" />
</SelectTrigger>
<SelectContent>
{mockThirdPartyCarriers.map((carrier) => (
<SelectItem key={carrier.id} value={carrier.id}>{carrier.name}</SelectItem>
))}
</SelectContent>
</Select>
</TabsContent>
</Tabs>
<div className="mb-4">
<Label>Amount</Label>
<Input
type="number"
value={isNaN(segment.amount) ? '' : segment.amount}
readOnly
/>
</div>
</CardContent>
</Card>
))}
</CardContent>
</Card>
)
case 5:
return (
<Card>
<CardHeader>
<CardTitle>5. Final Review and Completion</CardTitle>
</CardHeader>
<CardContent>
{order && (
<>
<div className="grid grid-cols-2 gap-4 mb-4">
<div>
<strong>Order ID:</strong> {order.orderId}
</div>
<div>
<strong>Customer:</strong> {order.customerName}
</div>
<div>
<strong>Total Amount:</strong> ${order.totalAmount.toFixed(2)}
</div>
<div>
<strong>Total Split Amount:</strong> ${order.segments.reduce((sum, segment) => sum + (isNaN(segment.amount) ? 0 : segment.amount), 0).toFixed(2)}
</div>
<div>
<strong>Commission:</strong> ${isNaN(order.commission) ? '0.00' : order.commission.toFixed(2)}
</div>
<div>
<strong>Status:</strong> {isFinalized ?
<Badge className="bg-green-500">Finalized</Badge> :
<Badge className="bg-yellow-500">Pending</Badge>
}
</div>
</div>
<Accordion type="single" collapsible className="w-full mb-4">
<AccordionItem value="segments">
<AccordionTrigger>View Segments</AccordionTrigger>
<AccordionContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>Pickup</TableHead>
<TableHead>Delivery</TableHead>
<TableHead>Vehicle</TableHead>
<TableHead>Driver</TableHead>
<TableHead>Amount</TableHead>
<TableHead>State</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{order.segments.map((segment, index) => (
<TableRow key={index}>
<TableCell>{segment.pickupAddress}</TableCell>
<TableCell>{segment.deliveryAddress}</TableCell>
<TableCell>{segment.assignedVehicle}</TableCell>
<TableCell>{segment.isThirdParty ? 'N/A' : segment.driver}</TableCell>
<TableCell>${isNaN(segment.amount) ? '0.00' : segment.amount.toFixed(2)}</TableCell>
<TableCell>{segment.state}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</AccordionContent>
</AccordionItem>
</Accordion>
<div className="flex gap-4">
<AlertDialog>
<AlertDialogTrigger asChild>
<Button disabled={isFinalized}>
<Check className="mr-2 h-4 w-4" /> Finalize Order
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure you want to finalize this order?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. Please make sure all details are correct before finalizing.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={handleFinalize}>Finalize</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<Button onClick={handleUndoFinalize} disabled={!isFinalized || finalizeHistory.length <= 1}>
<Undo className="mr-2 h-4 w-4" /> Undo Finalize
</Button>
<Button onClick={() => setCurrentStep(6)} disabled={!isFinalized}>
<DollarSign className="mr-2 h-4 w-4" /> Generate Invoice
</Button>
<Button onClick={() => setCurrentStep(7)} disabled={!isFinalized}>
<FileText className="mr-2 h-4 w-4" /> Generate Report
</Button>
</div>
</>
)}
</CardContent>
</Card>
)
case 6:
return (
<Card>
<CardHeader>
<CardTitle>6. Generate Invoice</CardTitle>
</CardHeader>
<CardContent>
{order && (
<>
<div className="grid grid-cols-2 gap-4 mb-4">
<div>
<Label>Invoice Number</Label>
<Input value={`INV-${order.orderId}`} readOnly />
</div>
<div>
<Label>Invoice Date</Label>
<Input value={new Date().toISOString().split('T')[0]} readOnly />
</div>
<div>
<Label>Customer Name</Label>
<Input value={order.customerName} readOnly />
</div>
<div>
<Label>Total Amount</Label>
<Input value={`$${order.totalAmount.toFixed(2)}`} readOnly />
</div>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead>Description</TableHead>
<TableHead>Quantity</TableHead>
<TableHead>Unit Price</TableHead>
<TableHead>Total</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{order.segments.map((segment, index) => (
<TableRow key={index}>
<TableCell>{`Delivery from ${segment.pickupAddress} to ${segment.deliveryAddress}`}</TableCell>
<TableCell>1</TableCell>
<TableCell>${isNaN(segment.amount) ? '0.00' : segment.amount.toFixed(2)}</TableCell>
<TableCell>${isNaN(segment.amount) ? '0.00' : segment.amount.toFixed(2)}</TableCell>
</TableRow>
))}
<TableRow>
<TableCell>Commission</TableCell>
<TableCell>1</TableCell>
<TableCell>${isNaN(order.commission) ? '0.00' : order.commission.toFixed(2)}</TableCell>
<TableCell>${isNaN(order.commission) ? '0.00' : order.commission.toFixed(2)}</TableCell>
</TableRow>
</TableBody>
</Table>
<div className="flex justify-end mt-4">
<Button onClick={handleGenerateInvoice} disabled={invoiceGenerated}>
<Printer className="mr-2 h-4 w-4" /> {invoiceGenerated ? 'Invoice Generated' : 'Generate Invoice'}
</Button>
</div>
</>
)}
</CardContent>
</Card>
)
case 7:
return (
<Card>
<CardHeader>
<CardTitle>7. Generate Report</CardTitle>
</CardHeader>
<CardContent>
{order && (
<>
<div className="grid grid-cols-2 gap-4 mb-4">
<div>
<Label>Report Number</Label>
<Input value={`REP-${order.orderId}`} readOnly />
</div>
<div>
<Label>Report Date</Label>
<Input value={new Date().toISOString().split('T')[0]} readOnly />
</div>
<div>
<Label>Customer Name</Label>
<Input value={order.customerName} readOnly />
</div>
<div>
<Label>Total Segments</Label>
<Input value={order.segments.length.toString()} readOnly />
</div>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead>Segment</TableHead>
<TableHead>Pickup</TableHead>
<TableHead>Delivery</TableHead>
<TableHead>Vehicle</TableHead>
<TableHead>Driver</TableHead>
<TableHead>Amount</TableHead>
<TableHead>State</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{order.segments.map((segment, index) => (
<TableRow key={index}>
<TableCell>{index + 1}</TableCell>
<TableCell>{segment.pickupAddress}</TableCell>
<TableCell>{segment.deliveryAddress}</TableCell>
<TableCell>{segment.assignedVehicle}</TableCell>
<TableCell>{segment.isThirdParty ? 'N/A' : segment.driver}</TableCell>
<TableCell>${isNaN(segment.amount) ? '0.00' : segment.amount.toFixed(2)}</TableCell>
<TableCell>{segment.state}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<div className="mt-4">
<Label>Commission: ${isNaN(order.commission) ? '0.00' : order.commission.toFixed(2)}</Label>
</div>
<div className="flex justify-end mt-4">
<Button onClick={handleGenerateReport} disabled={reportGenerated}>
<Download className="mr-2 h-4 w-4" /> {reportGenerated ? 'Report Generated' : 'Generate Report'}
</Button>
</div>
</>
)}
</CardContent>
</Card>
)
default:
return null
}
}
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">Split Order Handling</h1>
{renderStep()}
<div className="flex justify-between mt-4">
<Button onClick={handlePrevStep} disabled={currentStep === 1}>Previous</Button>
<Button onClick={handleNextStep} disabled={currentStep === 7 || (currentStep === 3 && order && (order.totalAmount - order.segments.reduce((sum, segment) => sum + (isNaN(segment.amount) ? 0 : segment.amount), 0) - (isNaN(order.commission) ? 0 : order.commission)) !== 0)}>Next</Button>
</div>
</div>
)
}