feat: Initial commit of KROW Workforce Web client (Base44 export)
This commit is contained in:
346
src/components/procurement/W9FormViewer.jsx
Normal file
346
src/components/procurement/W9FormViewer.jsx
Normal file
@@ -0,0 +1,346 @@
|
||||
import React, { useState } from "react";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { FileText, Download, Upload, Save, X } from "lucide-react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
export default function W9FormViewer({ vendor, onClose }) {
|
||||
const [formData, setFormData] = useState({
|
||||
entity_name: vendor?.business_name || "",
|
||||
business_name: "",
|
||||
tax_classification: "",
|
||||
llc_classification: "",
|
||||
has_foreign_partners: false,
|
||||
exempt_payee_code: "",
|
||||
fatca_code: "",
|
||||
address: "",
|
||||
city_state_zip: "",
|
||||
account_numbers: "",
|
||||
ssn_part1: "",
|
||||
ssn_part2: "",
|
||||
ssn_part3: "",
|
||||
ein_part1: "",
|
||||
ein_part2: "",
|
||||
tin_type: "ssn",
|
||||
signature: "",
|
||||
date: ""
|
||||
});
|
||||
|
||||
const handleChange = (field, value) => {
|
||||
setFormData(prev => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
// Save logic here
|
||||
console.log("Saving W9 form:", formData);
|
||||
onClose?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Header with actions */}
|
||||
<div className="flex items-center justify-between pb-4 border-b border-slate-200">
|
||||
<div>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<FileText className="w-5 h-5 text-[#0A39DF]" />
|
||||
<h3 className="font-bold text-lg text-[#1C323E]">Form W-9 (Rev. March 2024)</h3>
|
||||
</div>
|
||||
<p className="text-xs text-slate-500">Request for Taxpayer Identification Number and Certification</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm">
|
||||
<Upload className="w-4 h-4 mr-2" />
|
||||
Upload Signed
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
<Download className="w-4 h-4 mr-2" />
|
||||
Download PDF
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Before you begin notice */}
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||||
<p className="text-sm font-semibold text-blue-900 mb-1">Before you begin</p>
|
||||
<p className="text-xs text-blue-700">Give form to the requester. Do not send to the IRS.</p>
|
||||
</div>
|
||||
|
||||
{/* Line 1 & 2 - Names */}
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label className="text-sm font-semibold">1. Name of entity/individual *</Label>
|
||||
<p className="text-xs text-slate-500 mb-2">For a sole proprietor or disregarded entity, enter the owner's name on line 1</p>
|
||||
<Input
|
||||
value={formData.entity_name}
|
||||
onChange={(e) => handleChange('entity_name', e.target.value)}
|
||||
placeholder="Enter name as shown on your tax return"
|
||||
className="font-medium"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label className="text-sm font-semibold">2. Business name/disregarded entity name, if different from above</Label>
|
||||
<Input
|
||||
value={formData.business_name}
|
||||
onChange={(e) => handleChange('business_name', e.target.value)}
|
||||
placeholder="Enter business or DBA name (if applicable)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Line 3a - Tax Classification */}
|
||||
<div className="border border-slate-200 rounded-lg p-4 bg-slate-50">
|
||||
<Label className="text-sm font-semibold mb-3 block">3a. Federal tax classification (Check only ONE box)</Label>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={formData.tax_classification === "individual"}
|
||||
onCheckedChange={(checked) => checked && handleChange('tax_classification', 'individual')}
|
||||
/>
|
||||
<Label className="text-sm font-normal cursor-pointer">Individual/sole proprietor</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={formData.tax_classification === "c_corp"}
|
||||
onCheckedChange={(checked) => checked && handleChange('tax_classification', 'c_corp')}
|
||||
/>
|
||||
<Label className="text-sm font-normal cursor-pointer">C corporation</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={formData.tax_classification === "s_corp"}
|
||||
onCheckedChange={(checked) => checked && handleChange('tax_classification', 's_corp')}
|
||||
/>
|
||||
<Label className="text-sm font-normal cursor-pointer">S corporation</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={formData.tax_classification === "partnership"}
|
||||
onCheckedChange={(checked) => checked && handleChange('tax_classification', 'partnership')}
|
||||
/>
|
||||
<Label className="text-sm font-normal cursor-pointer">Partnership</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={formData.tax_classification === "trust"}
|
||||
onCheckedChange={(checked) => checked && handleChange('tax_classification', 'trust')}
|
||||
/>
|
||||
<Label className="text-sm font-normal cursor-pointer">Trust/estate</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 col-span-2">
|
||||
<Checkbox
|
||||
checked={formData.tax_classification === "llc"}
|
||||
onCheckedChange={(checked) => checked && handleChange('tax_classification', 'llc')}
|
||||
/>
|
||||
<Label className="text-sm font-normal cursor-pointer">LLC</Label>
|
||||
<span className="text-xs text-slate-500 mx-2">Enter tax classification:</span>
|
||||
<Input
|
||||
value={formData.llc_classification}
|
||||
onChange={(e) => handleChange('llc_classification', e.target.value)}
|
||||
placeholder="C, S, or P"
|
||||
className="w-20 h-8"
|
||||
maxLength={1}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={formData.tax_classification === "other"}
|
||||
onCheckedChange={(checked) => checked && handleChange('tax_classification', 'other')}
|
||||
/>
|
||||
<Label className="text-sm font-normal cursor-pointer">Other (see instructions)</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Line 3b */}
|
||||
<div className="mt-4 pt-4 border-t border-slate-200">
|
||||
<div className="flex items-start space-x-2">
|
||||
<Checkbox
|
||||
checked={formData.has_foreign_partners}
|
||||
onCheckedChange={(checked) => handleChange('has_foreign_partners', checked)}
|
||||
/>
|
||||
<div>
|
||||
<Label className="text-sm font-semibold cursor-pointer">3b. Foreign partners, owners, or beneficiaries</Label>
|
||||
<p className="text-xs text-slate-500 mt-1">Check if you have any foreign partners, owners, or beneficiaries</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Line 4 - Exemptions */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label className="text-sm font-semibold">4. Exempt payee code (if any)</Label>
|
||||
<Input
|
||||
value={formData.exempt_payee_code}
|
||||
onChange={(e) => handleChange('exempt_payee_code', e.target.value)}
|
||||
placeholder="See instructions"
|
||||
className="mt-1"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm font-semibold">Exemption from FATCA reporting code (if any)</Label>
|
||||
<Input
|
||||
value={formData.fatca_code}
|
||||
onChange={(e) => handleChange('fatca_code', e.target.value)}
|
||||
placeholder="Applies to accounts outside US"
|
||||
className="mt-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Lines 5-7 - Address */}
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label className="text-sm font-semibold">5. Address (number, street, and apt. or suite no.)</Label>
|
||||
<Input
|
||||
value={formData.address}
|
||||
onChange={(e) => handleChange('address', e.target.value)}
|
||||
placeholder="Enter street address"
|
||||
className="mt-1"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm font-semibold">6. City, state, and ZIP code</Label>
|
||||
<Input
|
||||
value={formData.city_state_zip}
|
||||
onChange={(e) => handleChange('city_state_zip', e.target.value)}
|
||||
placeholder="City, State ZIP"
|
||||
className="mt-1"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm font-semibold">7. List account number(s) here (optional)</Label>
|
||||
<Input
|
||||
value={formData.account_numbers}
|
||||
onChange={(e) => handleChange('account_numbers', e.target.value)}
|
||||
placeholder="Account numbers"
|
||||
className="mt-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Part I - TIN */}
|
||||
<div className="border-2 border-slate-300 rounded-lg p-4 bg-white">
|
||||
<h3 className="font-bold text-sm mb-4">Part I - Taxpayer Identification Number (TIN)</h3>
|
||||
<p className="text-xs text-slate-600 mb-4">
|
||||
Enter your TIN in the appropriate box. The TIN provided must match the name given on line 1 to avoid backup withholding.
|
||||
</p>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* SSN */}
|
||||
<div>
|
||||
<Label className="text-sm font-semibold mb-2 block">Social security number</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
value={formData.ssn_part1}
|
||||
onChange={(e) => handleChange('ssn_part1', e.target.value)}
|
||||
maxLength={3}
|
||||
placeholder="XXX"
|
||||
className="w-20 text-center font-mono"
|
||||
disabled={formData.tin_type === "ein"}
|
||||
/>
|
||||
<span className="text-lg">–</span>
|
||||
<Input
|
||||
value={formData.ssn_part2}
|
||||
onChange={(e) => handleChange('ssn_part2', e.target.value)}
|
||||
maxLength={2}
|
||||
placeholder="XX"
|
||||
className="w-16 text-center font-mono"
|
||||
disabled={formData.tin_type === "ein"}
|
||||
/>
|
||||
<span className="text-lg">–</span>
|
||||
<Input
|
||||
value={formData.ssn_part3}
|
||||
onChange={(e) => handleChange('ssn_part3', e.target.value)}
|
||||
maxLength={4}
|
||||
placeholder="XXXX"
|
||||
className="w-24 text-center font-mono"
|
||||
disabled={formData.tin_type === "ein"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-center text-sm font-semibold text-slate-500">OR</div>
|
||||
|
||||
{/* EIN */}
|
||||
<div>
|
||||
<Label className="text-sm font-semibold mb-2 block">Employer identification number</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
value={formData.ein_part1}
|
||||
onChange={(e) => handleChange('ein_part1', e.target.value)}
|
||||
maxLength={2}
|
||||
placeholder="XX"
|
||||
className="w-16 text-center font-mono"
|
||||
disabled={formData.tin_type === "ssn"}
|
||||
/>
|
||||
<span className="text-lg">–</span>
|
||||
<Input
|
||||
value={formData.ein_part2}
|
||||
onChange={(e) => handleChange('ein_part2', e.target.value)}
|
||||
maxLength={7}
|
||||
placeholder="XXXXXXX"
|
||||
className="w-32 text-center font-mono"
|
||||
disabled={formData.tin_type === "ssn"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Part II - Certification */}
|
||||
<div className="border-2 border-slate-300 rounded-lg p-4 bg-yellow-50">
|
||||
<h3 className="font-bold text-sm mb-3">Part II - Certification</h3>
|
||||
<div className="text-xs text-slate-700 space-y-2 mb-4">
|
||||
<p className="font-semibold">Under penalties of perjury, I certify that:</p>
|
||||
<ol className="list-decimal list-inside space-y-1 pl-2">
|
||||
<li>The number shown on this form is my correct taxpayer identification number (or I am waiting for a number to be issued to me); and</li>
|
||||
<li>I am not subject to backup withholding because (a) I am exempt from backup withholding, or (b) I have not been notified by the IRS that I am subject to backup withholding as a result of a failure to report all interest or dividends, or (c) the IRS has notified me that I am no longer subject to backup withholding; and</li>
|
||||
<li>I am a U.S. citizen or other U.S. person (defined below); and</li>
|
||||
<li>The FATCA code(s) entered on this form (if any) indicating that I am exempt from FATCA reporting is correct.</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 mt-4">
|
||||
<div>
|
||||
<Label className="text-sm font-semibold">Signature of U.S. person *</Label>
|
||||
<Input
|
||||
value={formData.signature}
|
||||
onChange={(e) => handleChange('signature', e.target.value)}
|
||||
placeholder="Sign here"
|
||||
className="mt-1 italic"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm font-semibold">Date *</Label>
|
||||
<Input
|
||||
type="date"
|
||||
value={formData.date}
|
||||
onChange={(e) => handleChange('date', e.target.value)}
|
||||
className="mt-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex justify-between items-center pt-4 border-t border-slate-200">
|
||||
<Badge variant="outline" className="text-xs">
|
||||
Form W-9 (Rev. 3-2024)
|
||||
</Badge>
|
||||
<div className="flex gap-3">
|
||||
<Button variant="outline" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button className="bg-[#0A39DF] hover:bg-[#0A39DF]/90" onClick={handleSave}>
|
||||
<Save className="w-4 h-4 mr-2" />
|
||||
Save W-9 Form
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user