fix: price sorting by period type, pagination, avgRating on dashboard
- Sort by monthlyPrice when periodType=MONTHLY instead of always dailyPrice - Fix client-side pagination in MyBookingsPage and LandlordListingsPage - Compute avgRating in /rentals/mine endpoint so dashboard shows ratings - Fix falsy filter for avgRating=0 on landlord dashboard Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,7 +17,6 @@ const STATUS_TABS: (BookingStatus | 'ALL')[] = ['ALL', 'PENDING', 'CONFIRMED', '
|
||||
export function MyBookingsPage() {
|
||||
const navigate = useNavigate();
|
||||
const [bookings, setBookings] = useState<Booking[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [page, setPage] = useState(1);
|
||||
const [tab, setTab] = useState<BookingStatus | 'ALL'>('ALL');
|
||||
const [, setLoading] = useState(true);
|
||||
@@ -37,7 +36,6 @@ export function MyBookingsPage() {
|
||||
try {
|
||||
const res = await api.get<Booking[]>(`/bookings?${params}`);
|
||||
setBookings(res);
|
||||
setTotal(res.length);
|
||||
} catch {
|
||||
setBookings([]);
|
||||
} finally {
|
||||
@@ -170,8 +168,8 @@ export function MyBookingsPage() {
|
||||
render: (b: Booking) => <BookingStatusBadge status={b.status} />,
|
||||
},
|
||||
]}
|
||||
data={bookings}
|
||||
total={total}
|
||||
data={bookings.slice((page - 1) * 20, page * 20)}
|
||||
total={bookings.length}
|
||||
page={page}
|
||||
pageSize={20}
|
||||
onPageChange={setPage}
|
||||
|
||||
@@ -38,7 +38,7 @@ export function LandlordDashboardPage() {
|
||||
.filter((b) => b.status === 'COMPLETED')
|
||||
.reduce((sum, b) => sum + b.totalAmount, 0);
|
||||
|
||||
const ratings = rentalsRes.filter((r) => r.avgRating).map((r) => r.avgRating!);
|
||||
const ratings = rentalsRes.filter((r) => r.avgRating !== undefined && r.avgRating !== null).map((r) => r.avgRating!);
|
||||
const avgRating = ratings.length > 0 ? ratings.reduce((a, b) => a + b, 0) / ratings.length : 0;
|
||||
|
||||
setStats({ totalRentals, activeBookings, revenue, avgRating });
|
||||
|
||||
@@ -9,7 +9,6 @@ import type { RentalListing } from '../../types/rental';
|
||||
|
||||
export function LandlordListingsPage() {
|
||||
const [listings, setListings] = useState<RentalListing[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [page, setPage] = useState(1);
|
||||
const [search, setSearch] = useState('');
|
||||
|
||||
@@ -19,7 +18,6 @@ export function LandlordListingsPage() {
|
||||
if (search) params.set('search', search);
|
||||
const res = await api.get<RentalListing[]>(`/rentals/mine?${params}`);
|
||||
setListings(res);
|
||||
setTotal(res.length);
|
||||
} catch {
|
||||
// silently fail
|
||||
}
|
||||
@@ -143,8 +141,8 @@ export function LandlordListingsPage() {
|
||||
render: (l: RentalListing) => l._count?.bookings ?? 0,
|
||||
},
|
||||
]}
|
||||
data={listings}
|
||||
total={total}
|
||||
data={listings.slice((page - 1) * 20, page * 20)}
|
||||
total={listings.length}
|
||||
page={page}
|
||||
pageSize={20}
|
||||
onPageChange={setPage}
|
||||
|
||||
@@ -37,10 +37,16 @@ router.get('/mine', authenticate, async (req, res, next) => {
|
||||
|
||||
const listings = await prisma.rentalListing.findMany({
|
||||
where,
|
||||
select: rentalSelect,
|
||||
select: { ...rentalSelect, reviews: { select: { rating: true } } },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
res.json(listings);
|
||||
const withRatings = listings.map(l => ({
|
||||
...l,
|
||||
avgRating: l.reviews.length > 0
|
||||
? l.reviews.reduce((sum, r) => sum + r.rating, 0) / l.reviews.length
|
||||
: undefined,
|
||||
}));
|
||||
res.json(withRatings);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
@@ -111,8 +117,9 @@ router.get('/', optionalAuth, async (req, res, next) => {
|
||||
where.dailyPrice = priceFilter;
|
||||
}
|
||||
|
||||
const orderBy = sort === 'price_asc' ? { dailyPrice: 'asc' as const }
|
||||
: sort === 'price_desc' ? { dailyPrice: 'desc' as const }
|
||||
const priceField = periodType === 'MONTHLY' ? 'monthlyPrice' : 'dailyPrice';
|
||||
const orderBy = sort === 'price_asc' ? { [priceField]: 'asc' as const }
|
||||
: sort === 'price_desc' ? { [priceField]: 'desc' as const }
|
||||
: sort === 'popular' ? { viewCount: 'desc' as const }
|
||||
: { createdAt: 'desc' as const };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user