@@ -21,6 +21,7 @@ import {
2121 RefreshCw ,
2222 Edit ,
2323 Check ,
24+ DollarSign ,
2425} from 'lucide-react' ;
2526
2627import { Button } from '@/components/ui/button' ;
@@ -45,6 +46,9 @@ import { Input } from '@/components/ui/input';
4546import { Label } from '@/components/ui/label' ;
4647import { Separator } from '@/components/ui/separator' ;
4748import { toast } from 'sonner' ;
49+ import { OrderStatusTimeline } from '@/components/orders/order-status-timeline' ;
50+ import { RefundDialog } from '@/components/orders/refund-dialog' ;
51+ import { OrderStatus } from '@prisma/client' ;
4852
4953// Types
5054interface OrderItem {
@@ -81,21 +85,28 @@ interface Customer {
8185interface Order {
8286 id : string ;
8387 orderNumber : string ;
84- status : string ;
88+ status : OrderStatus ;
8589 paymentStatus : string ;
8690 subtotal : number ;
8791 taxAmount : number ;
8892 shippingAmount : number ;
8993 discountAmount : number ;
9094 totalAmount : number ;
95+ refundedAmount ?: number ;
9196 shippingAddress : Address | string ;
9297 billingAddress : Address | string ;
9398 shippingMethod : string ;
9499 trackingNumber : string | null ;
95100 trackingUrl : string | null ;
96101 customerNote : string | null ;
102+ adminNote ?: string | null ;
97103 createdAt : string ;
98104 updatedAt : string ;
105+ fulfilledAt ?: string | null ;
106+ deliveredAt ?: string | null ;
107+ canceledAt ?: string | null ;
108+ cancelReason ?: string | null ;
109+ refundReason ?: string | null ;
99110 items : OrderItem [ ] ;
100111 customer ?: Customer | null ;
101112}
@@ -134,6 +145,7 @@ export function OrderDetailClient({ orderId, storeId }: OrderDetailClientProps)
134145 const [ trackingNumber , setTrackingNumber ] = useState ( '' ) ;
135146 const [ trackingUrl , setTrackingUrl ] = useState ( '' ) ;
136147 const [ isEditingTracking , setIsEditingTracking ] = useState ( false ) ;
148+ const [ isRefundDialogOpen , setIsRefundDialogOpen ] = useState ( false ) ;
137149
138150 // Fetch order details
139151 const fetchOrder = async ( ) => {
@@ -264,6 +276,40 @@ export function OrderDetailClient({ orderId, storeId }: OrderDetailClientProps)
264276 }
265277 } ;
266278
279+ // Handle refund
280+ const handleRefund = async ( amount : number , reason : string ) => {
281+ if ( ! order ) return ;
282+
283+ try {
284+ setUpdating ( true ) ;
285+
286+ const response = await fetch ( `/api/orders/${ order . id } /refund` , {
287+ method : 'POST' ,
288+ headers : { 'Content-Type' : 'application/json' } ,
289+ body : JSON . stringify ( {
290+ storeId,
291+ refundAmount : amount ,
292+ reason,
293+ } ) ,
294+ } ) ;
295+
296+ if ( ! response . ok ) {
297+ const error = await response . json ( ) ;
298+ throw new Error ( error . error || 'Failed to process refund' ) ;
299+ }
300+
301+ toast . success ( `Refund of ${ formatCurrency ( amount ) } processed successfully` ) ;
302+
303+ // Refresh order data
304+ await fetchOrder ( ) ;
305+ } catch ( error ) {
306+ console . error ( 'Error processing refund:' , error ) ;
307+ throw error ; // Let RefundDialog handle the error
308+ } finally {
309+ setUpdating ( false ) ;
310+ }
311+ } ;
312+
267313 // Format currency
268314 const formatCurrency = ( amount : number ) => {
269315 return new Intl . NumberFormat ( 'en-US' , {
@@ -347,6 +393,16 @@ export function OrderDetailClient({ orderId, storeId }: OrderDetailClientProps)
347393 </ div >
348394 </ div >
349395
396+ { /* Status Timeline */ }
397+ < Card >
398+ < CardHeader >
399+ < CardTitle > Order Status Timeline</ CardTitle >
400+ </ CardHeader >
401+ < CardContent >
402+ < OrderStatusTimeline currentStatus = { order . status } />
403+ </ CardContent >
404+ </ Card >
405+
350406 < div className = "grid gap-6 md:grid-cols-3" >
351407 { /* Left Column - Order Details */ }
352408 < div className = "md:col-span-2 space-y-6" >
@@ -609,6 +665,52 @@ export function OrderDetailClient({ orderId, storeId }: OrderDetailClientProps)
609665 </ CardContent >
610666 </ Card >
611667
668+ { /* Refund Management */ }
669+ { ( order . status === 'DELIVERED' || order . status === 'PAID' ) && (
670+ < Card >
671+ < CardHeader >
672+ < CardTitle className = "flex items-center gap-2" >
673+ < DollarSign className = "h-4 w-4" />
674+ Refund Management
675+ </ CardTitle >
676+ </ CardHeader >
677+ < CardContent className = "space-y-4" >
678+ < div className = "rounded-lg border p-3 bg-muted/50" >
679+ < div className = "space-y-1 text-sm" >
680+ < div className = "flex justify-between" >
681+ < span className = "text-muted-foreground" > Order Total:</ span >
682+ < span className = "font-medium" > { formatCurrency ( order . totalAmount ) } </ span >
683+ </ div >
684+ { order . refundedAmount && order . refundedAmount > 0 && (
685+ < div className = "flex justify-between" >
686+ < span className = "text-muted-foreground" > Already Refunded:</ span >
687+ < span className = "font-medium text-orange-600" >
688+ -{ formatCurrency ( order . refundedAmount ) }
689+ </ span >
690+ </ div >
691+ ) }
692+ < div className = "flex justify-between pt-1 border-t" >
693+ < span className = "font-semibold" > Refundable Balance:</ span >
694+ < span className = "font-semibold" >
695+ { formatCurrency ( order . totalAmount - ( order . refundedAmount || 0 ) ) }
696+ </ span >
697+ </ div >
698+ </ div >
699+ </ div >
700+
701+ < Button
702+ onClick = { ( ) => setIsRefundDialogOpen ( true ) }
703+ disabled = { updating || ( order . totalAmount - ( order . refundedAmount || 0 ) ) <= 0 }
704+ className = "w-full"
705+ variant = "destructive"
706+ >
707+ < DollarSign className = "h-4 w-4 mr-2" />
708+ Issue Refund
709+ </ Button >
710+ </ CardContent >
711+ </ Card >
712+ ) }
713+
612714 { /* Customer Note */ }
613715 { order . customerNote && (
614716 < Card >
@@ -627,6 +729,17 @@ export function OrderDetailClient({ orderId, storeId }: OrderDetailClientProps)
627729 ) }
628730 </ div >
629731 </ div >
732+
733+ { /* Refund Dialog */ }
734+ < RefundDialog
735+ open = { isRefundDialogOpen }
736+ onOpenChange = { setIsRefundDialogOpen }
737+ onRefund = { handleRefund }
738+ totalAmount = { order . totalAmount }
739+ refundedAmount = { order . refundedAmount || 0 }
740+ orderNumber = { order . orderNumber }
741+ loading = { updating }
742+ />
630743 </ div >
631744 ) ;
632745}
0 commit comments