feat(admin): Sprint 3 — Réservations, Utilisateurs, Avis
This commit is contained in:
parent
8f31047b36
commit
d9ee072744
16 changed files with 1632 additions and 0 deletions
100
src/lib/admin/bookings.ts
Normal file
100
src/lib/admin/bookings.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import "server-only";
|
||||
|
||||
import { Prisma } from "@/generated/prisma/client";
|
||||
import { BookingStatus, PaymentStatus } from "@/generated/prisma/enums";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export type AdminBookingFilters = {
|
||||
q?: string;
|
||||
status?: BookingStatus;
|
||||
paymentStatus?: PaymentStatus;
|
||||
carbetId?: string;
|
||||
tenantId?: string;
|
||||
from?: Date;
|
||||
to?: Date;
|
||||
};
|
||||
|
||||
export type AdminBookingListItem = {
|
||||
id: string;
|
||||
startDate: Date;
|
||||
endDate: Date;
|
||||
guestCount: number;
|
||||
status: BookingStatus;
|
||||
paymentStatus: PaymentStatus;
|
||||
amount: string;
|
||||
currency: string;
|
||||
createdAt: Date;
|
||||
carbet: { id: string; title: string; slug: string };
|
||||
tenant: { id: string; firstName: string; lastName: string; email: string };
|
||||
};
|
||||
|
||||
export async function listBookingsAdmin(
|
||||
filters: AdminBookingFilters = {},
|
||||
): Promise<AdminBookingListItem[]> {
|
||||
const where: Prisma.BookingWhereInput = {};
|
||||
|
||||
if (filters.q) {
|
||||
where.OR = [
|
||||
{ id: { contains: filters.q, mode: "insensitive" } },
|
||||
{ tenant: { email: { contains: filters.q, mode: "insensitive" } } },
|
||||
{ tenant: { firstName: { contains: filters.q, mode: "insensitive" } } },
|
||||
{ tenant: { lastName: { contains: filters.q, mode: "insensitive" } } },
|
||||
{ carbet: { title: { contains: filters.q, mode: "insensitive" } } },
|
||||
{ carbet: { slug: { contains: filters.q, mode: "insensitive" } } },
|
||||
];
|
||||
}
|
||||
if (filters.status) where.status = filters.status;
|
||||
if (filters.paymentStatus) where.paymentStatus = filters.paymentStatus;
|
||||
if (filters.carbetId) where.carbetId = filters.carbetId;
|
||||
if (filters.tenantId) where.tenantId = filters.tenantId;
|
||||
if (filters.from || filters.to) {
|
||||
where.startDate = {};
|
||||
if (filters.from) where.startDate.gte = filters.from;
|
||||
if (filters.to) where.startDate.lte = filters.to;
|
||||
}
|
||||
|
||||
const rows = await prisma.booking.findMany({
|
||||
where,
|
||||
orderBy: [{ createdAt: "desc" }],
|
||||
take: 200,
|
||||
select: {
|
||||
id: true,
|
||||
startDate: true,
|
||||
endDate: true,
|
||||
guestCount: true,
|
||||
status: true,
|
||||
paymentStatus: true,
|
||||
amount: true,
|
||||
currency: true,
|
||||
createdAt: true,
|
||||
carbet: { select: { id: true, title: true, slug: true } },
|
||||
tenant: { select: { id: true, firstName: true, lastName: true, email: true } },
|
||||
},
|
||||
});
|
||||
|
||||
return rows.map((r) => ({
|
||||
...r,
|
||||
amount: r.amount.toString(),
|
||||
}));
|
||||
}
|
||||
|
||||
export async function getBookingForAdmin(id: string) {
|
||||
return prisma.booking.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
carbet: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
slug: true,
|
||||
river: true,
|
||||
owner: { select: { id: true, firstName: true, lastName: true, email: true } },
|
||||
},
|
||||
},
|
||||
tenant: {
|
||||
select: { id: true, firstName: true, lastName: true, email: true, phone: true, role: true },
|
||||
},
|
||||
review: { select: { id: true, rating: true, createdAt: true } },
|
||||
},
|
||||
});
|
||||
}
|
||||
69
src/lib/admin/reviews.ts
Normal file
69
src/lib/admin/reviews.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import "server-only";
|
||||
|
||||
import { Prisma } from "@/generated/prisma/client";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export type AdminReviewFilters = {
|
||||
q?: string;
|
||||
carbetId?: string;
|
||||
rating?: number;
|
||||
withResponse?: "yes" | "no";
|
||||
};
|
||||
|
||||
export type AdminReviewListItem = {
|
||||
id: string;
|
||||
rating: number;
|
||||
comment: string | null;
|
||||
hostResponse: string | null;
|
||||
hostRespondedAt: Date | null;
|
||||
createdAt: Date;
|
||||
carbet: { id: string; title: string; slug: string };
|
||||
author: { id: string; firstName: string; lastName: string; email: string };
|
||||
booking: { id: string };
|
||||
};
|
||||
|
||||
export async function listReviewsAdmin(filters: AdminReviewFilters = {}): Promise<AdminReviewListItem[]> {
|
||||
const where: Prisma.ReviewWhereInput = {};
|
||||
if (filters.q) {
|
||||
where.OR = [
|
||||
{ id: { contains: filters.q, mode: "insensitive" } },
|
||||
{ comment: { contains: filters.q, mode: "insensitive" } },
|
||||
{ author: { email: { contains: filters.q, mode: "insensitive" } } },
|
||||
{ author: { firstName: { contains: filters.q, mode: "insensitive" } } },
|
||||
{ author: { lastName: { contains: filters.q, mode: "insensitive" } } },
|
||||
{ carbet: { title: { contains: filters.q, mode: "insensitive" } } },
|
||||
];
|
||||
}
|
||||
if (filters.carbetId) where.carbetId = filters.carbetId;
|
||||
if (filters.rating) where.rating = filters.rating;
|
||||
if (filters.withResponse === "yes") where.hostResponse = { not: null };
|
||||
if (filters.withResponse === "no") where.hostResponse = null;
|
||||
|
||||
return prisma.review.findMany({
|
||||
where,
|
||||
orderBy: [{ createdAt: "desc" }],
|
||||
take: 200,
|
||||
select: {
|
||||
id: true,
|
||||
rating: true,
|
||||
comment: true,
|
||||
hostResponse: true,
|
||||
hostRespondedAt: true,
|
||||
createdAt: true,
|
||||
booking: { select: { id: true } },
|
||||
carbet: { select: { id: true, title: true, slug: true } },
|
||||
author: { select: { id: true, firstName: true, lastName: true, email: true } },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function getReviewForAdmin(id: string) {
|
||||
return prisma.review.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
booking: { select: { id: true, startDate: true, endDate: true, amount: true, currency: true } },
|
||||
carbet: { select: { id: true, title: true, slug: true } },
|
||||
author: { select: { id: true, firstName: true, lastName: true, email: true } },
|
||||
},
|
||||
});
|
||||
}
|
||||
91
src/lib/admin/users.ts
Normal file
91
src/lib/admin/users.ts
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import "server-only";
|
||||
|
||||
import { Prisma } from "@/generated/prisma/client";
|
||||
import { UserRole } from "@/generated/prisma/enums";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export type AdminUserFilters = {
|
||||
q?: string;
|
||||
role?: UserRole;
|
||||
active?: "yes" | "no";
|
||||
};
|
||||
|
||||
export type AdminUserListItem = {
|
||||
id: string;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
role: UserRole;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
carbetsCount: number;
|
||||
bookingsCount: number;
|
||||
reviewsCount: number;
|
||||
};
|
||||
|
||||
export async function listUsersAdmin(filters: AdminUserFilters = {}): Promise<AdminUserListItem[]> {
|
||||
const where: Prisma.UserWhereInput = {};
|
||||
if (filters.q) {
|
||||
where.OR = [
|
||||
{ email: { contains: filters.q, mode: "insensitive" } },
|
||||
{ firstName: { contains: filters.q, mode: "insensitive" } },
|
||||
{ lastName: { contains: filters.q, mode: "insensitive" } },
|
||||
{ phone: { contains: filters.q, mode: "insensitive" } },
|
||||
];
|
||||
}
|
||||
if (filters.role) where.role = filters.role;
|
||||
if (filters.active === "yes") where.isActive = true;
|
||||
if (filters.active === "no") where.isActive = false;
|
||||
|
||||
const rows = await prisma.user.findMany({
|
||||
where,
|
||||
orderBy: [{ createdAt: "desc" }],
|
||||
take: 300,
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
role: true,
|
||||
isActive: true,
|
||||
createdAt: true,
|
||||
_count: { select: { carbets: true, bookings: true, reviews: true } },
|
||||
},
|
||||
});
|
||||
|
||||
return rows.map((u) => ({
|
||||
id: u.id,
|
||||
email: u.email,
|
||||
firstName: u.firstName,
|
||||
lastName: u.lastName,
|
||||
role: u.role,
|
||||
isActive: u.isActive,
|
||||
createdAt: u.createdAt,
|
||||
carbetsCount: u._count.carbets,
|
||||
bookingsCount: u._count.bookings,
|
||||
reviewsCount: u._count.reviews,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function getUserForAdmin(id: string) {
|
||||
return prisma.user.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
organization: { select: { id: true, name: true } },
|
||||
_count: { select: { carbets: true, bookings: true, reviews: true, subscriptions: true } },
|
||||
bookings: {
|
||||
take: 10,
|
||||
orderBy: { createdAt: "desc" },
|
||||
select: {
|
||||
id: true, status: true, paymentStatus: true, startDate: true, endDate: true, amount: true, currency: true,
|
||||
carbet: { select: { id: true, title: true } },
|
||||
},
|
||||
},
|
||||
carbets: {
|
||||
take: 10,
|
||||
orderBy: { updatedAt: "desc" },
|
||||
select: { id: true, title: true, slug: true, status: true, updatedAt: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue