Files
rentall-app/frontend/src/components/ReviewRenterModal.tsx
2025-08-25 16:12:30 -04:00

225 lines
7.1 KiB
TypeScript

import React, { useState } from "react";
import { rentalAPI } from "../services/api";
import { Rental } from "../types";
import SuccessModal from "./SuccessModal";
interface ReviewRenterModalProps {
show: boolean;
onClose: () => void;
rental: Rental;
onSuccess: () => void;
}
const ReviewRenterModal: React.FC<ReviewRenterModalProps> = ({
show,
onClose,
rental,
onSuccess,
}) => {
const [rating, setRating] = useState(5);
const [review, setReview] = useState("");
const [privateMessage, setPrivateMessage] = useState("");
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null);
const [showSuccessModal, setShowSuccessModal] = useState(false);
const [successMessage, setSuccessMessage] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
setSubmitting(true);
try {
const response = await rentalAPI.reviewRenter(rental.id, {
rating,
review,
privateMessage,
});
// Reset form
setRating(5);
setReview("");
setPrivateMessage("");
// Show success modal with appropriate message
if (response.data.reviewVisible) {
setSuccessMessage("Review published successfully!");
} else {
setSuccessMessage("Review submitted! It will be published when both parties have reviewed or after 10 minutes.");
}
setShowSuccessModal(true);
} catch (err: any) {
setError(err.response?.data?.error || "Failed to submit review");
} finally {
setSubmitting(false);
}
};
const handleStarClick = (value: number) => {
setRating(value);
};
const handleSuccessModalClose = () => {
setShowSuccessModal(false);
onSuccess();
onClose();
};
if (!show) return null;
return (
<div
className="modal d-block"
tabIndex={-1}
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Review Renter</h5>
<button
type="button"
className="btn-close"
onClick={onClose}
></button>
</div>
<form onSubmit={handleSubmit}>
<div className="modal-body">
{rental.renter && rental.item && (
<div className="mb-4 text-center">
<div className="d-flex justify-content-center mb-3">
{rental.renter.profileImage ? (
<img
src={rental.renter.profileImage}
alt={`${rental.renter.firstName} ${rental.renter.lastName}`}
className="rounded-circle"
style={{
width: "60px",
height: "60px",
objectFit: "cover",
}}
/>
) : (
<div
className="rounded-circle bg-primary d-flex align-items-center justify-content-center text-white fw-bold"
style={{ width: "60px", height: "60px" }}
>
{rental.renter.firstName[0]}
{rental.renter.lastName[0]}
</div>
)}
</div>
<h6 className="mb-1">
{rental.renter.firstName} {rental.renter.lastName}
</h6>
<p className="mb-1 text-muted small">{rental.item.name}</p>
<small className="text-muted">
{new Date(rental.startDate).toLocaleDateString()} to{" "}
{new Date(rental.endDate).toLocaleDateString()}
</small>
</div>
)}
{error && (
<div className="alert alert-danger" role="alert">
{error}
</div>
)}
<div className="mb-3">
<div
className="d-flex justify-content-center gap-1"
style={{ fontSize: "2rem" }}
>
{[1, 2, 3, 4, 5].map((star) => (
<button
key={star}
type="button"
className="btn btn-link p-0 text-decoration-none"
onClick={() => handleStarClick(star)}
style={{ color: star <= rating ? "#ffc107" : "#dee2e6" }}
>
<i
className={`bi ${
star <= rating ? "bi-star-fill" : "bi-star"
}`}
></i>
</button>
))}
</div>
</div>
<div className="mb-3">
<label htmlFor="privateMessage" className="form-label">
Private Message to Renter{" "}
</label>
<textarea
className="form-control"
id="privateMessage"
rows={3}
value={privateMessage}
onChange={(e) => setPrivateMessage(e.target.value)}
placeholder=""
disabled={submitting}
></textarea>
</div>
<div className="mb-3">
<label htmlFor="review" className="form-label">
Public Review
</label>
<textarea
className="form-control"
id="review"
rows={4}
value={review}
onChange={(e) => setReview(e.target.value)}
placeholder=""
disabled={submitting}
></textarea>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-secondary"
onClick={onClose}
disabled={submitting}
>
Cancel
</button>
<button
type="submit"
className="btn btn-primary"
disabled={submitting || !review.trim()}
>
{submitting ? (
<>
<span
className="spinner-border spinner-border-sm me-2"
role="status"
aria-hidden="true"
></span>
Submitting...
</>
) : (
"Submit Review"
)}
</button>
</div>
</form>
</div>
</div>
<SuccessModal
show={showSuccessModal}
onClose={handleSuccessModalClose}
title="Thank you for your review!"
message={successMessage}
/>
</div>
);
};
export default ReviewRenterModal;