Productionize EventSphere platform
This commit is contained in:
51
apps/api/src/modules/calendar/calendar.controller.ts
Normal file
51
apps/api/src/modules/calendar/calendar.controller.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Body, Controller, Get, Post, Query, Req, UseGuards } from "@nestjs/common";
|
||||
import type { Request } from "express";
|
||||
import { JwtAuthGuard, PermissionsGuard, RequirePermissions, TenantGuard } from "../auth/guards";
|
||||
import { CalendarService } from "./calendar.service";
|
||||
|
||||
@Controller("calendar")
|
||||
export class CalendarController {
|
||||
constructor(private readonly service: CalendarService) {}
|
||||
|
||||
@UseGuards(JwtAuthGuard, TenantGuard, PermissionsGuard)
|
||||
@RequirePermissions("calendar.read")
|
||||
@Get("routing-forms")
|
||||
routingForms(@Req() req: Request) {
|
||||
return this.service.routingForms((req.user as any).tenantId as string);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard, TenantGuard, PermissionsGuard)
|
||||
@RequirePermissions("calendar.write")
|
||||
@Post("routing-forms")
|
||||
createRoutingForm(@Req() req: Request, @Body() payload: Record<string, unknown>) {
|
||||
return this.service.createRoutingForm((req.user as any).tenantId as string, payload);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard, TenantGuard, PermissionsGuard)
|
||||
@RequirePermissions("calendar.read")
|
||||
@Get("slots")
|
||||
slots(@Req() req: Request, @Query("routingFormId") routingFormId?: string) {
|
||||
return this.service.slots((req.user as any).tenantId as string, routingFormId);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard, TenantGuard, PermissionsGuard)
|
||||
@RequirePermissions("calendar.write")
|
||||
@Post("slots")
|
||||
createSlot(@Req() req: Request, @Body() payload: Record<string, unknown>) {
|
||||
return this.service.createSlot((req.user as any).tenantId as string, payload);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard, TenantGuard, PermissionsGuard)
|
||||
@RequirePermissions("calendar.read")
|
||||
@Get("bookings")
|
||||
bookings(@Req() req: Request) {
|
||||
return this.service.bookings((req.user as any).tenantId as string);
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard, TenantGuard, PermissionsGuard)
|
||||
@RequirePermissions("calendar.write")
|
||||
@Post("bookings")
|
||||
createBooking(@Req() req: Request, @Body() payload: Record<string, unknown>) {
|
||||
return this.service.createBooking((req.user as any).tenantId as string, payload);
|
||||
}
|
||||
}
|
||||
9
apps/api/src/modules/calendar/calendar.module.ts
Normal file
9
apps/api/src/modules/calendar/calendar.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { CalendarController } from "./calendar.controller";
|
||||
import { CalendarService } from "./calendar.service";
|
||||
|
||||
@Module({
|
||||
controllers: [CalendarController],
|
||||
providers: [CalendarService]
|
||||
})
|
||||
export class CalendarModule {}
|
||||
92
apps/api/src/modules/calendar/calendar.service.ts
Normal file
92
apps/api/src/modules/calendar/calendar.service.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { PrismaService } from "../../prisma/prisma.service";
|
||||
|
||||
@Injectable()
|
||||
export class CalendarService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
routingForms(tenantId: string) {
|
||||
return this.prisma.calendarRoutingForm.findMany({
|
||||
where: { tenantId },
|
||||
orderBy: { createdAt: "desc" },
|
||||
include: { event: true, _count: { select: { slots: true, bookings: true } } }
|
||||
});
|
||||
}
|
||||
|
||||
createRoutingForm(tenantId: string, payload: any) {
|
||||
return this.prisma.calendarRoutingForm.create({
|
||||
data: {
|
||||
tenantId,
|
||||
eventId: payload.eventId || null,
|
||||
name: String(payload.name ?? ""),
|
||||
slug: String(payload.slug ?? "").toLowerCase().trim(),
|
||||
description: payload.description ? String(payload.description) : null,
|
||||
durationMinutes: Number(payload.durationMinutes ?? 30),
|
||||
active: payload.active === undefined ? true : Boolean(payload.active)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
slots(tenantId: string, routingFormId?: string) {
|
||||
return this.prisma.calendarSlot.findMany({
|
||||
where: { tenantId, ...(routingFormId ? { routingFormId } : {}) },
|
||||
orderBy: { startsAt: "asc" },
|
||||
include: { routingForm: true }
|
||||
});
|
||||
}
|
||||
|
||||
async createSlot(tenantId: string, payload: any) {
|
||||
const routingForm = await this.prisma.calendarRoutingForm.findFirst({ where: { tenantId, id: String(payload.routingFormId ?? "") } });
|
||||
if (!routingForm) throw new NotFoundException("Routing form not found");
|
||||
const startsAt = new Date(String(payload.startsAt ?? ""));
|
||||
const endsAt = new Date(String(payload.endsAt ?? ""));
|
||||
if (!Number.isFinite(startsAt.getTime()) || !Number.isFinite(endsAt.getTime()) || endsAt <= startsAt) {
|
||||
throw new BadRequestException("Invalid slot time");
|
||||
}
|
||||
return this.prisma.calendarSlot.create({
|
||||
data: {
|
||||
tenantId,
|
||||
routingFormId: routingForm.id,
|
||||
startsAt,
|
||||
endsAt,
|
||||
capacity: Number(payload.capacity ?? 1),
|
||||
active: payload.active === undefined ? true : Boolean(payload.active)
|
||||
},
|
||||
include: { routingForm: true }
|
||||
});
|
||||
}
|
||||
|
||||
bookings(tenantId: string) {
|
||||
return this.prisma.booking.findMany({
|
||||
where: { tenantId },
|
||||
orderBy: { startsAt: "desc" },
|
||||
include: { routingForm: true, event: true, attendee: true }
|
||||
});
|
||||
}
|
||||
|
||||
async createBooking(tenantId: string, payload: any) {
|
||||
const routingForm = await this.prisma.calendarRoutingForm.findFirst({ where: { tenantId, id: String(payload.routingFormId ?? "") } });
|
||||
if (!routingForm) throw new NotFoundException("Routing form not found");
|
||||
const startsAt = new Date(String(payload.startsAt ?? ""));
|
||||
const endsAt = new Date(String(payload.endsAt ?? ""));
|
||||
if (!Number.isFinite(startsAt.getTime()) || !Number.isFinite(endsAt.getTime()) || endsAt <= startsAt) {
|
||||
throw new BadRequestException("Invalid booking time");
|
||||
}
|
||||
return this.prisma.booking.create({
|
||||
data: {
|
||||
tenantId,
|
||||
routingFormId: routingForm.id,
|
||||
eventId: payload.eventId || routingForm.eventId || null,
|
||||
attendeeId: payload.attendeeId || null,
|
||||
fullName: String(payload.fullName ?? ""),
|
||||
email: String(payload.email ?? "").toLowerCase().trim(),
|
||||
phone: payload.phone ? String(payload.phone) : null,
|
||||
startsAt,
|
||||
endsAt,
|
||||
status: payload.status ? String(payload.status) : "booked",
|
||||
notes: payload.notes ? String(payload.notes) : null
|
||||
},
|
||||
include: { routingForm: true, event: true, attendee: true }
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user