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:
delta-lynx-89e8
2026-02-22 17:03:23 -08:00
parent dcd2dcb841
commit dc07f2a98d
4 changed files with 16 additions and 13 deletions

View File

@@ -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}

View File

@@ -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 });

View File

@@ -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}

View File

@@ -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 };