Add Google Calendar sync: OAuth connect flow, dedicated Бронирования calendar, best-effort event create/update/delete on booking changes
This commit is contained in:
1 parent
14a849bfb9
commit
7654a7b616
14 files changed
+981
-3
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import { and, eq, gte, lt, inArray, sql } from "drizzle-orm";
|
||||
import { db } from "@/lib/db/client";
|
||||
import { bookings, bookingObjects, bookableObjects, users } from "@/lib/db/schema";
|
||||
import { createCalendarEvent, updateCalendarEvent, deleteCalendarEvent } from "@/lib/google/calendar";
|
||||
|
||||
export interface BookableObjectDTO {
|
||||
id: string;
|
||||
@@ -52,6 +53,7 @@ export interface BookingDTO {
|
||||
status: "confirmed" | "cancelled";
|
||||
objects: { id: string; name: string }[];
|
||||
bookedByName: string;
|
||||
googleEventId: string | null;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
@@ -81,6 +83,7 @@ async function toBookingDTO(row: typeof bookings.$inferSelect): Promise<BookingD
|
||||
status: row.status,
|
||||
objects: objRows,
|
||||
bookedByName: bookedBy?.name ?? "—",
|
||||
googleEventId: row.googleEventId,
|
||||
createdAt: row.createdAt,
|
||||
};
|
||||
}
|
||||
@@ -126,7 +129,20 @@ export async function createBooking(input: CreateBookingInput): Promise<BookingD
|
||||
await db.insert(bookingObjects).values(input.objectIds.map((objectId) => ({ bookingId: row.id, objectId })));
|
||||
}
|
||||
|
||||
return toBookingDTO(row);
|
||||
const dto = await toBookingDTO(row);
|
||||
|
||||
// Best-effort Google Calendar sync — never blocks/fails booking creation.
|
||||
try {
|
||||
const googleEventId = await createCalendarEvent(dto);
|
||||
if (googleEventId) {
|
||||
await db.update(bookings).set({ googleEventId }).where(eq(bookings.id, row.id));
|
||||
dto.googleEventId = googleEventId;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Google Calendar sync failed for booking", row.bookingNumber, err);
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
export interface UpdateBookingInput {
|
||||
@@ -160,7 +176,29 @@ export async function updateBooking(id: string, input: UpdateBookingInput): Prom
|
||||
}
|
||||
const row = await db.query.bookings.findFirst({ where: eq(bookings.id, id) });
|
||||
if (!row) return null;
|
||||
return toBookingDTO(row);
|
||||
const dto = await toBookingDTO(row);
|
||||
|
||||
// Best-effort Google Calendar sync — never blocks/fails the update.
|
||||
try {
|
||||
if (dto.status === "cancelled" && dto.googleEventId) {
|
||||
await deleteCalendarEvent(dto.googleEventId);
|
||||
await db.update(bookings).set({ googleEventId: null }).where(eq(bookings.id, id));
|
||||
dto.googleEventId = null;
|
||||
} else if (dto.status === "confirmed" && dto.googleEventId) {
|
||||
await updateCalendarEvent(dto);
|
||||
} else if (dto.status === "confirmed" && !dto.googleEventId) {
|
||||
// Never synced yet (created before Google was connected, or just restored from cancelled).
|
||||
const googleEventId = await createCalendarEvent(dto);
|
||||
if (googleEventId) {
|
||||
await db.update(bookings).set({ googleEventId }).where(eq(bookings.id, id));
|
||||
dto.googleEventId = googleEventId;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Google Calendar sync failed for booking", dto.bookingNumber, err);
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
export async function getBooking(id: string): Promise<BookingDTO | null> {
|
||||
|
||||
Reference in new issue
Block a user