condition checks in rental history in profile
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user