140 lines
3.8 KiB
TypeScript
140 lines
3.8 KiB
TypeScript
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() {
|
|
return prisma.trip.findMany({
|
|
include: {
|
|
organizer: { select: { id: true, name: true, image: true } },
|
|
images: { orderBy: { order: "asc" }, take: 1 },
|
|
_count: {
|
|
select: {
|
|
participants: { where: { status: { not: "CANCELLED" } } },
|
|
},
|
|
},
|
|
},
|
|
orderBy: { date: "asc" },
|
|
});
|
|
},
|
|
|
|
async findOpen(filters?: { q?: string; from?: string; to?: string }) {
|
|
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) {
|
|
andParts.push({
|
|
OR: [
|
|
{ title: { contains: filters.q, mode: "insensitive" } },
|
|
{ mountain: { contains: filters.q, mode: "insensitive" } },
|
|
{ location: { contains: filters.q, mode: "insensitive" } },
|
|
],
|
|
});
|
|
}
|
|
|
|
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: { where: { status: { not: "CANCELLED" } } },
|
|
},
|
|
},
|
|
},
|
|
orderBy: { date: "asc" },
|
|
});
|
|
},
|
|
|
|
async findById(id: string) {
|
|
return prisma.trip.findUnique({
|
|
where: { id },
|
|
include: {
|
|
organizer: { select: { id: true, name: true, email: true, image: true } },
|
|
images: { orderBy: { order: "asc" } },
|
|
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 });
|
|
},
|
|
|
|
async updateStatus(id: string, status: "OPEN" | "FULL" | "CLOSED" | "COMPLETED") {
|
|
return prisma.trip.update({ where: { id }, data: { status } });
|
|
},
|
|
};
|