feat: update employment earnings metric to monthly and document new KYC application requirements
This commit is contained in:
@@ -57,7 +57,9 @@ interface CompanySettings {
|
||||
};
|
||||
masterData: {
|
||||
kycDocuments: { name: string; required: boolean }[];
|
||||
riderDocuments: { id: string; name: string; required: boolean; description: string }[];
|
||||
subscriptionPlans: { name: string; price: number; duration: number; features: string[] }[];
|
||||
rentalPlans: { id: string; name: string; type: string; description: string; price: number; duration: number }[];
|
||||
investorDocuments: { id: string; name: string; required: boolean; description: string }[];
|
||||
merchantDocuments: { id: string; name: string; required: boolean; description: string }[];
|
||||
swapStationDocuments: { id: string; name: string; required: boolean; description: string }[];
|
||||
@@ -67,7 +69,7 @@ interface CompanySettings {
|
||||
documents: { id: string; name: string; required: boolean; description: string }[];
|
||||
}[];
|
||||
};
|
||||
parts: { id: string; name: string; price: number; inStock: number }[];
|
||||
parts: { id: string; name: string; price?: number; minPrice?: number; maxPrice?: number; inStock: number }[];
|
||||
serviceCenters: { id: string; name: string; address: string; phone: string; rating: number }[];
|
||||
rentalPolicy: {
|
||||
minAge: number;
|
||||
@@ -140,12 +142,27 @@ const initialSettings: CompanySettings = {
|
||||
{ name: 'Address Proof', required: false },
|
||||
{ name: 'Business Trade License', required: false },
|
||||
],
|
||||
riderDocuments: [
|
||||
{ id: 'rider_nid_front', name: 'NID (Front)', required: true, description: 'National ID card front side' },
|
||||
{ id: 'rider_nid_back', name: 'NID (Back)', required: true, description: 'National ID card back side' },
|
||||
{ id: 'rider_license', name: 'Driving License', required: true, description: 'Valid driving license' },
|
||||
{ id: 'rider_photo', name: 'Profile Photo', required: true, description: 'Recent passport size photo' },
|
||||
{ id: 'rider_bank_card', name: 'Bank Account Card', required: false, description: 'Bank account card/cheque' },
|
||||
{ id: 'rider_wallet', name: 'Mobile Wallet Info', required: false, description: 'bKash/Rocket account details' },
|
||||
],
|
||||
subscriptionPlans: [
|
||||
{ name: 'Daily', price: 500, duration: 1, features: ['24 hours access', 'Basic support'] },
|
||||
{ name: 'Weekly', price: 3000, duration: 7, features: ['7 days access', 'Priority support', 'Free swap'] },
|
||||
{ name: 'Monthly', price: 10000, duration: 30, features: ['30 days access', 'VIP support', 'Unlimited swap', 'Damage coverage'] },
|
||||
{ name: 'Yearly', price: 80000, duration: 365, features: ['1 year access', 'Dedicated manager', 'Unlimited swap', 'Full coverage', 'Discounted rates'] },
|
||||
],
|
||||
rentalPlans: [
|
||||
{ id: 'single_rent', name: 'Single Rent', type: 'single', description: 'Single person rental plan', price: 500, duration: 1 },
|
||||
{ id: 'weekly_rent', name: 'Weekly Rent', type: 'weekly', description: '7 days rental plan', price: 3000, duration: 7 },
|
||||
{ id: 'monthly_rent', name: 'Monthly Rent', type: 'monthly', description: '30 days rental plan', price: 10000, duration: 30 },
|
||||
{ id: 'rent_to_own', name: 'Rent to Own', type: 'rent-to-own', description: 'Own after X months', price: 15000, duration: 365 },
|
||||
{ id: 'share_ev', name: 'Share EV', type: 'shared', description: 'Shared bike', price: 2500, duration: 30 },
|
||||
],
|
||||
investorDocuments: [
|
||||
{ id: 'inv_nid', name: 'NID Card (Front & Back)', required: true, description: 'National ID card copy' },
|
||||
{ id: 'inv_photo', name: 'Passport Size Photo', required: true, description: 'Recent passport size photograph' },
|
||||
@@ -219,10 +236,20 @@ const initialSettings: CompanySettings = {
|
||||
},
|
||||
parts: [
|
||||
{ id: 'PRT-001', name: 'Battery 60V', price: 15000, inStock: 25 },
|
||||
{ id: 'PRT-002', name: 'Front Tire', price: 2500, inStock: 50 },
|
||||
{ id: 'PRT-003', name: 'Rear Tire', price: 2500, inStock: 50 },
|
||||
{ id: 'PRT-004', name: 'Brake Pad', price: 800, inStock: 100 },
|
||||
{ id: 'PRT-005', name: 'Mirror', price: 350, inStock: 80 },
|
||||
{ id: 'PRT-002', name: 'Battery 48V', price: 12000, inStock: 30 },
|
||||
{ id: 'PRT-003', name: 'Front Tire', price: 2500, inStock: 50 },
|
||||
{ id: 'PRT-004', name: 'Rear Tire', price: 2500, inStock: 50 },
|
||||
{ id: 'PRT-005', name: 'Brake Pad', price: 800, inStock: 100 },
|
||||
{ id: 'PRT-006', name: 'Mirror', price: 350, inStock: 80 },
|
||||
{ id: 'PRT-007', name: 'Controller', minPrice: 3500, maxPrice: 5000, inStock: 15 },
|
||||
{ id: 'PRT-008', name: 'Motor', minPrice: 8000, maxPrice: 12000, inStock: 10 },
|
||||
{ id: 'PRT-009', name: 'Charger', minPrice: 1500, maxPrice: 2500, inStock: 20 },
|
||||
{ id: 'PRT-010', name: 'Display Meter', price: 1200, inStock: 25 },
|
||||
{ id: 'PRT-011', name: 'Throttle', price: 800, inStock: 40 },
|
||||
{ id: 'PRT-012', name: 'Brake Cable', price: 250, inStock: 60 },
|
||||
{ id: 'PRT-013', name: 'Chain', price: 600, inStock: 35 },
|
||||
{ id: 'PRT-014', name: 'Sprocket', price: 450, inStock: 45 },
|
||||
{ id: 'PRT-015', name: 'Foot Peg', price: 300, inStock: 50 },
|
||||
],
|
||||
serviceCenters: [
|
||||
{ id: 'SC-001', name: 'JAIBEN Service Center - Gulshan', address: 'House 45, Road 13, Gulshan 1, Dhaka', phone: '+8801712345670', rating: 4.8 },
|
||||
@@ -251,16 +278,19 @@ const initialSettings: CompanySettings = {
|
||||
|
||||
export default function CompanySettingsPage() {
|
||||
const [settings, setSettings] = useState<CompanySettings>(initialSettings);
|
||||
const [activeTab, setActiveTab] = useState<'general' | 'branding' | 'social' | 'integration' | 'landing' | 'kyc' | 'rental'>('general');
|
||||
const [activeTab, setActiveTab] = useState<'general' | 'branding' | 'social' | 'integration' | 'landing' | 'kyc' | 'parts' | 'rental'>('general');
|
||||
const [activeMasterTab, setActiveMasterTab] = useState<'investor' | 'merchant' | 'swapstation' | 'rental'>('investor');
|
||||
const [saved, setSaved] = useState(false);
|
||||
const [addDocType, setAddDocType] = useState<'investor' | 'merchant' | 'swapstation' | 'rental' | null>(null);
|
||||
const [newDocName, setNewDocName] = useState('');
|
||||
const [newDocDesc, setNewDocDesc] = useState('');
|
||||
|
||||
const handleSave = () => {
|
||||
setSaved(true);
|
||||
setTimeout(() => setSaved(false), 2000);
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
const tabs = [
|
||||
{ id: 'general', label: 'General', icon: Settings },
|
||||
{ id: 'branding', label: 'Branding', icon: Palette },
|
||||
{ id: 'social', label: 'Social Media', icon: Link2 },
|
||||
@@ -268,6 +298,7 @@ export default function CompanySettingsPage() {
|
||||
{ id: 'landing', label: 'Landing Page', icon: Monitor },
|
||||
|
||||
{ id: 'kyc', label: 'KYC Documents', icon: Package },
|
||||
{ id: 'parts', label: 'EV Parts', icon: Package },
|
||||
{ id: 'rental', label: 'Rental Policy', icon: FileCheck },
|
||||
];
|
||||
|
||||
@@ -901,7 +932,61 @@ export default function CompanySettingsPage() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="mt-4 text-sm text-accent hover:underline">+ Add Document</button>
|
||||
<button
|
||||
onClick={() => setAddDocType('investor')}
|
||||
className="mt-4 text-sm text-accent hover:underline"
|
||||
>
|
||||
+ Add Document
|
||||
</button>
|
||||
{addDocType === 'investor' && (
|
||||
<div className="mt-3 p-3 bg-slate-50 rounded-lg border border-slate-200">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Document name"
|
||||
value={newDocName}
|
||||
onChange={(e) => setNewDocName(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mb-2"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Description"
|
||||
value={newDocDesc}
|
||||
onChange={(e) => setNewDocDesc(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mb-2"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
if (newDocName.trim()) {
|
||||
const updated = [...settings.masterData.investorDocuments, {
|
||||
id: `inv_${Date.now()}`,
|
||||
name: newDocName,
|
||||
required: false,
|
||||
description: newDocDesc || ''
|
||||
}];
|
||||
setSettings({ ...settings, masterData: { ...settings.masterData, investorDocuments: updated } });
|
||||
setNewDocName('');
|
||||
setNewDocDesc('');
|
||||
setAddDocType(null);
|
||||
}
|
||||
}}
|
||||
className="px-3 py-1.5 bg-accent text-white text-sm rounded-lg"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setAddDocType(null);
|
||||
setNewDocName('');
|
||||
setNewDocDesc('');
|
||||
}}
|
||||
className="px-3 py-1.5 border border-slate-200 text-slate-600 text-sm rounded-lg"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -931,7 +1016,61 @@ export default function CompanySettingsPage() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="mt-4 text-sm text-accent hover:underline">+ Add Document</button>
|
||||
<button
|
||||
onClick={() => setAddDocType('merchant')}
|
||||
className="mt-4 text-sm text-accent hover:underline"
|
||||
>
|
||||
+ Add Document
|
||||
</button>
|
||||
{addDocType === 'merchant' && (
|
||||
<div className="mt-3 p-3 bg-slate-50 rounded-lg border border-slate-200">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Document name"
|
||||
value={newDocName}
|
||||
onChange={(e) => setNewDocName(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mb-2"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Description"
|
||||
value={newDocDesc}
|
||||
onChange={(e) => setNewDocDesc(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mb-2"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
if (newDocName.trim()) {
|
||||
const updated = [...settings.masterData.merchantDocuments, {
|
||||
id: `mer_${Date.now()}`,
|
||||
name: newDocName,
|
||||
required: false,
|
||||
description: newDocDesc || ''
|
||||
}];
|
||||
setSettings({ ...settings, masterData: { ...settings.masterData, merchantDocuments: updated } });
|
||||
setNewDocName('');
|
||||
setNewDocDesc('');
|
||||
setAddDocType(null);
|
||||
}
|
||||
}}
|
||||
className="px-3 py-1.5 bg-accent text-white text-sm rounded-lg"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setAddDocType(null);
|
||||
setNewDocName('');
|
||||
setNewDocDesc('');
|
||||
}}
|
||||
className="px-3 py-1.5 border border-slate-200 text-slate-600 text-sm rounded-lg"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -961,7 +1100,61 @@ export default function CompanySettingsPage() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="mt-4 text-sm text-accent hover:underline">+ Add Document</button>
|
||||
<button
|
||||
onClick={() => setAddDocType('swapstation')}
|
||||
className="mt-4 text-sm text-accent hover:underline"
|
||||
>
|
||||
+ Add Document
|
||||
</button>
|
||||
{addDocType === 'swapstation' && (
|
||||
<div className="mt-3 p-3 bg-slate-50 rounded-lg border border-slate-200">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Document name"
|
||||
value={newDocName}
|
||||
onChange={(e) => setNewDocName(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mb-2"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Description"
|
||||
value={newDocDesc}
|
||||
onChange={(e) => setNewDocDesc(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mb-2"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
if (newDocName.trim()) {
|
||||
const updated = [...settings.masterData.swapStationDocuments, {
|
||||
id: `ss_${Date.now()}`,
|
||||
name: newDocName,
|
||||
required: false,
|
||||
description: newDocDesc || ''
|
||||
}];
|
||||
setSettings({ ...settings, masterData: { ...settings.masterData, swapStationDocuments: updated } });
|
||||
setNewDocName('');
|
||||
setNewDocDesc('');
|
||||
setAddDocType(null);
|
||||
}
|
||||
}}
|
||||
className="px-3 py-1.5 bg-accent text-white text-sm rounded-lg"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setAddDocType(null);
|
||||
setNewDocName('');
|
||||
setNewDocDesc('');
|
||||
}}
|
||||
className="px-3 py-1.5 border border-slate-200 text-slate-600 text-sm rounded-lg"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -996,7 +1189,64 @@ export default function CompanySettingsPage() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="mt-3 text-sm text-accent hover:underline">+ Add Document</button>
|
||||
<button
|
||||
onClick={() => setAddDocType('rental')}
|
||||
className="mt-3 text-sm text-accent hover:underline"
|
||||
>
|
||||
+ Add Document
|
||||
</button>
|
||||
{addDocType === 'rental' && (
|
||||
<div className="mt-3 p-3 bg-slate-50 rounded-lg border border-slate-200">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Document name"
|
||||
value={newDocName}
|
||||
onChange={(e) => setNewDocName(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mb-2"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Description"
|
||||
value={newDocDesc}
|
||||
onChange={(e) => setNewDocDesc(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mb-2"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
if (newDocName.trim()) {
|
||||
const updated = [...settings.masterData.rentalDocuments];
|
||||
updated.forEach((rental) => {
|
||||
rental.documents.push({
|
||||
id: `rent_${Date.now()}`,
|
||||
name: newDocName,
|
||||
required: false,
|
||||
description: newDocDesc || ''
|
||||
});
|
||||
});
|
||||
setSettings({ ...settings, masterData: { ...settings.masterData, rentalDocuments: updated } });
|
||||
setNewDocName('');
|
||||
setNewDocDesc('');
|
||||
setAddDocType(null);
|
||||
}
|
||||
}}
|
||||
className="px-3 py-1.5 bg-accent text-white text-sm rounded-lg"
|
||||
>
|
||||
Add to All
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setAddDocType(null);
|
||||
setNewDocName('');
|
||||
setNewDocDesc('');
|
||||
}}
|
||||
className="px-3 py-1.5 border border-slate-200 text-slate-600 text-sm rounded-lg"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -1004,6 +1254,52 @@ export default function CompanySettingsPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'parts' && (
|
||||
<div className="p-6 space-y-6">
|
||||
<h3 className="text-lg font-semibold text-slate-800">EV Parts</h3>
|
||||
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<thead className="bg-slate-50">
|
||||
<tr>
|
||||
<th className="px-3 py-2 text-left text-xs font-semibold">Part ID</th>
|
||||
<th className="px-3 py-2 text-left text-xs font-semibold">Name</th>
|
||||
<th className="px-3 py-2 text-left text-xs font-semibold">Price Range</th>
|
||||
<th className="px-3 py-2 text-left text-xs font-semibold">In Stock</th>
|
||||
<th className="px-3 py-2 text-left text-xs font-semibold">Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{settings.parts.map(part => (
|
||||
<tr key={part.id} className="border-t">
|
||||
<td className="px-3 py-2 text-sm">{part.id}</td>
|
||||
<td className="px-3 py-2 text-sm font-medium">{part.name}</td>
|
||||
<td className="px-3 py-2 text-sm">
|
||||
{part.minPrice && part.maxPrice ? (
|
||||
<span className="text-amber-600">৳{part.minPrice} - ৳{part.maxPrice}</span>
|
||||
) : part.price ? (
|
||||
<span>৳{part.price}</span>
|
||||
) : (
|
||||
<span className="text-slate-400">-</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-3 py-2 text-sm">{part.inStock}</td>
|
||||
<td className="px-3 py-2 text-sm">
|
||||
{part.minPrice ? (
|
||||
<span className="text-xs px-2 py-0.5 bg-amber-100 text-amber-700 rounded">Range</span>
|
||||
) : (
|
||||
<span className="text-xs px-2 py-0.5 bg-green-100 text-green-700 rounded">Fixed</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<button className="mt-4 text-sm text-accent hover:underline">+ Add Part</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'rental' && (
|
||||
<div className="p-6 space-y-6">
|
||||
<h3 className="text-lg font-semibold text-slate-800">Rental Policy</h3>
|
||||
|
||||
Reference in New Issue
Block a user