From 1fd8c5153a27795a01d07a7f004f7679223cfddf Mon Sep 17 00:00:00 2001 From: sazzadulalambd Date: Fri, 15 May 2026 01:25:48 +0600 Subject: [PATCH] feat: implement investor withdrawal flow and add necessary profile, investment, and planning pages --- src/app/investor/profile/page.tsx | 1106 +++++++++++++++++++++++++++++ 1 file changed, 1106 insertions(+) create mode 100644 src/app/investor/profile/page.tsx diff --git a/src/app/investor/profile/page.tsx b/src/app/investor/profile/page.tsx new file mode 100644 index 0000000..7a7082d --- /dev/null +++ b/src/app/investor/profile/page.tsx @@ -0,0 +1,1106 @@ +'use client'; + +import { useState } from 'react'; +import { + Camera, Save, CheckCircle, Upload, Plus, Trash2, + ShieldCheck, CreditCard, Building2, Smartphone, User, MapPin, Phone, Briefcase, + Calendar, Mail, FileText, ChevronRight, Edit, Heart, PhoneCall, X, Eye, EyeOff, + Lock, Key, Shield, Activity, LogOut, AlertCircle, Trash, Pencil, Home, + Banknote, + TrashIcon +} from 'lucide-react'; +import { investors } from '@/data/mockData'; +import toast from 'react-hot-toast'; + +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 ( +
+
+
+ +

{title}

+
+ {editKey && setEditingSection ? ( + editingSection !== editKey ? ( + + ) : ( +
+ + +
+ ) + ) : null} +
+
+ {children} +
+
+ ); +} + +export default function InvestorProfilePage() { + const investor = investors.find(i => i.id === 'inv1') || investors[0]; + const [activeTab, setActiveTab] = useState('personal'); + const [editingSection, setEditingSection] = useState(null); + const [editForm, setEditForm] = useState({}); + const [showPassword, setShowPassword] = useState({ current: false, new: false, confirm: false }); + const [passwordForm, setPasswordForm] = useState({ current: '', new: '', confirm: '' }); + const [twoFactorEnabled, setTwoFactorEnabled] = useState(false); + + const [showAddBankModal, setShowAddBankModal] = useState(false); + const [showEditBankModal, setShowEditBankModal] = useState(false); + const [showDeleteBankModal, setShowDeleteBankModal] = useState(false); + const [editingBank, setEditingBank] = useState({ id: '', bankName: '', accountName: '', accountNumber: '', branch: '', routing: '', isPrimary: false }); + const [bankToDelete, setBankToDelete] = useState(null); + + const [showAddMobileModal, setShowAddMobileModal] = useState(false); + const [showEditMobileModal, setShowEditMobileModal] = useState(false); + const [showDeleteMobileModal, setShowDeleteMobileModal] = useState(false); + const [showTaxModal, setShowTaxModal] = useState(false); + const [editingMobile, setEditingMobile] = useState({ provider: '', number: '', isPrimary: false }); + const [editingMobileIndex, setEditingMobileIndex] = useState(null); + const [editingTax, setEditingTax] = useState({ tinNumber: '', passportNumber: '' }); + const [mobileToDelete, setMobileToDelete] = useState(null); + + const [newBankForm, setNewBankForm] = useState({ bankName: '', accountName: '', accountNumber: '', branch: '', routing: '', isPrimary: false }); + const [newMobileForm, setNewMobileForm] = useState({ provider: '', number: '' }); + + const currentBalance = investor.totalEarnings - investor.totalWithdrawn - investor.pendingEarnings; + + const sessionHistory = [ + { id: 1, device: 'iPhone 14 Pro', location: 'Dhaka, Bangladesh', time: '2 hours ago', current: true }, + { id: 2, device: 'Chrome on Windows', location: 'Dhaka, Bangladesh', time: '2 days ago', current: false }, + ]; + + const handlePasswordChange = () => { + if (passwordForm.new !== passwordForm.confirm) { + toast.error('Passwords do not match!'); + return; + } + if (passwordForm.new.length < 8) { + toast.error('Password must be at least 8 characters!'); + return; + } + toast.success('Password changed successfully!'); + setPasswordForm({ current: '', new: '', confirm: '' }); + }; + + const handleSaveBank = () => { + toast.success('Bank account saved successfully!'); + setShowAddBankModal(false); + setShowEditBankModal(false); + setNewBankForm({ bankName: '', accountName: '', accountNumber: '', branch: '', routing: '', isPrimary: false }); + }; + + const handleDeleteBank = () => { + toast.success('Bank account deleted!'); + setShowDeleteBankModal(false); + }; + + const handleSaveMobile = () => { + toast.success('Mobile banking saved successfully!'); + setShowAddMobileModal(false); + setShowEditMobileModal(false); + setNewMobileForm({ provider: '', number: '' }); + }; + + const handleDeleteMobile = () => { + toast.success('Mobile banking deleted!'); + setShowDeleteMobileModal(false); + }; + + const tabs = [ + { id: 'personal', label: 'Personal Info', icon: User }, + { id: 'nominee', label: 'Nominee & Emergency', icon: Heart }, + { id: 'financial', label: 'Financial', icon: CreditCard }, + { id: 'kyc', label: 'KYC', icon: FileText }, + { id: 'security', label: 'Security', icon: Lock }, + ]; + + return ( +
+
+ {/* Profile Header */} +
+
+
+
+ {investor.name.charAt(0)} +
+ +
+ +
+
+

{investor.name}

+ + KYC {investor.kycStatus} + + + {investor.status} + + + Risk: {investor.riskLevel} + +
+

{investor.id} • {investor.email}

+
+ Ref: {investor.referralCode} + {investor.totalReferrals} Referrals + • {investor.investments?.length || 0} Investments + • Referral Earnings: ৳{investor.referralEarnings?.toLocaleString() || 0} +
+
+
+ +
+
+

Invested

+

৳{investor.totalInvested.toLocaleString()}

+
+
+

Earnings

+

৳{investor.totalEarnings.toLocaleString()}

+
+
+

Withdrawn

+

৳{investor.totalWithdrawn.toLocaleString()}

+
+
+

Balance

+

৳{currentBalance.toLocaleString()}

+
+
+

Bikes

+

{investor.activeBikes}

+
+
+

Pending

+

৳{investor.pendingEarnings.toLocaleString()}

+
+
+
+ + {/* Tabs */} +
+
+ {tabs.map(tab => { + const Icon = tab.icon; + return ( + + ); + })} +
+ +
+ {/* Personal Info Tab */} + {activeTab === 'personal' && ( +
+
+ 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' ? ( +
+
+ + setEditForm({ ...editForm, fullName: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, phone: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, phoneAlt: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, email: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, nidNumber: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, tinNumber: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, dateOfBirth: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + +
+
+ + setEditForm({ ...editForm, occupation: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + +
+
+ + +
+
+ + +
+
+ + setEditForm({ ...editForm, nationality: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ ) : ( +
+

Full Name

{investor.name}

+

Phone

{investor.phone}

+

Alternate Phone

{investor.phoneAlt || '-'}

+

Email

{investor.email}

+

NID Number

{investor.nidNumber || '-'}

+

TIN Number

{investor.tinNumber || '-'}

+

Date of Birth

{investor.dateOfBirth || '-'}

+

Gender

{investor.gender || '-'}

+

Occupation

{investor.occupation || '-'}

+

Blood Group

{(investor as any).bloodGroup || '-'}

+

Marital Status

{(investor as any).maritalStatus || '-'}

+

Religion

{(investor as any).religion || '-'}

+

Nationality

{(investor as any).nationality || 'Bangladeshi'}

+
+ )} +
+ + 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' ? ( +
+
+ + setEditForm({ ...editForm, companyName: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, monthlyIncome: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, investmentSource: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, profession: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ ) : ( +
+

Company / Business Name

{(investor as any).companyName || '-'}

+

Monthly Income

{(investor as any).monthlyIncome || '-'}

+

Investment Source

{(investor as any).investmentSource || '-'}

+

Profession / Occupation

{investor.occupation || '-'}

+
+ )} +
+
+ +
+ + { + 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] || '1205', + landmark: parts[7] || '' + }); + }} + editForm={editForm} setEditForm={setEditForm}> + {editingSection === 'presentAddress' ? ( +
+
+ + setEditForm({ ...editForm, addressLine1: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, addressLine2: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + +
+
+ + +
+
+ + setEditForm({ ...editForm, thana: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, zipCode: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, landmark: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ ) : ( +
+

Address Line 1

{investor.address}

+

Landmark

-

+
+

Division

Dhaka

+

District

Dhaka

+

Thana

-

+

Zip Code

1205

+
+
+ )} +
+ + { + 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] || '1205', + isSameAsPresent: true + }); + }} + editForm={editForm} setEditForm={setEditForm}> + {editingSection === 'permanentAddress' ? ( +
+
+ setEditForm({ ...editForm, isSameAsPresent: e.target.checked })} className="rounded text-investor" /> + +
+ {!editForm.isSameAsPresent && ( +
+
+ + setEditForm({ ...editForm, addressLine1: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, addressLine2: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + +
+
+ + +
+
+ + setEditForm({ ...editForm, thana: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ + setEditForm({ ...editForm, zipCode: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" /> +
+
+ )} +
+ ) : ( +
+
+ Same as Present +
+

Address Line 1

{investor.address}

+

Landmark

-

+
+

Division

Dhaka

+

District

Dhaka

+

Thana

-

+

Zip Code

1205

+
+
+ )} +
+ setEditForm({ notes: investor.notes || '' })} + editForm={editForm} setEditForm={setEditForm}> + {editingSection === 'note' ? ( +
+