templates2.Booking.Next/prisma/seed.ts
w4c-templates 6a0c2e88d2
Some checks are pending
CI / quality (push) Waiting to run
chore(template): publish Booking.Next
2026-10-11 23:27:02 +03:00

108 lines
6.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { PrismaClient } from '@prisma/client';
import bcrypt from 'bcryptjs';
import { zonedTimeToUtc, zonedParts } from '../lib/slots';
const db = new PrismaClient();
const TZ = process.env.SITE_TIMEZONE || 'UTC';
const SERVICES = [
{ id: 'svc-consult', slug: 'consultation', name: 'Initial Consultation', durationMin: 30, priceCents: 7500, description: 'A focused 30-minute session to assess your goals and plan next steps.' },
{ id: 'svc-therapy', slug: 'therapy-session', name: 'Therapy Session', durationMin: 60, priceCents: 12000, description: 'A full one-hour hands-on therapy session with a senior specialist.' },
{ id: 'svc-training', slug: 'personal-training', name: 'Personal Training', durationMin: 45, priceCents: 6000, description: 'A 45-minute one-to-one training session tailored to your routine.' },
];
const STAFF = [
{ id: 'staff-alex', slug: 'alex-rivera', name: 'Alex Rivera', title: 'Senior Specialist', avatarColor: '#4f46e5', bio: 'Twelve years of clinical practice and a calm, methodical approach.', services: ['svc-consult', 'svc-therapy', 'svc-training'] },
{ id: 'staff-sam', slug: 'sam-patel', name: 'Sam Patel', title: 'Wellness Coach', avatarColor: '#0d9488', bio: 'Strength and mobility coach focused on sustainable progress.', services: ['svc-consult', 'svc-training'] },
];
// Mon–Fri, 09:00–17:00 (weekday 1..5).
const WEEKDAY_HOURS = [1, 2, 3, 4, 5].map((weekday) => ({ weekday, startMin: 9 * 60, endMin: 17 * 60 }));
/** A wall-clock date `offsetDays` from today (in the site timezone) at hour:minute. */
function at(offsetDays: number, hour: number, minute = 0): Date {
const nowParts = zonedParts(new Date(), TZ);
const base = new Date(Date.UTC(nowParts.year, nowParts.month - 1, nowParts.day + offsetDays));
return zonedTimeToUtc({ year: base.getUTCFullYear(), month: base.getUTCMonth() + 1, day: base.getUTCDate() }, hour * 60 + minute, TZ);
}
async function main() {
const password = await bcrypt.hash('password', 10);
const admin = await db.user.upsert({
where: { email: 'admin@example.com' },
update: { role: 'admin' },
create: { email: 'admin@example.com', name: 'Booking Admin', role: 'admin', passwordHash: password },
});
const customer = await db.user.upsert({
where: { email: 'user@example.com' },
update: {},
create: { email: 'user@example.com', name: 'Demo Customer', role: 'user', passwordHash: password },
});
await db.subscription.upsert({ where: { userId: admin.id }, update: {}, create: { userId: admin.id, plan: 'pro', status: 'active', provider: 'mock' } });
await db.subscription.upsert({ where: { userId: customer.id }, update: {}, create: { userId: customer.id, plan: 'free', status: 'active', provider: 'mock' } });
const serviceIds = new Map<string, string>();
for (const s of SERVICES) {
const row = await db.service.upsert({
where: { slug: s.slug },
update: { name: s.name, description: s.description, durationMin: s.durationMin, priceCents: s.priceCents, active: true },
create: { id: s.id, slug: s.slug, name: s.name, description: s.description, durationMin: s.durationMin, priceCents: s.priceCents },
});
serviceIds.set(s.id, row.id);
}
const staffIds = new Map<string, string>();
for (const s of STAFF) {
const row = await db.staff.upsert({
where: { slug: s.slug },
update: { name: s.name, title: s.title, bio: s.bio, avatarColor: s.avatarColor },
create: { id: s.id, slug: s.slug, name: s.name, title: s.title, bio: s.bio, avatarColor: s.avatarColor },
});
staffIds.set(s.id, row.id);
// Reset this member's schedule and service offering.
await db.staffService.deleteMany({ where: { staffId: row.id } });
await db.workingHour.deleteMany({ where: { staffId: row.id } });
await db.staffService.createMany({ data: s.services.map((sid) => ({ staffId: row.id, serviceId: serviceIds.get(sid)! })) });
await db.workingHour.createMany({ data: WEEKDAY_HOURS.map((h) => ({ staffId: row.id, ...h })) });
}
// Refresh the demo bookings so they always sit around "today".
const svc = (id: string) => serviceIds.get(id)!;
const who = (id: string) => staffIds.get(id)!;
await db.booking.deleteMany({});
await db.booking.createMany({
data: [
{ serviceId: svc('svc-therapy'), staffId: who('staff-alex'), userId: customer.id, startsAt: at(0, 14, 0), endsAt: at(0, 15, 0), status: 'confirmed', customerName: 'Demo Customer', customerEmail: customer.email, notes: 'First visit.' },
{ serviceId: svc('svc-consult'), staffId: who('staff-sam'), userId: customer.id, startsAt: at(1, 10, 0), endsAt: at(1, 10, 30), status: 'pending', customerName: 'Demo Customer', customerEmail: customer.email },
{ serviceId: svc('svc-therapy'), staffId: who('staff-alex'), startsAt: at(2, 11, 0), endsAt: at(2, 12, 0), status: 'confirmed', customerName: 'Jordan Lee', customerEmail: 'jordan.lee@example.com', notes: 'Follow-up session.' },
{ serviceId: svc('svc-training'), staffId: who('staff-sam'), startsAt: at(3, 9, 30), endsAt: at(3, 10, 15), status: 'pending', customerName: 'Priya Nair', customerEmail: 'priya.nair@example.com' },
{ serviceId: svc('svc-consult'), staffId: who('staff-alex'), startsAt: at(-1, 9, 30), endsAt: at(-1, 10, 0), status: 'completed', customerName: 'Jordan Lee', customerEmail: 'jordan.lee@example.com' },
{ serviceId: svc('svc-therapy'), staffId: who('staff-sam'), startsAt: at(-1, 15, 0), endsAt: at(-1, 16, 0), status: 'no_show', customerName: 'Casey Brooks', customerEmail: 'casey.brooks@example.com' },
{ serviceId: svc('svc-training'), staffId: who('staff-alex'), startsAt: at(-3, 12, 0), endsAt: at(-3, 12, 45), status: 'cancelled', customerName: 'Morgan Diaz', customerEmail: 'morgan.diaz@example.com' },
],
});
if ((await db.auditLog.count()) === 0) {
await db.auditLog.createMany({
data: [
{ actorId: admin.id, action: 'seed', target: 'system', meta: 'Initial demo data' },
{ actorId: admin.id, action: 'catalog.loaded', target: `${SERVICES.length} services, ${STAFF.length} staff` },
],
});
}
console.log(`Seeded booking: ${admin.email} (admin), ${customer.email} (customer) — password: "password" (timezone: ${TZ})`);
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await db.$disconnect();
});