create review and profile

This commit is contained in:
arifal
2026-04-20 00:25:05 +07:00
parent 7159e9108f
commit ba5f64ae0e
37 changed files with 3324 additions and 109 deletions
+88 -22
View File
@@ -1,5 +1,11 @@
import { prisma } from "@/lib/prisma";
import { Prisma } from "@/app/generated/prisma/client";
import {
utcStartOfDay,
utcDayStartFromYmd,
utcDayEndFromYmd,
maxUtcDate,
} from "@/lib/trip-dates";
export const tripRepo = {
async findAll() {
@@ -7,44 +13,76 @@ export const tripRepo = {
include: {
organizer: { select: { id: true, name: true, image: true } },
images: { orderBy: { order: "asc" }, take: 1 },
_count: { select: { participants: true } },
_count: {
select: {
participants: { where: { status: { not: "CANCELLED" } } },
},
},
},
orderBy: { date: "asc" },
});
},
async findOpen(filters?: { q?: string; from?: string; to?: string }) {
const where: Prisma.TripWhereInput = {
status: "OPEN",
date: { gte: new Date() },
};
const todayStart = utcStartOfDay(new Date());
const andParts: Prisma.TripWhereInput[] = [{ status: "OPEN" }];
if (!filters?.from && !filters?.to) {
andParts.push({ date: { gte: todayStart } });
} else {
const userRangeStart = filters.from
? utcDayStartFromYmd(filters.from)
: todayStart;
const userRangeEnd = filters.to
? utcDayEndFromYmd(filters.to)
: utcDayEndFromYmd("2099-12-31");
const rangeStart = maxUtcDate(todayStart, userRangeStart);
const rangeEnd = userRangeEnd;
andParts.push({
OR: [
{
AND: [
{ endDate: { not: null } },
{ date: { lte: rangeEnd } },
{ endDate: { gte: rangeStart } },
],
},
{
AND: [
{ endDate: null },
{ date: { gte: rangeStart } },
{ date: { lte: rangeEnd } },
],
},
],
});
}
if (filters?.q) {
where.OR = [
{ title: { contains: filters.q, mode: "insensitive" } },
{ mountain: { contains: filters.q, mode: "insensitive" } },
{ location: { contains: filters.q, mode: "insensitive" } },
];
andParts.push({
OR: [
{ title: { contains: filters.q, mode: "insensitive" } },
{ mountain: { contains: filters.q, mode: "insensitive" } },
{ location: { contains: filters.q, mode: "insensitive" } },
],
});
}
if (filters?.from || filters?.to) {
const dateFilter: Prisma.DateTimeFilter = { gte: new Date() };
if (filters.from) {
const fromDate = new Date(filters.from);
if (fromDate > new Date()) dateFilter.gte = fromDate;
}
if (filters.to) {
dateFilter.lte = new Date(filters.to + "T23:59:59.999Z");
}
where.date = dateFilter;
}
const where: Prisma.TripWhereInput = { AND: andParts };
return prisma.trip.findMany({
where,
include: {
organizer: { select: { id: true, name: true, image: true } },
images: { orderBy: { order: "asc" }, take: 1 },
_count: { select: { participants: true } },
_count: {
select: {
participants: { where: { status: { not: "CANCELLED" } } },
},
},
},
orderBy: { date: "asc" },
});
@@ -59,10 +97,38 @@ export const tripRepo = {
participants: {
include: { user: { select: { id: true, name: true, image: true } } },
},
reviews: {
orderBy: { createdAt: "desc" },
include: {
user: { select: { id: true, name: true, image: true } },
},
},
},
});
},
async countByOrganizerSince(organizerId: string, since: Date) {
return prisma.trip.count({
where: { organizerId, createdAt: { gte: since } },
});
},
/** Semua trip yang dibuat user (semua status), terbaru dulu — untuk profil. */
async findByOrganizerId(organizerId: string) {
return prisma.trip.findMany({
where: { organizerId },
include: {
images: { orderBy: { order: "asc" }, take: 1 },
_count: {
select: {
participants: { where: { status: { not: "CANCELLED" } } },
},
},
},
orderBy: { date: "desc" },
});
},
async create(data: Prisma.TripCreateInput) {
return prisma.trip.create({ data });
},