Compare commits
2 Commits
a62923f1a1
...
100b567e3a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
100b567e3a | ||
|
|
bf3e1c8931 |
@@ -289,6 +289,15 @@ export default function RentalDetailPage() {
|
|||||||
const [lockReason, setLockReason] = useState('');
|
const [lockReason, setLockReason] = useState('');
|
||||||
const [rejectNote, setRejectNote] = useState('');
|
const [rejectNote, setRejectNote] = useState('');
|
||||||
const [showRejectModal, setShowRejectModal] = useState(false);
|
const [showRejectModal, setShowRejectModal] = useState(false);
|
||||||
|
const [showDamageModal, setShowDamageModal] = useState(false);
|
||||||
|
const [showSmsModal, setShowSmsModal] = useState(false);
|
||||||
|
const [damageDesc, setDamageDesc] = useState('');
|
||||||
|
const [damageSeverity, setDamageSeverity] = useState<'minor' | 'moderate' | 'severe'>('minor');
|
||||||
|
const [smsText, setSmsText] = useState('');
|
||||||
|
const [damages, setDamages] = useState(mockDamageHistory);
|
||||||
|
const [documents, setDocuments] = useState(mockDocuments);
|
||||||
|
const [showUploadModal, setShowUploadModal] = useState(false);
|
||||||
|
const [uploadDocName, setUploadDocName] = useState('');
|
||||||
|
|
||||||
const [acceptPermission, setAcceptPermission] = useState(false);
|
const [acceptPermission, setAcceptPermission] = useState(false);
|
||||||
const [rejectPermission, setRejectPermission] = useState(false);
|
const [rejectPermission, setRejectPermission] = useState(false);
|
||||||
@@ -447,6 +456,28 @@ export default function RentalDetailPage() {
|
|||||||
setNewNote('');
|
setNewNote('');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleReportDamage = () => {
|
||||||
|
if (!damageDesc.trim()) return;
|
||||||
|
setDamages(prev => [...prev, { id: `DMG-${Date.now()}`, date: new Date().toISOString().split('T')[0], description: damageDesc, severity: damageSeverity, status: 'reported' }]);
|
||||||
|
setDamageDesc('');
|
||||||
|
setDamageSeverity('minor');
|
||||||
|
setShowDamageModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUploadDocument = () => {
|
||||||
|
if (!uploadDocName.trim()) return;
|
||||||
|
setDocuments(prev => [...prev, { id: `DOC-${Date.now()}`, name: uploadDocName, type: 'other', uploadedAt: new Date().toISOString().split('T')[0], downloaded: false }]);
|
||||||
|
setUploadDocName('');
|
||||||
|
setShowUploadModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSendSms = () => {
|
||||||
|
if (!smsText.trim()) return;
|
||||||
|
alert(`SMS sent to ${rental.userPhone}: ${smsText}`);
|
||||||
|
setSmsText('');
|
||||||
|
setShowSmsModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
const statusBadge = getStatusBadge(rental.status);
|
const statusBadge = getStatusBadge(rental.status);
|
||||||
const typeBadge = getTypeBadge(rental.type);
|
const typeBadge = getTypeBadge(rental.type);
|
||||||
const paymentBadge = getPaymentStatusBadge(rental.paymentStatus);
|
const paymentBadge = getPaymentStatusBadge(rental.paymentStatus);
|
||||||
@@ -601,6 +632,9 @@ export default function RentalDetailPage() {
|
|||||||
<a href={`sms:${rental.userPhone}`} className="flex-1 py-1.5 bg-blue-500 text-white rounded-lg text-xs text-center hover:bg-blue-600 flex items-center justify-center gap-1">
|
<a href={`sms:${rental.userPhone}`} className="flex-1 py-1.5 bg-blue-500 text-white rounded-lg text-xs text-center hover:bg-blue-600 flex items-center justify-center gap-1">
|
||||||
<MessageCircle className="w-3 h-3" /> SMS
|
<MessageCircle className="w-3 h-3" /> SMS
|
||||||
</a>
|
</a>
|
||||||
|
<button onClick={() => setShowSmsModal(true)} className="flex-1 py-1.5 bg-indigo-500 text-white rounded-lg text-xs text-center hover:bg-indigo-600 flex items-center justify-center gap-1">
|
||||||
|
<MessageSquare className="w-3 h-3" /> In-App SMS
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -783,12 +817,12 @@ export default function RentalDetailPage() {
|
|||||||
<h3 className="font-semibold text-slate-700 flex items-center gap-2">
|
<h3 className="font-semibold text-slate-700 flex items-center gap-2">
|
||||||
<AlertTriangle className="w-5 h-5 text-red-500" /> Damage History
|
<AlertTriangle className="w-5 h-5 text-red-500" /> Damage History
|
||||||
</h3>
|
</h3>
|
||||||
<button className="px-3 py-1.5 bg-red-500 text-white rounded-lg text-sm hover:bg-red-600 flex items-center gap-2">
|
<button onClick={() => setShowDamageModal(true)} className="px-3 py-1.5 bg-red-500 text-white rounded-lg text-sm hover:bg-red-600 flex items-center gap-2">
|
||||||
<Plus className="w-4 h-4" /> Report Damage
|
<Plus className="w-4 h-4" /> Report Damage
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{mockDamageHistory.map(damage => (
|
{damages.map(damage => (
|
||||||
<div key={damage.id} className="p-3 bg-slate-50 rounded-lg flex items-center justify-between">
|
<div key={damage.id} className="p-3 bg-slate-50 rounded-lg flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-slate-700">{damage.description}</p>
|
<p className="text-sm font-medium text-slate-700">{damage.description}</p>
|
||||||
@@ -816,7 +850,7 @@ export default function RentalDetailPage() {
|
|||||||
<h3 className="font-semibold text-slate-700 flex items-center gap-2">
|
<h3 className="font-semibold text-slate-700 flex items-center gap-2">
|
||||||
<FileText className="w-5 h-5 text-blue-500" /> Rental Documents
|
<FileText className="w-5 h-5 text-blue-500" /> Rental Documents
|
||||||
</h3>
|
</h3>
|
||||||
<button className="px-3 py-1.5 bg-blue-500 text-white rounded-lg text-sm hover:bg-blue-600 flex items-center gap-2">
|
<button onClick={() => setShowUploadModal(true)} className="px-3 py-1.5 bg-blue-500 text-white rounded-lg text-sm hover:bg-blue-600 flex items-center gap-2">
|
||||||
<Upload className="w-4 h-4" /> Upload Document
|
<Upload className="w-4 h-4" /> Upload Document
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -830,8 +864,16 @@ export default function RentalDetailPage() {
|
|||||||
<p className="text-xs text-slate-500">{doc.uploadedAt}</p>
|
<p className="text-xs text-slate-500">{doc.uploadedAt}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button className="px-3 py-1.5 text-blue-600 hover:bg-blue-50 rounded-lg text-sm flex items-center gap-1">
|
<button onClick={() => {
|
||||||
<Download className="w-4 h-4" /> View
|
const link = document.createElement('a');
|
||||||
|
link.href = '#';
|
||||||
|
link.download = doc.name;
|
||||||
|
alert(`Downloading: ${doc.name}`);
|
||||||
|
}} className="px-3 py-1.5 text-blue-600 hover:bg-blue-50 rounded-lg text-sm flex items-center gap-1">
|
||||||
|
<Download className="w-4 h-4" /> Download
|
||||||
|
</button>
|
||||||
|
<button onClick={() => alert(`Viewing: ${doc.name}`)} className="px-3 py-1.5 text-slate-600 hover:bg-slate-100 rounded-lg text-sm flex items-center gap-1">
|
||||||
|
<FileText className="w-4 h-4" /> View
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -990,6 +1032,125 @@ export default function RentalDetailPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{showDamageModal && (
|
||||||
|
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||||
|
<div className="bg-white rounded-xl shadow-xl w-full max-w-md">
|
||||||
|
<div className="p-4 border-b border-slate-100 flex justify-between items-center">
|
||||||
|
<h3 className="font-semibold text-slate-800 flex items-center gap-2">
|
||||||
|
<AlertTriangle className="w-5 h-5 text-red-500" /> Report Damage
|
||||||
|
</h3>
|
||||||
|
<button onClick={() => setShowDamageModal(false)} className="text-slate-400 hover:text-slate-600 text-2xl">×</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 space-y-4">
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600 block mb-1">Description</label>
|
||||||
|
<textarea
|
||||||
|
value={damageDesc}
|
||||||
|
onChange={(e) => setDamageDesc(e.target.value)}
|
||||||
|
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
|
||||||
|
rows={3}
|
||||||
|
placeholder="Describe the damage..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600 block mb-1">Severity</label>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
{(['minor', 'moderate', 'severe'] as const).map(sev => (
|
||||||
|
<button
|
||||||
|
key={sev}
|
||||||
|
onClick={() => setDamageSeverity(sev)}
|
||||||
|
className={`flex-1 py-2 rounded-lg text-sm border ${damageSeverity === sev
|
||||||
|
? sev === 'minor' ? 'bg-yellow-100 border-yellow-300 text-yellow-700'
|
||||||
|
: sev === 'moderate' ? 'bg-orange-100 border-orange-300 text-orange-700'
|
||||||
|
: 'bg-red-100 border-red-300 text-red-700'
|
||||||
|
: 'border-slate-200 text-slate-600'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{sev.charAt(0).toUpperCase() + sev.slice(1)}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 border-t border-slate-100 flex justify-end gap-2">
|
||||||
|
<button onClick={() => setShowDamageModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg">Cancel</button>
|
||||||
|
<button onClick={handleReportDamage} disabled={!damageDesc.trim()} className="px-4 py-2 bg-red-600 text-white rounded-lg disabled:opacity-50">Report Damage</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showSmsModal && (
|
||||||
|
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||||
|
<div className="bg-white rounded-xl shadow-xl w-full max-w-md">
|
||||||
|
<div className="p-4 border-b border-slate-100 flex justify-between items-center">
|
||||||
|
<h3 className="font-semibold text-slate-800 flex items-center gap-2">
|
||||||
|
<MessageCircle className="w-5 h-5 text-blue-500" /> Send SMS
|
||||||
|
</h3>
|
||||||
|
<button onClick={() => setShowSmsModal(false)} className="text-slate-400 hover:text-slate-600 text-2xl">×</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 space-y-3">
|
||||||
|
<div className="bg-slate-50 p-3 rounded-lg text-sm">
|
||||||
|
<p className="text-slate-500">To:</p>
|
||||||
|
<p className="font-medium text-slate-800">{rental.userName} ({rental.userPhone})</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600 block mb-1">Message</label>
|
||||||
|
<textarea
|
||||||
|
value={smsText}
|
||||||
|
onChange={(e) => setSmsText(e.target.value)}
|
||||||
|
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
|
||||||
|
rows={4}
|
||||||
|
placeholder="Type your message..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 border-t border-slate-100 flex justify-end gap-2">
|
||||||
|
<button onClick={() => setShowSmsModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg">Cancel</button>
|
||||||
|
<button onClick={handleSendSms} disabled={!smsText.trim()} className="px-4 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50">Send SMS</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showUploadModal && (
|
||||||
|
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||||
|
<div className="bg-white rounded-xl shadow-xl w-full max-w-md">
|
||||||
|
<div className="p-4 border-b border-slate-100 flex justify-between items-center">
|
||||||
|
<h3 className="font-semibold text-slate-800 flex items-center gap-2">
|
||||||
|
<Upload className="w-5 h-5 text-blue-500" /> Upload Document
|
||||||
|
</h3>
|
||||||
|
<button onClick={() => setShowUploadModal(false)} className="text-slate-400 hover:text-slate-600 text-2xl">×</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 space-y-4">
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600 block mb-1">Document Name</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={uploadDocName}
|
||||||
|
onChange={(e) => setUploadDocName(e.target.value)}
|
||||||
|
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
|
||||||
|
placeholder="Enter document name..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600 block mb-1">Choose File</label>
|
||||||
|
<div className="border-2 border-dashed border-slate-200 rounded-lg p-6 text-center hover:border-blue-400 cursor-pointer">
|
||||||
|
<Upload className="w-8 h-8 text-slate-300 mx-auto mb-2" />
|
||||||
|
<p className="text-sm text-slate-500">Click to upload or drag and drop</p>
|
||||||
|
<p className="text-xs text-slate-400 mt-1">PDF, PNG, JPG (max 10MB)</p>
|
||||||
|
<input type="file" className="hidden" accept=".pdf,.png,.jpg,.jpeg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 border-t border-slate-100 flex justify-end gap-2">
|
||||||
|
<button onClick={() => setShowUploadModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg">Cancel</button>
|
||||||
|
<button onClick={handleUploadDocument} disabled={!uploadDocName.trim()} className="px-4 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50">Upload</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user