getting to payment screen. Bug fixes and formatting changes for item detail

This commit is contained in:
jackiettran
2025-08-21 16:44:05 -04:00
parent b624841350
commit 022c0b9c06
10 changed files with 859 additions and 815 deletions

View File

@@ -0,0 +1,81 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Item } from '../types';
interface ItemCardProps {
item: Item;
variant?: 'compact' | 'standard';
}
const ItemCard: React.FC<ItemCardProps> = ({
item,
variant = 'standard'
}) => {
const isCompact = variant === 'compact';
const getPriceDisplay = () => {
if (item.pricePerDay !== undefined) {
return Number(item.pricePerDay) === 0
? "Free to Borrow"
: `$${Math.floor(Number(item.pricePerDay))}/Day`;
} else if (item.pricePerHour !== undefined) {
return Number(item.pricePerHour) === 0
? "Free to Borrow"
: `$${Math.floor(Number(item.pricePerHour))}/Hour`;
}
return null;
};
const getLocationDisplay = () => {
return item.city && item.state
? `${item.city}, ${item.state}`
: item.location;
};
return (
<Link to={`/items/${item.id}`} className="text-decoration-none">
<div className="card h-100" style={{ cursor: 'pointer' }}>
{item.images && item.images[0] ? (
<img
src={item.images[0]}
className="card-img-top"
alt={item.name}
style={{
height: isCompact ? '150px' : '200px',
objectFit: 'cover'
}}
/>
) : (
<div
className="card-img-top bg-light d-flex align-items-center justify-content-center"
style={{ height: isCompact ? '150px' : '200px' }}
>
<i className="bi bi-image text-muted" style={{ fontSize: '2rem' }}></i>
</div>
)}
<div className={`card-body ${isCompact ? 'p-2' : ''}`}>
{isCompact ? (
<h6 className="card-title text-truncate mb-1 text-dark">{item.name}</h6>
) : (
<h5 className="card-title text-dark">{item.name}</h5>
)}
<div className={isCompact ? "mb-1" : "mb-3"}>
<div className="text-primary">
<strong className={isCompact ? "small" : ""}>
{getPriceDisplay()}
</strong>
</div>
</div>
<div className={`text-muted small ${isCompact ? 'mb-1' : 'mb-2'}`}>
<i className="bi bi-geo-alt"></i> {getLocationDisplay()}
</div>
</div>
</div>
</Link>
);
};
export default ItemCard;

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { Rental } from "../types";
import { rentalAPI } from "../services/api";
import { itemAPI } from "../services/api";
interface ItemReviewsProps {
itemId: string;
@@ -17,26 +17,11 @@ const ItemReviews: React.FC<ItemReviewsProps> = ({ itemId }) => {
const fetchReviews = async () => {
try {
// Fetch all rentals for this item
const response = await rentalAPI.getMyListings();
const allRentals: Rental[] = response.data;
// Filter for completed rentals with reviews for this specific item
const itemReviews = allRentals.filter(
(rental) =>
rental.itemId === itemId &&
rental.status === "completed" &&
rental.rating &&
rental.review
);
setReviews(itemReviews);
// Calculate average rating
if (itemReviews.length > 0) {
const sum = itemReviews.reduce((acc, r) => acc + (r.rating || 0), 0);
setAverageRating(sum / itemReviews.length);
}
const response = await itemAPI.getItemReviews(itemId);
const { reviews, averageRating } = response.data;
setReviews(reviews);
setAverageRating(averageRating);
} catch (error) {
console.error("Failed to fetch reviews:", error);
} finally {