refund confirmation

This commit is contained in:
jackiettran
2025-09-04 18:02:01 -04:00
parent 1b3c8a9691
commit bbab991e31
3 changed files with 154 additions and 64 deletions

View File

@@ -22,6 +22,12 @@ const RentalCancellationModal: React.FC<RentalCancellationModalProps> = ({
const [processing, setProcessing] = useState(false);
const [error, setError] = useState<string | null>(null);
const [reason, setReason] = useState("");
const [success, setSuccess] = useState(false);
const [processedRefund, setProcessedRefund] = useState<{
amount: number;
refundId?: string;
} | null>(null);
const [updatedRental, setUpdatedRental] = useState<Rental | null>(null);
useEffect(() => {
if (show && rental) {
@@ -52,8 +58,19 @@ const RentalCancellationModal: React.FC<RentalCancellationModalProps> = ({
setError(null);
const response = await rentalAPI.cancelRental(rental.id, reason.trim());
onCancellationComplete(response.data.rental);
onHide();
// Store refund details for confirmation screen
setProcessedRefund({
amount: refundPreview.refundAmount,
refundId: response.data.rental.stripeRefundId
});
// Store updated rental data for later callback
setUpdatedRental(response.data.rental);
// Show success confirmation instead of closing immediately
setSuccess(true);
// Don't call onCancellationComplete here - wait until user clicks "Done"
} catch (error: any) {
setError(error.response?.data?.error || "Failed to cancel rental");
} finally {
@@ -61,6 +78,24 @@ const RentalCancellationModal: React.FC<RentalCancellationModalProps> = ({
}
};
const handleClose = () => {
// Call parent callback with updated rental data if we have it
if (updatedRental) {
onCancellationComplete(updatedRental);
}
// Reset all states when closing
setRefundPreview(null);
setLoading(false);
setProcessing(false);
setError(null);
setReason("");
setSuccess(false);
setProcessedRefund(null);
setUpdatedRental(null);
onHide();
};
const formatCurrency = (amount: number | string | undefined) => {
const numAmount = Number(amount) || 0;
return `$${numAmount.toFixed(2)}`;
@@ -75,19 +110,19 @@ const RentalCancellationModal: React.FC<RentalCancellationModalProps> = ({
const handleBackdropClick = useCallback(
(e: React.MouseEvent) => {
if (e.target === e.currentTarget) {
onHide();
handleClose();
}
},
[onHide]
[handleClose]
);
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (e.key === "Escape") {
onHide();
handleClose();
}
},
[onHide]
[handleClose]
);
useEffect(() => {
@@ -116,31 +151,60 @@ const RentalCancellationModal: React.FC<RentalCancellationModalProps> = ({
<div className="modal-dialog modal-lg modal-dialog-centered">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Cancel Rental</h5>
<h5 className="modal-title">
{success ? "Refund Confirmation" : "Cancel Rental"}
</h5>
<button
type="button"
className="btn-close"
onClick={onHide}
onClick={handleClose}
aria-label="Close"
></button>
</div>
<div className="modal-body">
{loading && (
{success && processedRefund ? (
<div className="text-center py-4">
<div className="spinner-border me-2" role="status">
<span className="visually-hidden">Loading...</span>
<div className="mb-4">
<i className="bi bi-check-circle-fill text-success" style={{ fontSize: '4rem' }}></i>
</div>
Calculating refund...
<h3 className="text-success mb-3">Refund Processed Successfully!</h3>
<div className="alert alert-success mb-4">
<h5 className="mb-3">
<strong>{formatCurrency(processedRefund.amount)}</strong> has been refunded
</h5>
<div className="small text-muted">
<p className="mb-2">
<i className="bi bi-clock me-2"></i>
Your refund will appear in your payment method within <strong>3-5 business days</strong>
</p>
<p className="mb-0">
<i className="bi bi-credit-card me-2"></i>
Refund will be processed to your original payment method
</p>
</div>
</div>
<p className="text-muted mb-4">
Thank you for using our platform. We hope you'll rent with us again soon!
</p>
</div>
)}
) : (
<>
{loading && (
<div className="text-center py-4">
<div className="spinner-border me-2" role="status">
<span className="visually-hidden">Loading...</span>
</div>
Calculating refund...
</div>
)}
{error && (
<div className="alert alert-danger mb-3" role="alert">
{error}
</div>
)}
{error && (
<div className="alert alert-danger mb-3" role="alert">
{error}
</div>
)}
{refundPreview && !loading && (
{refundPreview && !loading && (
<>
<div className="mb-4">
<h5>Rental Details</h5>
@@ -206,41 +270,55 @@ const RentalCancellationModal: React.FC<RentalCancellationModalProps> = ({
</form>
</>
)}
</>
)}
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-secondary"
onClick={onHide}
disabled={processing}
>
Keep Rental
</button>
{refundPreview && (
{success ? (
<button
type="button"
className="btn btn-danger"
onClick={handleCancel}
disabled={processing || loading}
className="btn btn-primary btn-lg"
onClick={handleClose}
>
{processing ? (
<>
<div
className="spinner-border spinner-border-sm me-2"
role="status"
>
<span className="visually-hidden">Loading...</span>
</div>
Processing...
</>
) : (
`Cancel with ${
refundPreview.refundAmount > 0
? `Refund ${formatCurrency(refundPreview.refundAmount)}`
: "No Refund"
}`
)}
Done
</button>
) : (
<>
<button
type="button"
className="btn btn-secondary"
onClick={handleClose}
disabled={processing}
>
Keep Rental
</button>
{refundPreview && (
<button
type="button"
className="btn btn-danger"
onClick={handleCancel}
disabled={processing || loading}
>
{processing ? (
<>
<div
className="spinner-border spinner-border-sm me-2"
role="status"
>
<span className="visually-hidden">Loading...</span>
</div>
Processing...
</>
) : (
`Cancel with ${
refundPreview.refundAmount > 0
? `Refund ${formatCurrency(refundPreview.refundAmount)}`
: "No Refund"
}`
)}
</button>
)}
</>
)}
</div>
</div>