condition checks in rental history in profile

This commit is contained in:
jackiettran
2025-12-16 14:15:07 -05:00
parent 27a7b641dd
commit 38e0b6a16d
2 changed files with 130 additions and 12 deletions

View File

@@ -9,10 +9,10 @@ interface ConditionCheckViewerModalProps {
}
const checkTypeLabels: Record<string, string> = {
pre_rental_owner: "Pre-Rental Check (Owner)",
rental_start_renter: "Rental Start Check (Renter)",
rental_end_renter: "Rental End Check (Renter)",
post_rental_owner: "Post-Rental Check (Owner)",
pre_rental_owner: "Pre-Rental Condition (Owner)",
rental_start_renter: "Rental Start Condition (Renter)",
rental_end_renter: "Rental End Condition (Renter)",
post_rental_owner: "Post-Rental Condition (Owner)",
};
const ConditionCheckViewerModal: React.FC<ConditionCheckViewerModalProps> = ({
@@ -65,10 +65,13 @@ const ConditionCheckViewerModal: React.FC<ConditionCheckViewerModalProps> = ({
? `${conditionCheck.submittedByUser.firstName} ${conditionCheck.submittedByUser.lastName}`
: "Unknown";
const submittedDate = new Date(conditionCheck.submittedAt).toLocaleString(undefined, {
dateStyle: "short",
timeStyle: "short",
});
const submittedDate = new Date(conditionCheck.submittedAt).toLocaleString(
undefined,
{
dateStyle: "short",
timeStyle: "short",
}
);
// Filter to only valid string keys for display
const validImageKeys = (conditionCheck.imageFilenames || []).filter(
@@ -76,7 +79,9 @@ const ConditionCheckViewerModal: React.FC<ConditionCheckViewerModalProps> = ({
);
const currentImageKey = validImageKeys[selectedImage];
const currentImageUrl = currentImageKey ? imageUrls.get(currentImageKey) : undefined;
const currentImageUrl = currentImageKey
? imageUrls.get(currentImageKey)
: undefined;
return (
<div
@@ -219,7 +224,11 @@ const ConditionCheckViewerModal: React.FC<ConditionCheckViewerModalProps> = ({
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={onHide}>
<button
type="button"
className="btn btn-secondary"
onClick={onHide}
>
Close
</button>
</div>

View File

@@ -1,13 +1,14 @@
import React, { useState, useEffect, useCallback } from "react";
import { useNavigate } from "react-router-dom";
import { useAuth } from "../contexts/AuthContext";
import { userAPI, itemAPI, rentalAPI, addressAPI } from "../services/api";
import { User, Item, Rental, Address } from "../types";
import { userAPI, itemAPI, rentalAPI, addressAPI, conditionCheckAPI } from "../services/api";
import { User, Item, Rental, Address, ConditionCheck } from "../types";
import { uploadFile, getPublicImageUrl } from "../services/uploadService";
import AvailabilitySettings from "../components/AvailabilitySettings";
import ReviewItemModal from "../components/ReviewModal";
import ReviewRenterModal from "../components/ReviewRenterModal";
import ReviewDetailsModal from "../components/ReviewDetailsModal";
import ConditionCheckViewerModal from "../components/ConditionCheckViewerModal";
import Avatar from "../components/Avatar";
import {
geocodingService,
@@ -114,6 +115,11 @@ const Profile: React.FC = () => {
"renter" | "owner"
>("renter");
// Condition check state
const [conditionChecks, setConditionChecks] = useState<ConditionCheck[]>([]);
const [showConditionCheckViewer, setShowConditionCheckViewer] = useState(false);
const [selectedConditionCheck, setSelectedConditionCheck] = useState<ConditionCheck | null>(null);
useEffect(() => {
fetchProfile();
fetchStats();
@@ -239,6 +245,63 @@ const Profile: React.FC = () => {
}
};
const fetchConditionChecks = async (renterRentals: Rental[], ownerRentals: Rental[]) => {
try {
const allRentals = [...renterRentals, ...ownerRentals];
// Remove duplicates (a rental could appear in both if user is both renter and owner somehow)
const uniqueRentals = allRentals.filter(
(rental, index, self) => self.findIndex((r) => r.id === rental.id) === index
);
const allChecks: ConditionCheck[] = [];
for (const rental of uniqueRentals) {
try {
const response = await conditionCheckAPI.getConditionChecks(rental.id);
if (response.data.conditionChecks) {
allChecks.push(...response.data.conditionChecks);
}
} catch (err) {
// Skip rentals with no condition checks
}
}
setConditionChecks(allChecks);
} catch (err) {
console.error("Failed to fetch condition checks:", err);
setConditionChecks([]);
}
};
// Fetch condition checks when rental history is loaded
useEffect(() => {
if (pastRenterRentals.length > 0 || pastOwnerRentals.length > 0) {
fetchConditionChecks(pastRenterRentals, pastOwnerRentals);
}
}, [pastRenterRentals, pastOwnerRentals]);
const getCompletedChecksForRental = (rentalId: string): ConditionCheck[] => {
return conditionChecks.filter((check) => check.rentalId === rentalId);
};
const handleViewConditionCheck = (check: ConditionCheck) => {
setSelectedConditionCheck(check);
setShowConditionCheckViewer(true);
};
const getConditionCheckLabel = (checkType: string): string => {
switch (checkType) {
case "pre_rental_owner":
return "Pre-Rental Condition";
case "rental_start_renter":
return "Rental Start Condition";
case "rental_end_renter":
return "Rental End Condition";
case "post_rental_owner":
return "Post-Rental Condition";
default:
return "Condition Check";
}
};
const handleReviewClick = (rental: Rental) => {
setSelectedRental(rental);
setShowReviewModal(true);
@@ -1274,6 +1337,24 @@ const Profile: React.FC = () => {
</div>
)}
{/* Condition Checks */}
{getCompletedChecksForRental(rental.id).length > 0 && (
<div className="mb-2">
{getCompletedChecksForRental(rental.id).map((check) => (
<button
key={`${rental.id}-${check.checkType}`}
className="btn btn-link text-success small p-0 text-decoration-none d-block"
onClick={() => handleViewConditionCheck(check)}
>
{getConditionCheckLabel(check.checkType)}
<small className="text-muted ms-2">
{new Date(check.createdAt).toLocaleDateString()}
</small>
</button>
))}
</div>
)}
<div className="d-flex gap-2 mt-3">
{rental.status === "completed" &&
!rental.itemRating &&
@@ -1400,6 +1481,24 @@ const Profile: React.FC = () => {
<strong>Total:</strong> ${rental.totalAmount}
</p>
{/* Condition Checks */}
{getCompletedChecksForRental(rental.id).length > 0 && (
<div className="mb-2">
{getCompletedChecksForRental(rental.id).map((check) => (
<button
key={`${rental.id}-${check.checkType}`}
className="btn btn-link text-success small p-0 text-decoration-none d-block"
onClick={() => handleViewConditionCheck(check)}
>
{getConditionCheckLabel(check.checkType)}
<small className="text-muted ms-2">
{new Date(check.createdAt).toLocaleDateString()}
</small>
</button>
))}
</div>
)}
<div className="d-flex gap-2 mt-3">
{rental.status === "completed" &&
!rental.renterRating &&
@@ -1615,6 +1714,16 @@ const Profile: React.FC = () => {
userType={reviewDetailsUserType}
/>
)}
{/* Condition Check Viewer Modal */}
<ConditionCheckViewerModal
show={showConditionCheckViewer}
onHide={() => {
setShowConditionCheckViewer(false);
setSelectedConditionCheck(null);
}}
conditionCheck={selectedConditionCheck}
/>
</div>
);
};