File size: 5,582 Bytes
f359e2d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import { useState, useEffect } from 'react';
import { Download, Eye, Loader2 } from 'lucide-react';
import api from '../api/api';
import { downloadInvoiceAsPDF, downloadInvoiceAsJSON } from '../utils/invoiceGenerator';

const InvoiceView = ({ invoiceId, photographer, customer }) => {
  const [invoice, setInvoice] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetchInvoice();
  }, [invoiceId]);

  const fetchInvoice = async () => {
    try {
      const res = await api.get(`/invoices/${invoiceId}`);
      setInvoice(res.data);
    } catch (err) {
      console.error('Failed to load invoice:', err);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return (
      <div className="flex items-center justify-center py-8">
        <Loader2 className="animate-spin text-blue-600" size={28} />
      </div>
    );
  }

  if (!invoice) {
    return <div className="text-center text-gray-600">Invoice not found</div>;
  }

  const statusColor = {
    pending: 'amber',
    paid: 'green',
    overdue: 'red',
  };

  const color = statusColor[invoice.paymentStatus];

  return (
    <div className="space-y-6">
      {/* Header */}
      <div className="bg-white border border-gray-200 rounded-lg p-6">
        <div className="flex items-center justify-between mb-4">
          <div>
            <h2 className="text-2xl font-bold text-gray-900">Invoice</h2>
            <p className="text-lg text-gray-600 font-semibold">{invoice.invoiceNumber}</p>
          </div>
          <div className={`px-4 py-2 rounded-lg bg-${color}-100 text-${color}-700 font-bold capitalize`}>
            {invoice.paymentStatus}
          </div>
        </div>

        <div className="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
          <div>
            <p className="text-gray-500">Issue Date</p>
            <p className="font-semibold">{new Date(invoice.issueDate).toLocaleDateString()}</p>
          </div>
          <div>
            <p className="text-gray-500">Due Date</p>
            <p className="font-semibold">{new Date(invoice.dueDate).toLocaleDateString()}</p>
          </div>
          <div>
            <p className="text-gray-500">From</p>
            <p className="font-semibold">{photographer?.firstName} {photographer?.lastName}</p>
          </div>
          <div>
            <p className="text-gray-500">To</p>
            <p className="font-semibold">{customer?.firstName} {customer?.lastName}</p>
          </div>
        </div>
      </div>

      {/* Items Table */}
      <div className="bg-white border border-gray-200 rounded-lg overflow-hidden">
        <table className="w-full">
          <thead className="bg-gray-50 border-b">
            <tr>
              <th className="px-6 py-3 text-left text-sm font-semibold text-gray-700">Description</th>
              <th className="px-6 py-3 text-right text-sm font-semibold text-gray-700">Quantity</th>
              <th className="px-6 py-3 text-right text-sm font-semibold text-gray-700">Unit Price</th>
              <th className="px-6 py-3 text-right text-sm font-semibold text-gray-700">Total</th>
            </tr>
          </thead>
          <tbody>
            {invoice.items?.map((item, idx) => (
              <tr key={idx} className="border-b hover:bg-gray-50">
                <td className="px-6 py-3 text-gray-900">{item.description}</td>
                <td className="px-6 py-3 text-right text-gray-900">{item.quantity}</td>
                <td className="px-6 py-3 text-right text-gray-900">₹{item.unitPrice.toFixed(2)}</td>
                <td className="px-6 py-3 text-right text-gray-900">₹{item.total.toFixed(2)}</td>
              </tr>
            ))}
          </tbody>
        </table>

        {/* Totals */}
        <div className="bg-gray-50 px-6 py-4 space-y-2 text-sm">
          <div className="flex justify-between">
            <span className="text-gray-700">Subtotal</span>
            <span className="font-semibold text-gray-900">₹{invoice.subtotal.toFixed(2)}</span>
          </div>
          <div className="flex justify-between">
            <span className="text-gray-700">Tax ({invoice.taxRate}%)</span>
            <span className="font-semibold text-gray-900">₹{invoice.tax.toFixed(2)}</span>
          </div>
          {invoice.discount > 0 && (
            <div className="flex justify-between">
              <span className="text-gray-700">Discount</span>
              <span className="font-semibold text-gray-900">-₹{invoice.discount.toFixed(2)}</span>
            </div>
          )}
          <div className="border-t pt-2 flex justify-between text-base font-bold">
            <span className="text-gray-900">Total Amount</span>
            <span className="text-blue-600">₹{invoice.totalAmount.toFixed(2)}</span>
          </div>
        </div>
      </div>

      {/* Action Buttons */}
      <div className="flex gap-3">
        <button
          onClick={() => downloadInvoiceAsPDF(invoice, photographer, customer)}
          className="flex-1 flex items-center justify-center gap-2 bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 font-medium"
        >
          <Download size={18} /> Download PDF
        </button>
        <button
          onClick={() => downloadInvoiceAsJSON(invoice)}
          className="flex-1 flex items-center justify-center gap-2 bg-gray-600 text-white px-4 py-2 rounded-lg hover:bg-gray-700 font-medium"
        >
          <Eye size={18} /> Export JSON
        </button>
      </div>
    </div>
  );
};

export default InvoiceView;