Add authentication #17
1 changed files with 37 additions and 51 deletions
|
@ -974,7 +974,7 @@ export default function ReimbursementManagementPortal() {
|
||||||
<div className="flex flex-wrap gap-2 w-full sm:w-auto">
|
<div className="flex flex-wrap gap-2 w-full sm:w-auto">
|
||||||
{selectedReimbursement.status === 'submitted' && (
|
{selectedReimbursement.status === 'submitted' && (
|
||||||
<button
|
<button
|
||||||
className="btn btn-info btn-sm sm:btn-md gap-2 flex-1 sm:flex-initial"
|
className="btn btn-sm btn-info gap-2 flex-1 sm:flex-initial"
|
||||||
onClick={() => updateStatus(selectedReimbursement.id, 'under_review')}
|
onClick={() => updateStatus(selectedReimbursement.id, 'under_review')}
|
||||||
disabled={loadingStatus}
|
disabled={loadingStatus}
|
||||||
>
|
>
|
||||||
|
@ -987,38 +987,23 @@ export default function ReimbursementManagementPortal() {
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{selectedReimbursement.status === 'under_review' && (
|
{selectedReimbursement.status === 'under_review' && (
|
||||||
<>
|
<button
|
||||||
<button
|
className="btn btn-sm btn-success gap-2 flex-1 sm:flex-initial px-6"
|
||||||
className="btn btn-success btn-sm sm:btn-md gap-2 flex-1 sm:flex-initial px-6"
|
onClick={() => updateStatus(selectedReimbursement.id, 'approved')}
|
||||||
onClick={() => updateStatus(selectedReimbursement.id, 'approved')}
|
disabled={loadingStatus || !canApproveOrReject(selectedReimbursement)}
|
||||||
disabled={loadingStatus || !canApproveOrReject(selectedReimbursement)}
|
title={!canApproveOrReject(selectedReimbursement) ? 'All receipts must be audited first' : ''}
|
||||||
title={!canApproveOrReject(selectedReimbursement) ? 'All receipts must be audited first' : ''}
|
>
|
||||||
>
|
{loadingStatus ? (
|
||||||
{loadingStatus ? (
|
<span className="loading loading-spinner loading-sm" />
|
||||||
<span className="loading loading-spinner loading-sm" />
|
) : (
|
||||||
) : (
|
<Icon icon="heroicons:check" className="h-4 w-4 flex-shrink-0" />
|
||||||
<Icon icon="heroicons:check" className="h-4 w-4 flex-shrink-0" />
|
)}
|
||||||
)}
|
<span className="font-medium">Approve</span>
|
||||||
<span className="font-medium">Approve</span>
|
</button>
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="btn btn-error btn-sm gap-2 flex-1 sm:flex-initial px-6"
|
|
||||||
onClick={() => handleReject(selectedReimbursement.id)}
|
|
||||||
disabled={loadingStatus || !canApproveOrReject(selectedReimbursement)}
|
|
||||||
title={!canApproveOrReject(selectedReimbursement) ? 'All receipts must be audited first' : ''}
|
|
||||||
>
|
|
||||||
{loadingStatus ? (
|
|
||||||
<span className="loading loading-spinner loading-sm" />
|
|
||||||
) : (
|
|
||||||
<Icon icon="heroicons:x-mark" className="h-4 w-4 flex-shrink-0" />
|
|
||||||
)}
|
|
||||||
<span className="font-medium">Reject</span>
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
{selectedReimbursement.status === 'approved' && (
|
{selectedReimbursement.status === 'approved' && (
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary btn-sm gap-2 flex-1 sm:flex-initial px-6"
|
className="btn btn-sm btn-primary gap-2 flex-1 sm:flex-initial px-6"
|
||||||
onClick={() => updateStatus(selectedReimbursement.id, 'in_progress')}
|
onClick={() => updateStatus(selectedReimbursement.id, 'in_progress')}
|
||||||
disabled={loadingStatus}
|
disabled={loadingStatus}
|
||||||
>
|
>
|
||||||
|
@ -1032,7 +1017,7 @@ export default function ReimbursementManagementPortal() {
|
||||||
)}
|
)}
|
||||||
{selectedReimbursement.status === 'in_progress' && (
|
{selectedReimbursement.status === 'in_progress' && (
|
||||||
<button
|
<button
|
||||||
className="btn btn-success btn-sm gap-2 flex-1 sm:flex-initial px-6"
|
className="btn btn-sm btn-success gap-2 flex-1 sm:flex-initial px-6"
|
||||||
onClick={() => updateStatus(selectedReimbursement.id, 'paid')}
|
onClick={() => updateStatus(selectedReimbursement.id, 'paid')}
|
||||||
disabled={loadingStatus}
|
disabled={loadingStatus}
|
||||||
>
|
>
|
||||||
|
@ -1044,6 +1029,20 @@ export default function ReimbursementManagementPortal() {
|
||||||
<span className="font-medium">Mark as Paid</span>
|
<span className="font-medium">Mark as Paid</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
{selectedReimbursement.status !== 'rejected' && selectedReimbursement.status !== 'paid' && (
|
||||||
|
<button
|
||||||
|
className="btn btn-sm btn-error gap-2 flex-1 sm:flex-initial px-6"
|
||||||
|
onClick={() => handleReject(selectedReimbursement.id)}
|
||||||
|
disabled={loadingStatus}
|
||||||
|
>
|
||||||
|
{loadingStatus ? (
|
||||||
|
<span className="loading loading-spinner loading-sm" />
|
||||||
|
) : (
|
||||||
|
<Icon icon="heroicons:x-mark" className="h-4 w-4 flex-shrink-0" />
|
||||||
|
)}
|
||||||
|
<span className="font-medium">Reject</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
className="btn btn-ghost btn-sm hover:bg-base-200"
|
className="btn btn-ghost btn-sm hover:bg-base-200"
|
||||||
onClick={() => setSelectedReimbursement(null)}
|
onClick={() => setSelectedReimbursement(null)}
|
||||||
|
@ -1653,8 +1652,11 @@ export default function ReimbursementManagementPortal() {
|
||||||
className="modal-box relative max-w-4xl w-full bg-base-100 p-0 overflow-hidden"
|
className="modal-box relative max-w-4xl w-full bg-base-100 p-0 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div className="sticky top-0 flex items-center justify-between p-4 bg-base-100 border-b border-base-300 z-10">
|
<div className="sticky top-0 flex items-center justify-between p-4 bg-base-100 border-b border-base-300 z-10">
|
||||||
<h3 className="font-bold text-lg">
|
<h3 className="font-bold text-lg pl-2">
|
||||||
|
File Preview
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className="btn btn-sm btn-ghost"
|
className="btn btn-sm btn-ghost"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -1662,34 +1664,18 @@ export default function ReimbursementManagementPortal() {
|
||||||
setSelectedReceipt(null);
|
setSelectedReceipt(null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
||||||
<Icon icon="heroicons:x-mark" className="h-5 w-5" />
|
<Icon icon="heroicons:x-mark" className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<div className="px-4 py-0">
|
||||||
<FilePreview
|
<FilePreview
|
||||||
url={getReceiptUrl(selectedReceipt)}
|
url={getReceiptUrl(selectedReceipt)}
|
||||||
filename={`Receipt from ${selectedReceipt.location_name}`}
|
filename={`Receipt from ${selectedReceipt.location_name}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="sticky bottom-0 flex justify-end gap-2 p-4 bg-base-100 border-t border-base-300">
|
<div className="sticky bottom-0 flex justify-end gap-2 p-4 bg-base-100 border-t border-base-300">
|
||||||
<a
|
|
||||||
href={getReceiptUrl(selectedReceipt)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="btn btn-ghost gap-2"
|
|
||||||
>
|
|
||||||
<Icon icon="heroicons:arrow-top-right-on-square" className="h-4 w-4" />
|
|
||||||
Open in new tab
|
|
||||||
</a>
|
|
||||||
<button
|
|
||||||
className="btn btn-primary gap-2"
|
|
||||||
onClick={() => {
|
|
||||||
setShowReceiptModal(false);
|
|
||||||
setSelectedReceipt(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Close
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue