InvoicesView.tsx 8.24 KB
import React, { useState } from 'react';
import { Download } from 'lucide-react';
import { Button } from '../ui/button';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '../ui/table';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '../ui/select';

// Notes:
// 1. Query purchasing modules under Partner, Group and Location; fees and payment status
// 2. Invoice permission for finance: view and export bills after login
// 3. Report generation: historical bills, unpaid bills, rates, overdue situations

export type InvoiceStatus = 'Paid' | 'Overdue';

export interface InvoiceRow {
  id: string;
  locationId: string;
  subscription: string;
  ratePerMonth: string;
  discountRate: string;
  totalAmount: string;
  period: string;
  status: InvoiceStatus;
  isOverdue?: boolean; // highlight rate and total in red when overdue
}

const MOCK_INVOICES: InvoiceRow[] = [
  { id: '1', locationId: '12345', subscription: 'Labeling', ratePerMonth: '9.99', discountRate: '1', totalAmount: '$9.99', period: 'October', status: 'Paid' },
  { id: '2', locationId: '12345', subscription: 'Tasks', ratePerMonth: '20', discountRate: '0.5', totalAmount: '10', period: 'October', status: 'Paid' },
  { id: '3', locationId: '12345', subscription: 'Sensor', ratePerMonth: '30', discountRate: '1', totalAmount: '30', period: 'October', status: 'Paid' },
  { id: '4', locationId: '12345', subscription: 'e-label', ratePerMonth: '25', discountRate: '1', totalAmount: '50', period: 'October', status: 'Overdue', isOverdue: true },
  { id: '5', locationId: '12345', subscription: 'Food Waste', ratePerMonth: '35', discountRate: '1', totalAmount: '35', period: 'October', status: 'Paid' },
];

export function InvoicesView() {
  const [invoices] = useState<InvoiceRow[]>(MOCK_INVOICES);
  const [periodFilter, setPeriodFilter] = useState('October');
  const [subscriptionFilter, setSubscriptionFilter] = useState('all');

  const filteredInvoices = invoices.filter((row) => {
    const matchPeriod = !periodFilter || row.period === periodFilter;
    const matchSub = subscriptionFilter === 'all' || row.subscription === subscriptionFilter;
    return matchPeriod && matchSub;
  });

  const handleExportBills = () => {
    // Finance personnel: export bills (e.g. CSV or PDF)
    const csv = [
      ['Location ID', 'Subscription', 'Rate/month', 'Discount Rate', 'Total Amount', 'Period', 'Status'].join(','),
      ...filteredInvoices.map((r) => [r.locationId, r.subscription, r.ratePerMonth, r.discountRate, r.totalAmount, r.period, r.status].join(',')),
    ].join('\n');
    const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
    const link = document.createElement('a');
    link.href = URL.createObjectURL(blob);
    link.download = `invoices-${periodFilter || 'all'}.csv`;
    link.click();
    URL.revokeObjectURL(link.href);
  };

  return (
    <div className="h-full flex flex-col bg-white">
      {/* Toolbar:与 Products/Locations 一致 — 单行、圆角、细边框、bg-gray-50、无标题、框内文字黑色 */}
      <div className="border-b border-gray-200 py-4 bg-gray-50">
        <div className="flex flex-nowrap items-center gap-2 overflow-x-auto min-w-0">
          <Select defaultValue="partner-a">
            <SelectTrigger className="w-[140px] h-9 rounded-lg border border-black font-medium text-black bg-white shrink-0">
              <SelectValue placeholder="Partner" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="partner-a">Partner A</SelectItem>
            </SelectContent>
          </Select>
          <Select defaultValue="group-b">
            <SelectTrigger className="w-[140px] h-9 rounded-lg border border-black font-medium text-black bg-white shrink-0">
              <SelectValue placeholder="Group" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="group-b">Group B</SelectItem>
            </SelectContent>
          </Select>
          <Select defaultValue="loc-12">
            <SelectTrigger className="w-[160px] h-9 rounded-lg border border-black font-medium text-black bg-white shrink-0">
              <SelectValue placeholder="Location" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="loc-12">Location 12</SelectItem>
              <SelectItem value="all">All Locations</SelectItem>
            </SelectContent>
          </Select>
          <Select value={subscriptionFilter} onValueChange={setSubscriptionFilter}>
            <SelectTrigger className="w-[140px] h-9 rounded-lg border border-black font-medium text-black bg-white shrink-0">
              <SelectValue placeholder="Subscription" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">Subscription (All)</SelectItem>
              <SelectItem value="Labeling">Labeling</SelectItem>
              <SelectItem value="Tasks">Tasks</SelectItem>
              <SelectItem value="Sensor">Sensor</SelectItem>
              <SelectItem value="e-label">e-label</SelectItem>
              <SelectItem value="Food Waste">Food Waste</SelectItem>
            </SelectContent>
          </Select>
          <Select value={periodFilter} onValueChange={setPeriodFilter}>
            <SelectTrigger className="w-[120px] h-9 rounded-lg border border-black font-medium text-black bg-white shrink-0">
              <SelectValue placeholder="Period" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="October">October</SelectItem>
              <SelectItem value="September">September</SelectItem>
              <SelectItem value="August">August</SelectItem>
            </SelectContent>
          </Select>
          <div className="flex-1 min-w-0" />
          <Button variant="outline" className="h-9 rounded-lg border border-black text-black gap-2 bg-white hover:bg-gray-50 shrink-0" onClick={handleExportBills}>
            <Download className="w-4 h-4" /> Export Bills
          </Button>
        </div>
      </div>

      {/* Content Area:与 Products 一致,无内边距、表格包在白色圆角框内 */}
      <div className="flex-1 overflow-auto bg-gray-50">
        <div className="bg-white border border-gray-200 shadow-sm rounded-sm overflow-hidden">
          <Table>
            <TableHeader>
              <TableRow className="bg-gray-100 hover:bg-gray-100">
                <TableHead className="font-bold text-gray-900 border-r">Location ID</TableHead>
                <TableHead className="font-bold text-gray-900 border-r">Subscription</TableHead>
                <TableHead className="font-bold text-gray-900 border-r">Rate/month</TableHead>
                <TableHead className="font-bold text-gray-900 border-r">Discount Rate</TableHead>
                <TableHead className="font-bold text-gray-900 border-r">Total Amount</TableHead>
                <TableHead className="font-bold text-gray-900 border-r">Period</TableHead>
                <TableHead className="font-bold text-gray-900 text-center">Status</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {filteredInvoices.map((row) => (
              <TableRow key={row.id} className="hover:bg-gray-50">
                <TableCell className="text-gray-700">{row.locationId}</TableCell>
                <TableCell className="text-gray-700">{row.subscription}</TableCell>
                <TableCell>
                  <span className={row.isOverdue ? 'text-red-600' : 'text-gray-700'}>
                    {row.ratePerMonth}
                  </span>
                </TableCell>
                <TableCell className="text-gray-700">{row.discountRate}</TableCell>
                <TableCell>
                  <span className={row.isOverdue ? 'text-red-600' : 'text-gray-700'}>
                    {row.totalAmount}
                  </span>
                </TableCell>
                <TableCell className="text-gray-700">{row.period}</TableCell>
                <TableCell>
                  <span className={row.status === 'Overdue' ? 'text-red-600 font-medium' : 'text-green-600'}>
                    {row.status}
                  </span>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
        </div>
      </div>
    </div>
  );
}