Files

156 lines
8.2 KiB
TypeScript

import { usePage, Link } from '@inertiajs/react';
import { PageProps, RetentionReminderItem } from '@/types';
import { useState } from 'react';
import { AlertCircle, CheckCircle2, ChevronRight, DollarSign, Send, UploadCloud, X } from 'lucide-react';
import { Button } from '@/Components/ui/button';
import { Badge } from '@/Components/ui/badge';
import RetentionPaymentProofModal from './RetentionPaymentProofModal';
const formatCurrency = (v: string | number) =>
new Intl.NumberFormat('en-PH', { style: 'currency', currency: 'PHP' }).format(Number(v || 0));
export default function RetentionStickyToast() {
const { props } = usePage<PageProps>();
const reminders = props.retention_reminders;
const [dismissed, setDismissed] = useState<string[]>([]);
const [activeProofModalInvoice, setActiveProofModalInvoice] = useState<RetentionReminderItem | null>(null);
if (!reminders || reminders.count === 0) return null;
const visibleItems = reminders.items.filter((item) => !dismissed.includes(item.id));
if (visibleItems.length === 0) return null;
const currentItem = visibleItems[0];
const isContractor = currentItem.role_target === 'contractor';
return (
<>
<div className="fixed bottom-6 right-6 z-50 max-w-md w-full animate-in fade-in slide-in-from-bottom-5 duration-300">
<div
className={`rounded-2xl border shadow-2xl p-4 backdrop-blur-md transition-all ${
isContractor
? 'bg-amber-50/95 border-amber-300/80 text-amber-950 shadow-amber-500/10'
: 'bg-indigo-50/95 border-indigo-300/80 text-indigo-950 shadow-indigo-500/10'
}`}
>
<div className="flex items-start justify-between gap-3">
<div className="flex items-start gap-3">
<div
className={`p-2.5 rounded-xl shrink-0 mt-0.5 ${
isContractor ? 'bg-amber-200/80 text-amber-800' : 'bg-indigo-200/80 text-indigo-800'
}`}
>
{isContractor ? (
<Send className="h-5 w-5 animate-pulse" />
) : (
<DollarSign className="h-5 w-5 animate-pulse" />
)}
</div>
<div className="space-y-1">
<div className="flex items-center gap-2">
<h4 className="font-bold text-xs uppercase tracking-wider">
{currentItem.title}
</h4>
<Badge
variant="outline"
className={`text-[10px] px-1.5 py-0 font-bold uppercase ${
isContractor
? 'bg-amber-100 text-amber-900 border-amber-300'
: 'bg-indigo-100 text-indigo-900 border-indigo-300'
}`}
>
{isContractor ? 'Awaiting 10% Proof' : 'Proof Received'}
</Badge>
</div>
<p className="text-xs text-slate-700 leading-relaxed font-medium">
{currentItem.message}
</p>
<div className="flex items-center gap-2 pt-1 text-[11px] font-semibold text-slate-600">
<span>Amount:</span>
<span className="font-bold text-slate-900 font-mono">
{formatCurrency(currentItem.amount)}
</span>
{currentItem.retention_amount && (
<span className={`font-mono font-bold ${isContractor ? 'text-rose-700' : 'text-emerald-700'}`}>
(10% Ret: {isContractor ? '-' : '+'}{formatCurrency(currentItem.retention_amount)})
</span>
)}
</div>
</div>
</div>
<Button
variant="ghost"
size="icon-xs"
onClick={() => setDismissed((prev) => [...prev, currentItem.id])}
className="text-slate-400 hover:text-slate-700 shrink-0 -mt-1 -mr-1"
title="Dismiss reminder"
>
<X className="h-4 w-4" />
</Button>
</div>
{/* Action Bar */}
<div className="mt-3.5 pt-3 border-t border-slate-200/80 flex items-center justify-between gap-2">
{visibleItems.length > 1 ? (
<span className="text-[10px] text-slate-500 font-medium">
+{visibleItems.length - 1} more pending action{visibleItems.length > 2 ? 's' : ''}
</span>
) : (
<span className="text-[10px] text-slate-500 font-medium">
Project: {currentItem.project_name}
</span>
)}
<div className="flex items-center gap-2">
{isContractor ? (
<Button
size="sm"
onClick={() => setActiveProofModalInvoice(currentItem)}
className="bg-amber-600 hover:bg-amber-700 text-white font-semibold text-xs shadow-xs"
>
<UploadCloud className="mr-1.5 h-3.5 w-3.5" /> Send Payment Proof
</Button>
) : (
<Link href={currentItem.view_url}>
<Button
size="sm"
className="bg-indigo-600 hover:bg-indigo-700 text-white font-semibold text-xs shadow-xs"
>
<CheckCircle2 className="mr-1.5 h-3.5 w-3.5" /> Check & Confirm
</Button>
</Link>
)}
<Link href={currentItem.view_url}>
<Button variant="outline" size="sm" className="text-xs bg-white">
Details <ChevronRight className="ml-1 h-3 w-3" />
</Button>
</Link>
</div>
</div>
</div>
</div>
{/* Quick-Action Modal for Contractor Admin */}
{activeProofModalInvoice && (
<RetentionPaymentProofModal
isOpen={!!activeProofModalInvoice}
onClose={() => setActiveProofModalInvoice(null)}
invoice={{
ulid: activeProofModalInvoice.ulid,
invoice_number: activeProofModalInvoice.invoice_number,
total_amount: activeProofModalInvoice.amount,
retention_amount: activeProofModalInvoice.retention_amount,
retention_rate: activeProofModalInvoice.retention_rate || 10,
project: {
name: activeProofModalInvoice.project_name,
code: '',
},
}}
/>
)}
</>
);
}