feat: implement editable profile sections and update layout in investor details page
This commit is contained in:
1542
src/app/admin/investors/[id]/page copy.tsx
Normal file
1542
src/app/admin/investors/[id]/page copy.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,13 +2,16 @@
|
|||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import { investors as initialInvestors, bikes as initialBikes, transactions as initialTransactions } from '@/data/mockData';
|
import { investors as initialInvestors, bikes as initialBikes, transactions as initialTransactions } from '@/data/mockData';
|
||||||
import type { Investor } from '@/data/mockData';
|
import type { Investor } from '@/data/mockData';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
import {
|
import {
|
||||||
ArrowLeft, Wallet, TrendingUp, Banknote, Calendar, Phone, Mail, MapPin, Edit, Trash2, Plus, X, Bike,
|
ArrowLeft, Wallet, TrendingUp, Banknote, Calendar, Phone, Mail, MapPin, Edit, Trash2, Plus, X, Bike,
|
||||||
User, FileText, CreditCard, DollarSign, Clock, ChevronDown, ExternalLink, Download, Upload,
|
User, FileText, CreditCard, DollarSign, Clock, ChevronDown, ExternalLink, Download, Upload,
|
||||||
AlertTriangle, Shield, Star, CheckCircle, XCircle, Search, Filter, BookOpen, ArrowRight, Printer
|
AlertTriangle, Shield, Star, CheckCircle, XCircle, Search, Filter, BookOpen, ArrowRight, Printer,
|
||||||
|
UserCircle, Home, Briefcase, CreditCardIcon, Heart, PhoneCall, PhoneOutgoing, MessageSquare, Save,
|
||||||
|
ShieldCheck, Building2, Users, Check, AlertOctagon, Activity, Award, Camera
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
const statusColors: Record<string, string> = {
|
const statusColors: Record<string, string> = {
|
||||||
@@ -39,8 +42,37 @@ const bikeStatusColors: Record<string, string> = {
|
|||||||
retired: 'bg-slate-100 text-slate-500',
|
retired: 'bg-slate-100 text-slate-500',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function SectionCard({ title, icon: Icon, children, headerBg = 'bg-slate-50', headerBorder = 'border-slate-100', editKey, editingSection, setEditingSection, onEdit, editForm, setEditForm }: { title: string; icon: any; children: React.ReactNode; headerBg?: string; headerBorder?: string; editKey?: string; editingSection?: string | null; setEditingSection?: (s: string | null) => void; onEdit?: () => void; editForm?: any; setEditForm?: any }) {
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||||
|
<div className={`${headerBg} px-5 py-4 border-b ${headerBorder} flex items-center justify-between`}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Icon className="w-5 h-5 text-slate-600" />
|
||||||
|
<h3 className="font-semibold text-slate-800">{title}</h3>
|
||||||
|
</div>
|
||||||
|
{editKey && setEditingSection ? (
|
||||||
|
editingSection !== editKey ? (
|
||||||
|
<button onClick={() => { setEditingSection(editKey); onEdit?.(); }} className="p-1.5 hover:bg-white rounded-lg transition-colors">
|
||||||
|
<Edit className="w-4 h-4 text-slate-500" />
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<button onClick={() => { toast.success('Updated'); setEditingSection(null); }} className="px-3 py-1.5 bg-green-600 text-white rounded-lg text-xs font-medium hover:bg-green-700">Save</button>
|
||||||
|
<button onClick={() => setEditingSection(null)} className="px-3 py-1.5 border border-slate-200 text-slate-600 rounded-lg text-xs font-medium hover:bg-slate-50">Cancel</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function InvestorDetailPage() {
|
export default function InvestorDetailPage() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
const router = useRouter();
|
||||||
const investorId = params.id as string;
|
const investorId = params.id as string;
|
||||||
|
|
||||||
const [investors] = useState<Investor[]>(initialInvestors);
|
const [investors] = useState<Investor[]>(initialInvestors);
|
||||||
@@ -59,6 +91,8 @@ export default function InvestorDetailPage() {
|
|||||||
const [selectedInvoice, setSelectedInvoice] = useState<any>(null);
|
const [selectedInvoice, setSelectedInvoice] = useState<any>(null);
|
||||||
const [investorJournals, setInvestorJournals] = useState<any[]>([]);
|
const [investorJournals, setInvestorJournals] = useState<any[]>([]);
|
||||||
const [showBankModal, setShowBankModal] = useState(false);
|
const [showBankModal, setShowBankModal] = useState(false);
|
||||||
|
const [editingSection, setEditingSection] = useState<string | null>(null);
|
||||||
|
const [editForm, setEditForm] = useState<any>({});
|
||||||
const [showMobileBankingModal, setShowMobileBankingModal] = useState(false);
|
const [showMobileBankingModal, setShowMobileBankingModal] = useState(false);
|
||||||
const [showTaxModal, setShowTaxModal] = useState(false);
|
const [showTaxModal, setShowTaxModal] = useState(false);
|
||||||
const [showDocModal, setShowDocModal] = useState(false);
|
const [showDocModal, setShowDocModal] = useState(false);
|
||||||
@@ -184,86 +218,93 @@ Credit (Cr): Investor Liability ৳${newInvestment.totalInvestment.toLocaleStri
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4 lg:p-6">
|
<div className="p-4 lg:p-6">
|
||||||
<div className="flex items-center justify-between mb-6">
|
<button onClick={() => router.push('/admin/investors')} className="flex items-center gap-2 text-slate-600 hover:text-slate-800 mb-4">
|
||||||
<div className="flex items-center gap-4">
|
<ArrowLeft className="w-4 h-4" /> Back to Investors
|
||||||
<Link href="/admin/investors" className="p-2 hover:bg-slate-100 rounded-lg">
|
</button>
|
||||||
<ArrowLeft className="w-5 h-5 text-slate-600" />
|
{/* Profile Card Header */}
|
||||||
</Link>
|
<div className="bg-white rounded-xl shadow-sm border border-slate-100 overflow-hidden mb-6">
|
||||||
|
<div className="p-5">
|
||||||
|
<div className="flex flex-col lg:flex-row lg:items-start gap-5">
|
||||||
|
{/* Profile Image */}
|
||||||
|
<div className="relative group flex-shrink-0 mx-auto lg:mx-0">
|
||||||
|
<div className="w-24 h-24 rounded-full bg-gradient-to-br from-purple-500 to-blue-500 flex items-center justify-center shadow-lg border-4 border-white">
|
||||||
|
<span className="text-3xl font-extrabold text-white">{investor.name.charAt(0)}</span>
|
||||||
|
</div>
|
||||||
|
<label className="absolute bottom-0 right-0 w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity shadow-lg border-2 border-white">
|
||||||
|
<Camera className="w-4 h-4 text-white" />
|
||||||
|
<input type="file" accept="image/*" className="hidden" onChange={() => toast.success('Profile image updated')} />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Profile Info */}
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl lg:text-3xl font-extrabold text-slate-800">{investor.name}</h1>
|
<h1 className="text-2xl font-extrabold text-slate-800">{investor.name}</h1>
|
||||||
<p className="text-sm text-slate-500">{investor.id} • {investor.email}</p>
|
<p className="text-sm text-slate-500 mt-0.5">{investor.id} • {investor.email}</p>
|
||||||
|
<div className="flex items-center gap-2 mt-1">
|
||||||
|
{investor.referralCode && (
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded bg-purple-50 text-purple-700 border border-purple-100">
|
||||||
|
<Star className="w-3 h-3" /> Ref: {investor.referralCode}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{investor.totalReferrals > 0 && (
|
||||||
|
<span className="text-xs text-slate-400">Referrals: {investor.totalReferrals}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap items-center gap-2 mt-2">
|
||||||
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${statusColors[investor.status]}`}>{investor.status}</span>
|
||||||
|
{investor.investments && investor.investments.length > 0 && (
|
||||||
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${planColors[investor.investments[0].planType]}`}>
|
||||||
|
{investor.investments.length} Investment{investor.investments.length > 1 ? 's' : ''}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${kycColors[investor.kycStatus]}`}>
|
||||||
|
<ShieldCheck className="w-3 h-3" /> KYC {investor.kycStatus}
|
||||||
|
</span>
|
||||||
|
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${investor.riskLevel === 'low' ? 'bg-green-100 text-green-700' : investor.riskLevel === 'medium' ? 'bg-amber-100 text-amber-700' : 'bg-red-100 text-red-700'}`}>
|
||||||
|
Risk: {investor.riskLevel}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2 flex-shrink-0">
|
||||||
<button onClick={() => setShowEditModal(true)} className="py-2.5 px-4 border border-slate-200 text-slate-600 rounded-lg font-semibold text-sm hover:bg-slate-50 flex items-center gap-2">
|
<button onClick={() => setShowEditModal(true)} className="py-2 px-4 border border-slate-200 text-slate-600 rounded-lg font-semibold text-sm hover:bg-slate-50 flex items-center gap-2">
|
||||||
<Edit className="w-4 h-4" /> Edit
|
<Edit className="w-4 h-4" /> Edit
|
||||||
</button>
|
</button>
|
||||||
<button className="py-2.5 px-4 bg-red-500 text-white rounded-lg font-semibold text-sm hover:bg-red-600 flex items-center gap-2">
|
<button className="py-2 px-4 bg-red-500 text-white rounded-lg font-semibold text-sm hover:bg-red-600 flex items-center gap-2">
|
||||||
<Trash2 className="w-4 h-4" /> Delete
|
<Trash2 className="w-4 h-4" /> Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-2 mb-6">
|
{/* Stats Row */}
|
||||||
<span className={`inline-flex items-center gap-1 text-sm font-medium px-3 py-1.5 rounded-full ${statusColors[investor.status]}`}>
|
<div className="grid grid-cols-3 lg:grid-cols-6 gap-3 mt-5">
|
||||||
{investor.status}
|
<div className="p-3 bg-purple-50 rounded-lg border border-purple-100">
|
||||||
</span>
|
<p className="text-xs text-purple-600 font-medium">Total Invested</p>
|
||||||
{investor.investments && investor.investments.length > 0 && (
|
<p className="text-sm font-bold text-purple-700">৳{investor.totalInvested.toLocaleString()}</p>
|
||||||
<span className={`inline-flex items-center gap-1 text-sm font-medium px-3 py-1.5 rounded-full ${planColors[investor.investments[0].planType]}`}>
|
|
||||||
{investor.investments.length} Investment{investor.investments.length > 1 ? 's' : ''}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
<span className={`inline-flex items-center gap-1 text-sm font-medium px-3 py-1.5 rounded-full ${kycColors[investor.kycStatus]}`}>
|
|
||||||
<Shield className="w-4 h-4" /> KYC {investor.kycStatus}
|
|
||||||
</span>
|
|
||||||
<span className={`inline-flex items-center gap-1 text-sm font-medium px-3 py-1.5 rounded-full ${investor.riskLevel === 'low' ? 'bg-green-100 text-green-700' : investor.riskLevel === 'medium' ? 'bg-amber-100 text-amber-700' : 'bg-red-100 text-red-700'}`}>
|
|
||||||
Risk: {investor.riskLevel}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="p-3 bg-green-50 rounded-lg border border-green-100">
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
<p className="text-xs text-green-600 font-medium">Total Earnings</p>
|
||||||
<div className="bg-white rounded-xl p-5 shadow-sm border border-slate-100">
|
<p className="text-sm font-bold text-green-700">৳{investor.totalEarnings.toLocaleString()}</p>
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="w-12 h-12 rounded-xl bg-purple-50 flex items-center justify-center">
|
|
||||||
<Wallet className="w-6 h-6 text-purple-600" />
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="p-3 bg-blue-50 rounded-lg border border-blue-100">
|
||||||
<p className="text-2xl font-extrabold text-slate-800">৳{investor.totalInvested.toLocaleString()}</p>
|
<p className="text-xs text-blue-600 font-medium">ROI</p>
|
||||||
<p className="text-sm text-slate-500">Total Invested</p>
|
<p className="text-sm font-bold text-blue-700">{investor.roi}%</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-amber-50 rounded-lg border border-amber-100">
|
||||||
|
<p className="text-xs text-amber-600 font-medium">Active Bikes</p>
|
||||||
|
<p className="text-sm font-bold text-amber-700">{investor.activeBikes}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-red-50 rounded-lg border border-red-100">
|
||||||
|
<p className="text-xs text-red-600 font-medium">Pending Earning</p>
|
||||||
|
<p className="text-sm font-bold text-red-700">৳{investor.pendingEarnings.toLocaleString()}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg border border-slate-100">
|
||||||
|
<p className="text-xs text-slate-600 font-medium">Withdrawn</p>
|
||||||
|
<p className="text-sm font-bold text-slate-700">৳{investor.totalWithdrawn.toLocaleString()}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white rounded-xl p-5 shadow-sm border border-slate-100">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="w-12 h-12 rounded-xl bg-green-50 flex items-center justify-center">
|
|
||||||
<TrendingUp className="w-6 h-6 text-green-600" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-2xl font-extrabold text-slate-800">৳{investor.totalEarnings.toLocaleString()}</p>
|
|
||||||
<p className="text-sm text-slate-500">Total Earnings</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white rounded-xl p-5 shadow-sm border border-slate-100">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="w-12 h-12 rounded-xl bg-blue-50 flex items-center justify-center">
|
|
||||||
<Bike className="w-6 h-6 text-blue-600" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-2xl font-extrabold text-slate-800">{investor.activeBikes}</p>
|
|
||||||
<p className="text-sm text-slate-500">Active Bikes</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white rounded-xl p-5 shadow-sm border border-slate-100">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="w-12 h-12 rounded-xl bg-amber-50 flex items-center justify-center">
|
|
||||||
<Calendar className="w-6 h-6 text-amber-600" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-2xl font-extrabold text-slate-800">{investor.roi}%</p>
|
|
||||||
<p className="text-sm text-slate-500">ROI</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -310,107 +351,551 @@ Credit (Cr): Investor Liability ৳${newInvestment.totalInvestment.toLocaleStri
|
|||||||
|
|
||||||
<div className="p-5">
|
<div className="p-5">
|
||||||
{activeTab === 'overview' && (
|
{activeTab === 'overview' && (
|
||||||
<div className="space-y-6">
|
<div className="space-y-4">
|
||||||
<div className="grid lg:grid-cols-2 gap-6">
|
<div className="flex gap-4">
|
||||||
|
<div className="flex-1 space-y-4">
|
||||||
|
<SectionCard title="Personal Information" icon={User} headerBg="bg-emerald-50" headerBorder="border-emerald-100" editKey="personal" editingSection={editingSection} setEditingSection={setEditingSection} onEdit={() => setEditForm({
|
||||||
|
fullName: investor.name,
|
||||||
|
phone: investor.phone,
|
||||||
|
phoneAlt: investor.phoneAlt || '',
|
||||||
|
email: investor.email,
|
||||||
|
nidNumber: investor.nidNumber || '',
|
||||||
|
tinNumber: investor.tinNumber || '',
|
||||||
|
dateOfBirth: investor.dateOfBirth || '',
|
||||||
|
gender: investor.gender || '',
|
||||||
|
occupation: investor.occupation || '',
|
||||||
|
bloodGroup: (investor as any).bloodGroup || '',
|
||||||
|
maritalStatus: (investor as any).maritalStatus || '',
|
||||||
|
religion: (investor as any).religion || '',
|
||||||
|
nationality: (investor as any).nationality || 'Bangladeshi'
|
||||||
|
})} editForm={editForm} setEditForm={setEditForm}>
|
||||||
|
{editingSection === 'personal' ? (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Full Name</label>
|
||||||
|
<input type="text" value={editForm.fullName || ''} onChange={(e) => setEditForm({ ...editForm, fullName: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-slate-800 mb-4">Personal Information</h3>
|
<label className="text-xs text-slate-500 mb-1 block">Phone</label>
|
||||||
<div className="space-y-3">
|
<input type="text" value={editForm.phone || ''} onChange={(e) => setEditForm({ ...editForm, phone: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
</div>
|
||||||
<User className="w-5 h-5 text-slate-400" />
|
|
||||||
<div>
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Alternate Phone</label>
|
||||||
|
<input type="text" value={editForm.phoneAlt || ''} onChange={(e) => setEditForm({ ...editForm, phoneAlt: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Email</label>
|
||||||
|
<input type="email" value={editForm.email || ''} onChange={(e) => setEditForm({ ...editForm, email: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">NID Number</label>
|
||||||
|
<input type="text" value={editForm.nidNumber || ''} onChange={(e) => setEditForm({ ...editForm, nidNumber: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">TIN Number</label>
|
||||||
|
<input type="text" value={editForm.tinNumber || ''} onChange={(e) => setEditForm({ ...editForm, tinNumber: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Date of Birth</label>
|
||||||
|
<input type="date" value={editForm.dateOfBirth || ''} onChange={(e) => setEditForm({ ...editForm, dateOfBirth: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Gender</label>
|
||||||
|
<select value={editForm.gender || ''} onChange={(e) => setEditForm({ ...editForm, gender: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="">Select</option>
|
||||||
|
<option value="Male">Male</option>
|
||||||
|
<option value="Female">Female</option>
|
||||||
|
<option value="Other">Other</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Occupation</label>
|
||||||
|
<input type="text" value={editForm.occupation || ''} onChange={(e) => setEditForm({ ...editForm, occupation: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Blood Group</label>
|
||||||
|
<select value={editForm.bloodGroup || ''} onChange={(e) => setEditForm({ ...editForm, bloodGroup: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="">Select</option>
|
||||||
|
<option value="A+">A+</option>
|
||||||
|
<option value="A-">A-</option>
|
||||||
|
<option value="B+">B+</option>
|
||||||
|
<option value="B-">B-</option>
|
||||||
|
<option value="O+">O+</option>
|
||||||
|
<option value="O-">O-</option>
|
||||||
|
<option value="AB+">AB+</option>
|
||||||
|
<option value="AB-">AB-</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Marital Status</label>
|
||||||
|
<select value={editForm.maritalStatus || ''} onChange={(e) => setEditForm({ ...editForm, maritalStatus: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="">Select</option>
|
||||||
|
<option value="Single">Single</option>
|
||||||
|
<option value="Married">Married</option>
|
||||||
|
<option value="Divorced">Divorced</option>
|
||||||
|
<option value="Widowed">Widowed</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Religion</label>
|
||||||
|
<select value={editForm.religion || ''} onChange={(e) => setEditForm({ ...editForm, religion: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="">Select</option>
|
||||||
|
<option value="Islam">Islam</option>
|
||||||
|
<option value="Hinduism">Hinduism</option>
|
||||||
|
<option value="Christianity">Christianity</option>
|
||||||
|
<option value="Buddhism">Buddhism</option>
|
||||||
|
<option value="Other">Other</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Nationality</label>
|
||||||
|
<input type="text" value={editForm.nationality || ''} onChange={(e) => setEditForm({ ...editForm, nationality: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
<p className="text-xs text-slate-500">Full Name</p>
|
<p className="text-xs text-slate-500">Full Name</p>
|
||||||
<p className="font-medium text-slate-700">{investor.name}</p>
|
<p className="font-medium text-slate-700">{investor.name}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
|
||||||
<Phone className="w-5 h-5 text-slate-400" />
|
|
||||||
<div>
|
|
||||||
<p className="text-xs text-slate-500">Phone</p>
|
<p className="text-xs text-slate-500">Phone</p>
|
||||||
<p className="font-medium text-slate-700">{investor.phone}</p>
|
<p className="font-medium text-slate-700">{investor.phone}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Alternate Phone</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.phoneAlt || '-'}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
<Mail className="w-5 h-5 text-slate-400" />
|
|
||||||
<div>
|
|
||||||
<p className="text-xs text-slate-500">Email</p>
|
<p className="text-xs text-slate-500">Email</p>
|
||||||
<p className="font-medium text-slate-700">{investor.email}</p>
|
<p className="font-medium text-slate-700">{investor.email}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">NID Number</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.nidNumber || '-'}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
<MapPin className="w-5 h-5 text-slate-400" />
|
<p className="text-xs text-slate-500">TIN Number</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.tinNumber || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Date of Birth</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.dateOfBirth || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Gender</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.gender || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Occupation</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.occupation || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Blood Group</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).bloodGroup || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Marital Status</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).maritalStatus || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Religion</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).religion || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Nationality</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).nationality || 'Bangladeshi'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</SectionCard>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<SectionCard title="Nominee Details" icon={Heart} headerBg="bg-orange-50" headerBorder="border-orange-100" editKey="nominee" editingSection={editingSection} setEditingSection={setEditingSection} onEdit={() => setEditForm({
|
||||||
|
nomineeName: (investor as any).nomineeName || '',
|
||||||
|
nomineeRelation: (investor as any).nomineeRelation || '',
|
||||||
|
nomineeNid: (investor as any).nomineeNid || '',
|
||||||
|
nomineePhone: (investor as any).nomineePhone || '',
|
||||||
|
nomineeEmail: (investor as any).nomineeEmail || '',
|
||||||
|
nomineeAddress: (investor as any).nomineeAddress || '',
|
||||||
|
nomineeShare: (investor as any).nomineeShare || ''
|
||||||
|
})} editForm={editForm} setEditForm={setEditForm}>
|
||||||
|
{editingSection === 'nominee' ? (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
<div>
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Nominee Name</label>
|
||||||
|
<input type="text" value={editForm.nomineeName || ''} onChange={(e) => setEditForm({ ...editForm, nomineeName: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Relationship</label>
|
||||||
|
<select value={editForm.nomineeRelation || ''} onChange={(e) => setEditForm({ ...editForm, nomineeRelation: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="">Select</option>
|
||||||
|
<option value="Spouse">Spouse</option>
|
||||||
|
<option value="Child">Child</option>
|
||||||
|
<option value="Parent">Parent</option>
|
||||||
|
<option value="Sibling">Sibling</option>
|
||||||
|
<option value="Other">Other</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">NID Number</label>
|
||||||
|
<input type="text" value={editForm.nomineeNid || ''} onChange={(e) => setEditForm({ ...editForm, nomineeNid: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Phone</label>
|
||||||
|
<input type="text" value={editForm.nomineePhone || ''} onChange={(e) => setEditForm({ ...editForm, nomineePhone: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Email</label>
|
||||||
|
<input type="email" value={editForm.nomineeEmail || ''} onChange={(e) => setEditForm({ ...editForm, nomineeEmail: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Share %</label>
|
||||||
|
<input type="number" value={editForm.nomineeShare || ''} onChange={(e) => setEditForm({ ...editForm, nomineeShare: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Address</label>
|
||||||
|
<input type="text" value={editForm.nomineeAddress || ''} onChange={(e) => setEditForm({ ...editForm, nomineeAddress: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Nominee Name</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).nomineeName || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Relationship</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).nomineeRelation || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">NID Number</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).nomineeNid || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Phone</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).nomineePhone || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Email</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).nomineeEmail || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Share %</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).nomineeShare || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg md:col-span-2">
|
||||||
<p className="text-xs text-slate-500">Address</p>
|
<p className="text-xs text-slate-500">Address</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).nomineeAddress || '-'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</SectionCard>
|
||||||
|
|
||||||
|
<SectionCard title="Emergency Contact" icon={PhoneCall} headerBg="bg-red-50" headerBorder="border-red-100" editKey="emergency" editingSection={editingSection} setEditingSection={setEditingSection} onEdit={() => setEditForm({
|
||||||
|
emergencyName: investor.emergencyContactName || '',
|
||||||
|
emergencyRelation: investor.emergencyContactRelation || '',
|
||||||
|
emergencyPhone: investor.emergencyContactPhone || '',
|
||||||
|
emergencyEmail: (investor as any).emergencyEmail || '',
|
||||||
|
emergencyAddress: (investor as any).emergencyAddress || ''
|
||||||
|
})} editForm={editForm} setEditForm={setEditForm}>
|
||||||
|
{editingSection === 'emergency' ? (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Contact Name</label>
|
||||||
|
<input type="text" value={editForm.emergencyName || ''} onChange={(e) => setEditForm({ ...editForm, emergencyName: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Relationship</label>
|
||||||
|
<select value={editForm.emergencyRelation || ''} onChange={(e) => setEditForm({ ...editForm, emergencyRelation: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="">Select</option>
|
||||||
|
<option value="Spouse">Spouse</option>
|
||||||
|
<option value="Child">Child</option>
|
||||||
|
<option value="Parent">Parent</option>
|
||||||
|
<option value="Sibling">Sibling</option>
|
||||||
|
<option value="Friend">Friend</option>
|
||||||
|
<option value="Other">Other</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Phone</label>
|
||||||
|
<input type="text" value={editForm.emergencyPhone || ''} onChange={(e) => setEditForm({ ...editForm, emergencyPhone: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Email</label>
|
||||||
|
<input type="email" value={editForm.emergencyEmail || ''} onChange={(e) => setEditForm({ ...editForm, emergencyEmail: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Address</label>
|
||||||
|
<input type="text" value={editForm.emergencyAddress || ''} onChange={(e) => setEditForm({ ...editForm, emergencyAddress: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Contact Name</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.emergencyContactName || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Relationship</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.emergencyContactRelation || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Phone</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.emergencyContactPhone || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Email</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).emergencyEmail || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg md:col-span-2">
|
||||||
|
<p className="text-xs text-slate-500">Address</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).emergencyAddress || '-'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</SectionCard>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 space-y-4">
|
||||||
|
<SectionCard title="Investment Information" icon={Briefcase} headerBg="bg-blue-50" headerBorder="border-blue-100" editKey="investmentInfo" editingSection={editingSection} setEditingSection={setEditingSection} onEdit={() => setEditForm({
|
||||||
|
companyName: (investor as any).companyName || '',
|
||||||
|
monthlyIncome: (investor as any).monthlyIncome || '',
|
||||||
|
investmentSource: (investor as any).investmentSource || '',
|
||||||
|
profession: investor.occupation || ''
|
||||||
|
})} editForm={editForm} setEditForm={setEditForm}>
|
||||||
|
{editingSection === 'investmentInfo' ? (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Company / Business Name</label>
|
||||||
|
<input type="text" value={editForm.companyName || ''} onChange={(e) => setEditForm({ ...editForm, companyName: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Monthly Income (৳)</label>
|
||||||
|
<input type="number" value={editForm.monthlyIncome || ''} onChange={(e) => setEditForm({ ...editForm, monthlyIncome: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Investment Source</label>
|
||||||
|
<input type="text" value={editForm.investmentSource || ''} onChange={(e) => setEditForm({ ...editForm, investmentSource: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="e.g., Savings, Business profit, Inheritance" />
|
||||||
|
</div>
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Profession / Occupation</label>
|
||||||
|
<input type="text" value={editForm.profession || ''} onChange={(e) => setEditForm({ ...editForm, profession: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Company / Business Name</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).companyName || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Monthly Income</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).monthlyIncome || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Investment Source</p>
|
||||||
|
<p className="font-medium text-slate-700">{(investor as any).investmentSource || '-'}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Profession / Occupation</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.occupation || '-'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</SectionCard>
|
||||||
|
<SectionCard title="Present Address" icon={Home} headerBg="bg-green-50" headerBorder="border-green-100" editKey="presentAddress" editingSection={editingSection} setEditingSection={setEditingSection} onEdit={() => {
|
||||||
|
const parts = investor.address.split(',').map(s => s.trim());
|
||||||
|
setEditForm({
|
||||||
|
addressLine1: parts.slice(0, 2).join(', '),
|
||||||
|
addressLine2: parts.slice(2, 4).join(', '),
|
||||||
|
division: parts[4] || 'Dhaka',
|
||||||
|
district: parts[5] || 'Dhaka',
|
||||||
|
thana: parts[3] || '',
|
||||||
|
zipCode: parts[6] || '',
|
||||||
|
landmark: parts[7] || ''
|
||||||
|
});
|
||||||
|
}} editForm={editForm} setEditForm={setEditForm}>
|
||||||
|
{editingSection === 'presentAddress' ? (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Address Line 1 (House/Flat + Road)</label>
|
||||||
|
<input type="text" value={editForm.addressLine1 || ''} onChange={(e) => setEditForm({ ...editForm, addressLine1: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Address Line 2 (Block + Area)</label>
|
||||||
|
<input type="text" value={editForm.addressLine2 || ''} onChange={(e) => setEditForm({ ...editForm, addressLine2: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Division</label>
|
||||||
|
<select value={editForm.division || ''} onChange={(e) => setEditForm({ ...editForm, division: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="Dhaka">Dhaka</option>
|
||||||
|
<option value="Chittagong">Chittagong</option>
|
||||||
|
<option value="Sylhet">Sylhet</option>
|
||||||
|
<option value="Khulna">Khulna</option>
|
||||||
|
<option value="Barisal">Barisal</option>
|
||||||
|
<option value="Rangpur">Rangpur</option>
|
||||||
|
<option value="Mymensingh">Mymensingh</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">District</label>
|
||||||
|
<select value={editForm.district || ''} onChange={(e) => setEditForm({ ...editForm, district: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="Dhaka">Dhaka</option>
|
||||||
|
<option value="Gazipur">Gazipur</option>
|
||||||
|
<option value="Narayanganj">Narayanganj</option>
|
||||||
|
<option value="Tangail">Tangail</option>
|
||||||
|
<option value="Kishoreganj">Kishoreganj</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Thana</label>
|
||||||
|
<input type="text" value={editForm.thana || ''} onChange={(e) => setEditForm({ ...editForm, thana: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Zip Code</label>
|
||||||
|
<input type="text" value={editForm.zipCode || ''} onChange={(e) => setEditForm({ ...editForm, zipCode: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Landmark</label>
|
||||||
|
<input type="text" value={editForm.landmark || ''} onChange={(e) => setEditForm({ ...editForm, landmark: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Address Line 1</p>
|
||||||
<p className="font-medium text-slate-700">{investor.address}</p>
|
<p className="font-medium text-slate-700">{investor.address}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Landmark</p>
|
||||||
|
<p className="font-medium text-slate-700">-</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Division</p>
|
||||||
|
<p className="font-medium text-slate-700">Dhaka</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">District</p>
|
||||||
|
<p className="font-medium text-slate-700">Dhaka</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Thana</p>
|
||||||
|
<p className="font-medium text-slate-700">-</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Zip Code</p>
|
||||||
|
<p className="font-medium text-slate-700">1205</p>
|
||||||
</div>
|
</div>
|
||||||
{investor.dateOfBirth && (
|
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
|
||||||
<Calendar className="w-5 h-5 text-slate-400" />
|
|
||||||
<div>
|
|
||||||
<p className="text-xs text-slate-500">Date of Birth</p>
|
|
||||||
<p className="font-medium text-slate-700">{investor.dateOfBirth}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{investor.nidNumber && (
|
</SectionCard>
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
|
||||||
<Shield className="w-5 h-5 text-slate-400" />
|
<SectionCard title="Permanent Address" icon={Home} headerBg="bg-emerald-50" headerBorder="border-emerald-100" editKey="permanentAddress" editingSection={editingSection} setEditingSection={setEditingSection} onEdit={() => {
|
||||||
|
const parts = investor.address.split(',').map(s => s.trim());
|
||||||
|
setEditForm({
|
||||||
|
addressLine1: parts.slice(0, 2).join(', '),
|
||||||
|
addressLine2: parts.slice(2, 4).join(', '),
|
||||||
|
division: parts[4] || 'Dhaka',
|
||||||
|
district: parts[5] || 'Dhaka',
|
||||||
|
thana: parts[3] || '',
|
||||||
|
zipCode: parts[6] || '',
|
||||||
|
isSameAsPresent: true
|
||||||
|
});
|
||||||
|
}} editForm={editForm} setEditForm={setEditForm}>
|
||||||
|
{editingSection === 'permanentAddress' ? (
|
||||||
<div>
|
<div>
|
||||||
<p className="text-xs text-slate-500">NID Number</p>
|
<div className="flex items-center gap-2 mb-4">
|
||||||
<p className="font-medium text-slate-700">{investor.nidNumber}</p>
|
<input type="checkbox" id="sameAsPresent" checked={editForm.isSameAsPresent || false} onChange={(e) => setEditForm({ ...editForm, isSameAsPresent: e.target.checked })} className="rounded text-investor" />
|
||||||
|
<label htmlFor="sameAsPresent" className="text-sm text-slate-600">Same as Present Address</label>
|
||||||
|
</div>
|
||||||
|
{!editForm.isSameAsPresent && (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Address Line 1 (House/Flat + Road)</label>
|
||||||
|
<input type="text" value={editForm.addressLine1 || ''} onChange={(e) => setEditForm({ ...editForm, addressLine1: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Address Line 2 (Block + Area)</label>
|
||||||
|
<input type="text" value={editForm.addressLine2 || ''} onChange={(e) => setEditForm({ ...editForm, addressLine2: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Division</label>
|
||||||
|
<select value={editForm.division || ''} onChange={(e) => setEditForm({ ...editForm, division: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="Dhaka">Dhaka</option>
|
||||||
|
<option value="Chittagong">Chittagong</option>
|
||||||
|
<option value="Sylhet">Sylhet</option>
|
||||||
|
<option value="Khulna">Khulna</option>
|
||||||
|
<option value="Barisal">Barisal</option>
|
||||||
|
<option value="Rangpur">Rangpur</option>
|
||||||
|
<option value="Mymensingh">Mymensingh</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">District</label>
|
||||||
|
<select value={editForm.district || ''} onChange={(e) => setEditForm({ ...editForm, district: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm">
|
||||||
|
<option value="Dhaka">Dhaka</option>
|
||||||
|
<option value="Gazipur">Gazipur</option>
|
||||||
|
<option value="Narayanganj">Narayanganj</option>
|
||||||
|
<option value="Tangail">Tangail</option>
|
||||||
|
<option value="Kishoreganj">Kishoreganj</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Thana</label>
|
||||||
|
<input type="text" value={editForm.thana || ''} onChange={(e) => setEditForm({ ...editForm, thana: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-xs text-slate-500 mb-1 block">Zip Code</label>
|
||||||
|
<input type="text" value={editForm.zipCode || ''} onChange={(e) => setEditForm({ ...editForm, zipCode: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<span className="text-xs bg-blue-100 text-blue-700 px-2 py-1 rounded-full">Same as Present</span>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Address Line 1</p>
|
||||||
|
<p className="font-medium text-slate-700">{investor.address}</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Landmark</p>
|
||||||
|
<p className="font-medium text-slate-700">-</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Division</p>
|
||||||
|
<p className="font-medium text-slate-700">Dhaka</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">District</p>
|
||||||
|
<p className="font-medium text-slate-700">Dhaka</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Thana</p>
|
||||||
|
<p className="font-medium text-slate-700">-</p>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 bg-slate-50 rounded-lg">
|
||||||
|
<p className="text-xs text-slate-500">Zip Code</p>
|
||||||
|
<p className="font-medium text-slate-700">1205</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</SectionCard>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<h3 className="font-semibold text-slate-800 mb-4">Emergency Contact</h3>
|
|
||||||
<div className="space-y-3">
|
|
||||||
{investor.emergencyContactName && (
|
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
|
||||||
<Phone className="w-5 h-5 text-slate-400" />
|
|
||||||
<div>
|
|
||||||
<p className="text-xs text-slate-500">Contact</p>
|
|
||||||
<p className="font-medium text-slate-700">{investor.emergencyContactName}</p>
|
|
||||||
<p className="text-xs text-slate-400">{investor.emergencyContactRelation} • {investor.emergencyContactPhone}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 className="font-semibold text-slate-800 mb-4 mt-6">Investment Details</h3>
|
|
||||||
<div className="space-y-3">
|
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
|
||||||
<Calendar className="w-5 h-5 text-slate-400" />
|
|
||||||
<div>
|
|
||||||
<p className="text-xs text-slate-500">Total Investments</p>
|
|
||||||
<p className="font-medium text-slate-700">
|
|
||||||
{investor.investments?.length || 0} active investments
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
|
||||||
<FileText className="w-5 h-5 text-slate-400" />
|
|
||||||
<div>
|
|
||||||
<p className="text-xs text-slate-500">Overall Status</p>
|
|
||||||
<p className="font-medium text-slate-700 capitalize">{investor.status}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{investor.referralCode && (
|
|
||||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
|
||||||
<Star className="w-5 h-5 text-slate-400" />
|
|
||||||
<div>
|
|
||||||
<p className="text-xs text-slate-500">Referral Code</p>
|
|
||||||
<p className="font-medium text-slate-700">{investor.referralCode}</p>
|
|
||||||
<p className="text-xs text-slate-400">Referrals: {investor.totalReferrals} • Earnings: ৳{investor.referralEarnings}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{investor.notes && (
|
{investor.notes && (
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
<h3 className="font-semibold text-slate-800 mb-2">Notes</h3>
|
<h3 className="font-semibold text-slate-800 mb-2">Notes</h3>
|
||||||
@@ -767,15 +1252,13 @@ Credit (Cr): Investor Liability ৳${newInvestment.totalInvestment.toLocaleStri
|
|||||||
{investorTransactions.map(tx => (
|
{investorTransactions.map(tx => (
|
||||||
<div key={tx.id} className="flex items-center justify-between p-3 bg-slate-50 rounded-lg">
|
<div key={tx.id} className="flex items-center justify-between p-3 bg-slate-50 rounded-lg">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className={`w-10 h-10 rounded-full flex items-center justify-center ${
|
<div className={`w-10 h-10 rounded-full flex items-center justify-center ${tx.type === 'earning' || tx.type === 'bike_earning' || tx.type === 'investment_return' ? 'bg-green-100' :
|
||||||
tx.type === 'earning' || tx.type === 'bike_earning' || tx.type === 'investment_return' ? 'bg-green-100' :
|
|
||||||
tx.type === 'withdrawal' ? 'bg-red-100' :
|
tx.type === 'withdrawal' ? 'bg-red-100' :
|
||||||
tx.type === 'investment' ? 'bg-purple-100' :
|
tx.type === 'investment' ? 'bg-purple-100' :
|
||||||
tx.type === 'referral_bonus' ? 'bg-yellow-100' :
|
tx.type === 'referral_bonus' ? 'bg-yellow-100' :
|
||||||
tx.type === 'adjustment' || tx.type === 'penalty' ? 'bg-orange-100' : 'bg-blue-100'
|
tx.type === 'adjustment' || tx.type === 'penalty' ? 'bg-orange-100' : 'bg-blue-100'
|
||||||
}`}>
|
}`}>
|
||||||
<DollarSign className={`w-5 h-5 ${
|
<DollarSign className={`w-5 h-5 ${tx.type === 'earning' || tx.type === 'bike_earning' ? 'text-green-600' :
|
||||||
tx.type === 'earning' || tx.type === 'bike_earning' ? 'text-green-600' :
|
|
||||||
tx.type === 'withdrawal' ? 'text-red-600' :
|
tx.type === 'withdrawal' ? 'text-red-600' :
|
||||||
tx.type === 'investment' ? 'text-purple-600' :
|
tx.type === 'investment' ? 'text-purple-600' :
|
||||||
tx.type === 'referral_bonus' ? 'text-yellow-600' :
|
tx.type === 'referral_bonus' ? 'text-yellow-600' :
|
||||||
@@ -840,14 +1323,12 @@ Credit (Cr): Investor Liability ৳${newInvestment.totalInvestment.toLocaleStri
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<p className={`text-sm font-medium ${
|
<p className={`text-sm font-medium ${tx.type === 'earning' || tx.type === 'bike_earning' || tx.type === 'investment_return' || tx.type === 'referral_bonus' ? 'text-green-600' :
|
||||||
tx.type === 'earning' || tx.type === 'bike_earning' || tx.type === 'investment_return' || tx.type === 'referral_bonus' ? 'text-green-600' :
|
|
||||||
tx.type === 'withdrawal' || tx.type === 'penalty' || tx.type === 'adjustment' ? 'text-red-600' : 'text-blue-600'
|
tx.type === 'withdrawal' || tx.type === 'penalty' || tx.type === 'adjustment' ? 'text-red-600' : 'text-blue-600'
|
||||||
}`}>
|
}`}>
|
||||||
{tx.type === 'earning' || tx.type === 'bike_earning' || tx.type === 'investment_return' || tx.type === 'referral_bonus' ? '+' : tx.type === 'withdrawal' || tx.type === 'penalty' || tx.type === 'adjustment' ? '-' : '+'}৳{tx.amount.toLocaleString()}
|
{tx.type === 'earning' || tx.type === 'bike_earning' || tx.type === 'investment_return' || tx.type === 'referral_bonus' ? '+' : tx.type === 'withdrawal' || tx.type === 'penalty' || tx.type === 'adjustment' ? '-' : '+'}৳{tx.amount.toLocaleString()}
|
||||||
</p>
|
</p>
|
||||||
<span className={`text-xs font-medium px-2 py-0.5 rounded-full ${
|
<span className={`text-xs font-medium px-2 py-0.5 rounded-full ${tx.status === 'completed' ? 'bg-green-100 text-green-700' :
|
||||||
tx.status === 'completed' ? 'bg-green-100 text-green-700' :
|
|
||||||
tx.status === 'pending' ? 'bg-amber-100 text-amber-700' :
|
tx.status === 'pending' ? 'bg-amber-100 text-amber-700' :
|
||||||
tx.status === 'cancelled' ? 'bg-red-100 text-red-700' : 'bg-slate-100 text-slate-700'
|
tx.status === 'cancelled' ? 'bg-red-100 text-red-700' : 'bg-slate-100 text-slate-700'
|
||||||
}`}>
|
}`}>
|
||||||
@@ -880,14 +1361,12 @@ Credit (Cr): Investor Liability ৳${newInvestment.totalInvestment.toLocaleStri
|
|||||||
{investor.kycDocuments?.map((doc, idx) => (
|
{investor.kycDocuments?.map((doc, idx) => (
|
||||||
<div key={idx} className="flex items-center justify-between p-4 bg-slate-50 rounded-lg">
|
<div key={idx} className="flex items-center justify-between p-4 bg-slate-50 rounded-lg">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className={`w-12 h-12 rounded-lg flex items-center justify-center ${
|
<div className={`w-12 h-12 rounded-lg flex items-center justify-center ${doc.type === 'nid' ? 'bg-blue-100' :
|
||||||
doc.type === 'nid' ? 'bg-blue-100' :
|
|
||||||
doc.type === 'passport' ? 'bg-purple-100' :
|
doc.type === 'passport' ? 'bg-purple-100' :
|
||||||
doc.type === 'bank_statement' ? 'bg-green-100' :
|
doc.type === 'bank_statement' ? 'bg-green-100' :
|
||||||
doc.type === 'tin_certificate' ? 'bg-amber-100' : 'bg-slate-100'
|
doc.type === 'tin_certificate' ? 'bg-amber-100' : 'bg-slate-100'
|
||||||
}`}>
|
}`}>
|
||||||
<FileText className={`w-6 h-6 ${
|
<FileText className={`w-6 h-6 ${doc.type === 'nid' ? 'text-blue-600' :
|
||||||
doc.type === 'nid' ? 'text-blue-600' :
|
|
||||||
doc.type === 'passport' ? 'text-purple-600' :
|
doc.type === 'passport' ? 'text-purple-600' :
|
||||||
doc.type === 'bank_statement' ? 'text-green-600' :
|
doc.type === 'bank_statement' ? 'text-green-600' :
|
||||||
doc.type === 'tin_certificate' ? 'text-amber-600' : 'text-slate-600'
|
doc.type === 'tin_certificate' ? 'text-amber-600' : 'text-slate-600'
|
||||||
@@ -1456,8 +1935,7 @@ Credit (Cr): Investor Liability ৳${newInvestment.totalInvestment.toLocaleStri
|
|||||||
|
|
||||||
<div className="flex justify-between mb-2">
|
<div className="flex justify-between mb-2">
|
||||||
<span className="text-xs text-slate-500">Status</span>
|
<span className="text-xs text-slate-500">Status</span>
|
||||||
<span className={`text-xs px-2 py-1 rounded-full ${
|
<span className={`text-xs px-2 py-1 rounded-full ${selectedInvoice.status === 'completed' ? 'bg-green-100 text-green-700' :
|
||||||
selectedInvoice.status === 'completed' ? 'bg-green-100 text-green-700' :
|
|
||||||
selectedInvoice.status === 'pending' ? 'bg-amber-100 text-amber-700' : 'bg-slate-100 text-slate-700'
|
selectedInvoice.status === 'pending' ? 'bg-amber-100 text-amber-700' : 'bg-slate-100 text-slate-700'
|
||||||
}`}>
|
}`}>
|
||||||
{selectedInvoice.status}
|
{selectedInvoice.status}
|
||||||
|
|||||||
@@ -30,10 +30,6 @@ interface InvestmentSettingsProps {
|
|||||||
setNewInvestLock: (n: number) => void;
|
setNewInvestLock: (n: number) => void;
|
||||||
newInvestPenalty: number;
|
newInvestPenalty: number;
|
||||||
setNewInvestPenalty: (n: number) => void;
|
setNewInvestPenalty: (n: number) => void;
|
||||||
newInvestMonthly: number;
|
|
||||||
setNewInvestMonthly: (n: number) => void;
|
|
||||||
newInvestTotal: number;
|
|
||||||
setNewInvestTotal: (n: number) => void;
|
|
||||||
newInvestFicoSingleRent: number;
|
newInvestFicoSingleRent: number;
|
||||||
setNewInvestFicoSingleRent: (n: number) => void;
|
setNewInvestFicoSingleRent: (n: number) => void;
|
||||||
newInvestFicoRentToOwn: number;
|
newInvestFicoRentToOwn: number;
|
||||||
@@ -42,6 +38,10 @@ interface InvestmentSettingsProps {
|
|||||||
setNewInvestFicoShareEv: (n: number) => void;
|
setNewInvestFicoShareEv: (n: number) => void;
|
||||||
newInvestDesc: string;
|
newInvestDesc: string;
|
||||||
setNewInvestDesc: (v: string) => void;
|
setNewInvestDesc: (v: string) => void;
|
||||||
|
newInvestEvBasePrice: number;
|
||||||
|
setNewInvestEvBasePrice: (n: number) => void;
|
||||||
|
newInvestMinQuantity: number;
|
||||||
|
setNewInvestMinQuantity: (n: number) => void;
|
||||||
createInvestPlan: () => void;
|
createInvestPlan: () => void;
|
||||||
handleSave: () => void;
|
handleSave: () => void;
|
||||||
}
|
}
|
||||||
@@ -60,14 +60,15 @@ export default function InvestmentSettings({
|
|||||||
newInvestDuration, setNewInvestDuration,
|
newInvestDuration, setNewInvestDuration,
|
||||||
newInvestLock, setNewInvestLock,
|
newInvestLock, setNewInvestLock,
|
||||||
newInvestPenalty, setNewInvestPenalty,
|
newInvestPenalty, setNewInvestPenalty,
|
||||||
newInvestMonthly, setNewInvestMonthly,
|
|
||||||
newInvestTotal, setNewInvestTotal,
|
|
||||||
newInvestFicoSingleRent, setNewInvestFicoSingleRent,
|
newInvestFicoSingleRent, setNewInvestFicoSingleRent,
|
||||||
newInvestFicoRentToOwn, setNewInvestFicoRentToOwn,
|
newInvestFicoRentToOwn, setNewInvestFicoRentToOwn,
|
||||||
newInvestFicoShareEv, setNewInvestFicoShareEv,
|
newInvestFicoShareEv, setNewInvestFicoShareEv,
|
||||||
newInvestDesc, setNewInvestDesc,
|
newInvestDesc, setNewInvestDesc,
|
||||||
|
newInvestEvBasePrice, setNewInvestEvBasePrice,
|
||||||
|
newInvestMinQuantity, setNewInvestMinQuantity,
|
||||||
createInvestPlan, handleSave,
|
createInvestPlan, handleSave,
|
||||||
}: InvestmentSettingsProps) {
|
}: InvestmentSettingsProps) {
|
||||||
|
const calculatedMinInvestment = newInvestMinQuantity * newInvestEvBasePrice;
|
||||||
return (
|
return (
|
||||||
<div className="p-6 space-y-6">
|
<div className="p-6 space-y-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@@ -121,9 +122,20 @@ export default function InvestmentSettings({
|
|||||||
<label className="text-sm text-slate-600">End Date</label>
|
<label className="text-sm text-slate-600">End Date</label>
|
||||||
<input type="date" value={newInvestEnd} onChange={(e) => setNewInvestEnd(e.target.value)} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
<input type="date" value={newInvestEnd} onChange={(e) => setNewInvestEnd(e.target.value)} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600">EV Base Price (৳)</label>
|
||||||
|
<input type="number" value={newInvestEvBasePrice} onChange={(e) => setNewInvestEvBasePrice(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" placeholder="Single EV cost" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600">Minimum Quantity (Bikes)</label>
|
||||||
|
<input type="number" value={newInvestMinQuantity} onChange={(e) => setNewInvestMinQuantity(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" placeholder="Min bikes to invest" />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm text-slate-600">Min Investment (৳)</label>
|
<label className="text-sm text-slate-600">Min Investment (৳)</label>
|
||||||
<input type="number" value={newInvestMin} onChange={(e) => setNewInvestMin(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
<div className="flex items-center gap-2 mt-1">
|
||||||
|
<input type="number" value={calculatedMinInvestment} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-100" />
|
||||||
|
<span className="text-xs text-slate-500 whitespace-nowrap">= Qty × Base Price</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm text-slate-600">Max Investment (৳)</label>
|
<label className="text-sm text-slate-600">Max Investment (৳)</label>
|
||||||
@@ -141,14 +153,6 @@ export default function InvestmentSettings({
|
|||||||
<label className="text-sm text-slate-600">Early Exit Penalty (%)</label>
|
<label className="text-sm text-slate-600">Early Exit Penalty (%)</label>
|
||||||
<input type="number" value={newInvestPenalty} onChange={(e) => setNewInvestPenalty(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
<input type="number" value={newInvestPenalty} onChange={(e) => setNewInvestPenalty(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label className="text-sm text-slate-600">Monthly Return (%)</label>
|
|
||||||
<input type="number" step="0.1" value={newInvestMonthly} onChange={(e) => setNewInvestMonthly(parseFloat(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="text-sm text-slate-600">Total Return (%)</label>
|
|
||||||
<input type="number" step="0.1" value={newInvestTotal} onChange={(e) => setNewInvestTotal(parseFloat(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-3 gap-4 mt-4">
|
<div className="grid grid-cols-3 gap-4 mt-4">
|
||||||
<div>
|
<div>
|
||||||
@@ -183,7 +187,7 @@ export default function InvestmentSettings({
|
|||||||
<div key={idx} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
<div key={idx} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||||
<div className="bg-amber-50 px-4 py-3 border-b border-amber-100 flex items-center justify-between">
|
<div className="bg-amber-50 px-4 py-3 border-b border-amber-100 flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-semibold text-amber-800">{plan.name} - {plan.monthlyReturnPercent}% per month</h4>
|
<h4 className="font-semibold text-amber-800">{plan.name}</h4>
|
||||||
<p className="text-sm text-amber-600 mt-1">{plan.description}</p>
|
<p className="text-sm text-amber-600 mt-1">{plan.description}</p>
|
||||||
</div>
|
</div>
|
||||||
<span className={`px-2 py-1 rounded-full text-xs font-medium ${plan.status === 'active' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>{plan.status}</span>
|
<span className={`px-2 py-1 rounded-full text-xs font-medium ${plan.status === 'active' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>{plan.status}</span>
|
||||||
@@ -214,9 +218,20 @@ export default function InvestmentSettings({
|
|||||||
<label className="text-sm text-slate-600">End Date</label>
|
<label className="text-sm text-slate-600">End Date</label>
|
||||||
<input type="date" value={plan.endDate} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].endDate = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
<input type="date" value={plan.endDate} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].endDate = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600">EV Base Price (৳)</label>
|
||||||
|
<input type="number" value={plan.evBasePrice} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].evBasePrice = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600">Minimum Quantity (Bikes)</label>
|
||||||
|
<input type="number" value={plan.minQuantity} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].minQuantity = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm text-slate-600">Min Investment (৳)</label>
|
<label className="text-sm text-slate-600">Min Investment (৳)</label>
|
||||||
<input type="number" value={plan.minInvestment} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].minInvestment = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
<div className="flex items-center gap-2 mt-1">
|
||||||
|
<input type="number" value={plan.evBasePrice * plan.minQuantity} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-100" />
|
||||||
|
<span className="text-xs text-slate-500 whitespace-nowrap">= Qty × Base Price</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm text-slate-600">Max Investment (৳)</label>
|
<label className="text-sm text-slate-600">Max Investment (৳)</label>
|
||||||
@@ -234,14 +249,6 @@ export default function InvestmentSettings({
|
|||||||
<label className="text-sm text-slate-600">Early Exit Penalty (%)</label>
|
<label className="text-sm text-slate-600">Early Exit Penalty (%)</label>
|
||||||
<input type="number" value={plan.earlyExitPenalty} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].earlyExitPenalty = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
<input type="number" value={plan.earlyExitPenalty} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].earlyExitPenalty = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label className="text-sm text-slate-600">Monthly Return (%)</label>
|
|
||||||
<input type="number" step="0.1" value={plan.monthlyReturnPercent} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].monthlyReturnPercent = parseFloat(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="text-sm text-slate-600">Total Return (%)</label>
|
|
||||||
<input type="number" step="0.1" value={plan.totalReturnPercent} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].totalReturnPercent = parseFloat(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-3 gap-4 mt-4">
|
<div className="grid grid-cols-3 gap-4 mt-4">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -184,13 +184,13 @@ export interface CompanySettings {
|
|||||||
id: string;
|
id: string;
|
||||||
tier: string;
|
tier: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
minQuantity: number;
|
||||||
|
evBasePrice: number;
|
||||||
minInvestment: number;
|
minInvestment: number;
|
||||||
maxInvestment: number;
|
maxInvestment: number;
|
||||||
monthlyReturnPercent: number;
|
|
||||||
durationMonths: number;
|
durationMonths: number;
|
||||||
profitSharePercent: number;
|
profitSharePercent: number;
|
||||||
lockInMonths: number;
|
lockInMonths: number;
|
||||||
totalReturnPercent: number;
|
|
||||||
earlyExitPenalty: number;
|
earlyExitPenalty: number;
|
||||||
startDate: string;
|
startDate: string;
|
||||||
endDate: string;
|
endDate: string;
|
||||||
@@ -695,13 +695,13 @@ const initialSettings: CompanySettings = {
|
|||||||
id: 'inv_demo_1',
|
id: 'inv_demo_1',
|
||||||
name: '1 Bike Plan',
|
name: '1 Bike Plan',
|
||||||
tier: 'Economy',
|
tier: 'Economy',
|
||||||
minInvestment: 50000,
|
minQuantity: 1,
|
||||||
maxInvestment: 100000,
|
evBasePrice: 200000,
|
||||||
monthlyReturnPercent: 2,
|
minInvestment: 200000,
|
||||||
|
maxInvestment: 1000000,
|
||||||
durationMonths: 12,
|
durationMonths: 12,
|
||||||
profitSharePercent: 50,
|
profitSharePercent: 50,
|
||||||
lockInMonths: 3,
|
lockInMonths: 3,
|
||||||
totalReturnPercent: 24,
|
|
||||||
earlyExitPenalty: 10,
|
earlyExitPenalty: 10,
|
||||||
startDate: '2026-01-01',
|
startDate: '2026-01-01',
|
||||||
endDate: '2026-12-31',
|
endDate: '2026-12-31',
|
||||||
@@ -716,13 +716,13 @@ const initialSettings: CompanySettings = {
|
|||||||
id: 'inv_demo_2',
|
id: 'inv_demo_2',
|
||||||
name: '5 Bike Plan',
|
name: '5 Bike Plan',
|
||||||
tier: 'Standard',
|
tier: 'Standard',
|
||||||
minInvestment: 150000,
|
minQuantity: 5,
|
||||||
maxInvestment: 500000,
|
evBasePrice: 180000,
|
||||||
monthlyReturnPercent: 2.5,
|
minInvestment: 900000,
|
||||||
|
maxInvestment: 5000000,
|
||||||
durationMonths: 24,
|
durationMonths: 24,
|
||||||
profitSharePercent: 50,
|
profitSharePercent: 50,
|
||||||
lockInMonths: 6,
|
lockInMonths: 6,
|
||||||
totalReturnPercent: 60,
|
|
||||||
earlyExitPenalty: 10,
|
earlyExitPenalty: 10,
|
||||||
startDate: '2026-01-01',
|
startDate: '2026-01-01',
|
||||||
endDate: '2026-12-31',
|
endDate: '2026-12-31',
|
||||||
@@ -846,16 +846,16 @@ export default function CompanySettingsPage() {
|
|||||||
const [newInvestEnd, setNewInvestEnd] = useState('2026-12-31');
|
const [newInvestEnd, setNewInvestEnd] = useState('2026-12-31');
|
||||||
const [newInvestMin, setNewInvestMin] = useState(10000);
|
const [newInvestMin, setNewInvestMin] = useState(10000);
|
||||||
const [newInvestMax, setNewInvestMax] = useState(100000);
|
const [newInvestMax, setNewInvestMax] = useState(100000);
|
||||||
const [newInvestMonthly, setNewInvestMonthly] = useState(2);
|
|
||||||
const [newInvestDuration, setNewInvestDuration] = useState(12);
|
const [newInvestDuration, setNewInvestDuration] = useState(12);
|
||||||
const [newInvestLock, setNewInvestLock] = useState(3);
|
const [newInvestLock, setNewInvestLock] = useState(3);
|
||||||
const [newInvestTotal, setNewInvestTotal] = useState(24);
|
|
||||||
const [newInvestPenalty, setNewInvestPenalty] = useState(10);
|
const [newInvestPenalty, setNewInvestPenalty] = useState(10);
|
||||||
const [newInvestProfitShare, setNewInvestProfitShare] = useState(50);
|
const [newInvestProfitShare, setNewInvestProfitShare] = useState(50);
|
||||||
const [newInvestFicoSingleRent, setNewInvestFicoSingleRent] = useState(45);
|
const [newInvestFicoSingleRent, setNewInvestFicoSingleRent] = useState(45);
|
||||||
const [newInvestFicoRentToOwn, setNewInvestFicoRentToOwn] = useState(55);
|
const [newInvestFicoRentToOwn, setNewInvestFicoRentToOwn] = useState(55);
|
||||||
const [newInvestFicoShareEv, setNewInvestFicoShareEv] = useState(60);
|
const [newInvestFicoShareEv, setNewInvestFicoShareEv] = useState(60);
|
||||||
const [newInvestDesc, setNewInvestDesc] = useState('');
|
const [newInvestDesc, setNewInvestDesc] = useState('');
|
||||||
|
const [newInvestEvBasePrice, setNewInvestEvBasePrice] = useState(200000);
|
||||||
|
const [newInvestMinQuantity, setNewInvestMinQuantity] = useState(1);
|
||||||
|
|
||||||
const createInvestPlan = () => {
|
const createInvestPlan = () => {
|
||||||
if (newInvestName.trim() && typeof window !== 'undefined') {
|
if (newInvestName.trim() && typeof window !== 'undefined') {
|
||||||
@@ -863,13 +863,13 @@ export default function CompanySettingsPage() {
|
|||||||
id: 'inv_' + Date.now(),
|
id: 'inv_' + Date.now(),
|
||||||
name: newInvestName,
|
name: newInvestName,
|
||||||
tier: newInvestTier,
|
tier: newInvestTier,
|
||||||
minInvestment: newInvestMin,
|
evBasePrice: newInvestEvBasePrice,
|
||||||
|
minQuantity: newInvestMinQuantity,
|
||||||
|
minInvestment: newInvestEvBasePrice * newInvestMinQuantity,
|
||||||
maxInvestment: newInvestMax,
|
maxInvestment: newInvestMax,
|
||||||
monthlyReturnPercent: newInvestMonthly,
|
|
||||||
durationMonths: newInvestDuration,
|
durationMonths: newInvestDuration,
|
||||||
profitSharePercent: newInvestProfitShare,
|
profitSharePercent: newInvestProfitShare,
|
||||||
lockInMonths: newInvestLock,
|
lockInMonths: newInvestLock,
|
||||||
totalReturnPercent: newInvestTotal,
|
|
||||||
earlyExitPenalty: newInvestPenalty,
|
earlyExitPenalty: newInvestPenalty,
|
||||||
startDate: newInvestStart,
|
startDate: newInvestStart,
|
||||||
endDate: newInvestEnd,
|
endDate: newInvestEnd,
|
||||||
@@ -1306,12 +1306,12 @@ export default function CompanySettingsPage() {
|
|||||||
newInvestDuration={newInvestDuration} setNewInvestDuration={setNewInvestDuration}
|
newInvestDuration={newInvestDuration} setNewInvestDuration={setNewInvestDuration}
|
||||||
newInvestLock={newInvestLock} setNewInvestLock={setNewInvestLock}
|
newInvestLock={newInvestLock} setNewInvestLock={setNewInvestLock}
|
||||||
newInvestPenalty={newInvestPenalty} setNewInvestPenalty={setNewInvestPenalty}
|
newInvestPenalty={newInvestPenalty} setNewInvestPenalty={setNewInvestPenalty}
|
||||||
newInvestMonthly={newInvestMonthly} setNewInvestMonthly={setNewInvestMonthly}
|
|
||||||
newInvestTotal={newInvestTotal} setNewInvestTotal={setNewInvestTotal}
|
|
||||||
newInvestFicoSingleRent={newInvestFicoSingleRent} setNewInvestFicoSingleRent={setNewInvestFicoSingleRent}
|
newInvestFicoSingleRent={newInvestFicoSingleRent} setNewInvestFicoSingleRent={setNewInvestFicoSingleRent}
|
||||||
newInvestFicoRentToOwn={newInvestFicoRentToOwn} setNewInvestFicoRentToOwn={setNewInvestFicoRentToOwn}
|
newInvestFicoRentToOwn={newInvestFicoRentToOwn} setNewInvestFicoRentToOwn={setNewInvestFicoRentToOwn}
|
||||||
newInvestFicoShareEv={newInvestFicoShareEv} setNewInvestFicoShareEv={setNewInvestFicoShareEv}
|
newInvestFicoShareEv={newInvestFicoShareEv} setNewInvestFicoShareEv={setNewInvestFicoShareEv}
|
||||||
newInvestDesc={newInvestDesc} setNewInvestDesc={setNewInvestDesc}
|
newInvestDesc={newInvestDesc} setNewInvestDesc={setNewInvestDesc}
|
||||||
|
newInvestEvBasePrice={newInvestEvBasePrice} setNewInvestEvBasePrice={setNewInvestEvBasePrice}
|
||||||
|
newInvestMinQuantity={newInvestMinQuantity} setNewInvestMinQuantity={setNewInvestMinQuantity}
|
||||||
createInvestPlan={createInvestPlan} handleSave={handleSave}
|
createInvestPlan={createInvestPlan} handleSave={handleSave}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user