import { db } from "./db";
import { bookings } from "./schema";
// day availability
export async function getSlots(date: string) {
const taken = await db
.select()
.from(bookings)
.where(eq(bookings.date, date));
return allSlots(date).filter(s => !taken.some(t => t.slot === s));
}
export function BookingForm() {
const [slot, setSlot] = useState<string | null>(null);
async function submit(e: FormEvent) {
e.preventDefault();
await fetch("/api/bookings", {
method: "POST",
body: JSON.stringify({ slot }),
});
}
return <form onSubmit={submit} />;
}
// routes
app.post("/api/bookings", async (req, res) => {
const data = schema.parse(req.body);
await db.insert(bookings).values(data);
await sendConfirmation(data);
res.status(201).json({ ok: true });
});
// i18n
const lang = detect(navigator.language) ?? "it";
const t = useTranslation(lang);
export const appointments = pgTable("appointments", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
date: date("date").notNull(),
slot: varchar("slot", { length: 5 }),
status: text("status").default("confirmed"),
});
/* mobile first */
@media (min-width: 768px) {
.panel { display: grid; gap: 24px; }
}
import { db } from "./db";
import { bookings } from "./schema";
// day availability
export async function getSlots(date: string) {
const taken = await db
.select()
.from(bookings)
.where(eq(bookings.date, date));
return allSlots(date).filter(s => !taken.some(t => t.slot === s));
}
export function BookingForm() {
const [slot, setSlot] = useState<string | null>(null);
async function submit(e: FormEvent) {
e.preventDefault();
await fetch("/api/bookings", {
method: "POST",
body: JSON.stringify({ slot }),
});
}
return <form onSubmit={submit} />;
}
// routes
app.post("/api/bookings", async (req, res) => {
const data = schema.parse(req.body);
await db.insert(bookings).values(data);
await sendConfirmation(data);
res.status(201).json({ ok: true });
});
// i18n
const lang = detect(navigator.language) ?? "it";
const t = useTranslation(lang);
export const appointments = pgTable("appointments", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
date: date("date").notNull(),
slot: varchar("slot", { length: 5 }),
status: text("status").default("confirmed"),
});
/* mobile first */
@media (min-width: 768px) {
.panel { display: grid; gap: 24px; }
}
// routes
app.post("/api/bookings", async (req, res) => {
const data = schema.parse(req.body);
await db.insert(bookings).values(data);
await sendConfirmation(data);
res.status(201).json({ ok: true });
});
// i18n
const lang = detect(navigator.language) ?? "it";
const t = useTranslation(lang);
export const appointments = pgTable("appointments", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
date: date("date").notNull(),
slot: varchar("slot", { length: 5 }),
status: text("status").default("confirmed"),
});
/* mobile first */
@media (min-width: 768px) {
.panel { display: grid; gap: 24px; }
}
import { db } from "./db";
import { bookings } from "./schema";
// day availability
export async function getSlots(date: string) {
const taken = await db
.select()
.from(bookings)
.where(eq(bookings.date, date));
return allSlots(date).filter(s => !taken.some(t => t.slot === s));
}
export function BookingForm() {
const [slot, setSlot] = useState<string | null>(null);
async function submit(e: FormEvent) {
e.preventDefault();
await fetch("/api/bookings", {
method: "POST",
body: JSON.stringify({ slot }),
});
}
return <form onSubmit={submit} />;
}
// routes
app.post("/api/bookings", async (req, res) => {
const data = schema.parse(req.body);
await db.insert(bookings).values(data);
await sendConfirmation(data);
res.status(201).json({ ok: true });
});
// i18n
const lang = detect(navigator.language) ?? "it";
const t = useTranslation(lang);
export const appointments = pgTable("appointments", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
date: date("date").notNull(),
slot: varchar("slot", { length: 5 }),
status: text("status").default("confirmed"),
});
/* mobile first */
@media (min-width: 768px) {
.panel { display: grid; gap: 24px; }
}
import { db } from "./db";
import { bookings } from "./schema";
// day availability
export async function getSlots(date: string) {
const taken = await db
.select()
.from(bookings)
.where(eq(bookings.date, date));
return allSlots(date).filter(s => !taken.some(t => t.slot === s));
}
export function BookingForm() {
const [slot, setSlot] = useState<string | null>(null);
async function submit(e: FormEvent) {
e.preventDefault();
await fetch("/api/bookings", {
method: "POST",
body: JSON.stringify({ slot }),
});
}
return <form onSubmit={submit} />;
}
export function BookingForm() {
const [slot, setSlot] = useState<string | null>(null);
async function submit(e: FormEvent) {
e.preventDefault();
await fetch("/api/bookings", {
method: "POST",
body: JSON.stringify({ slot }),
});
}
return <form onSubmit={submit} />;
}
import { db } from "./db";
import { bookings } from "./schema";
// day availability
export async function getSlots(date: string) {
const taken = await db
.select()
.from(bookings)
.where(eq(bookings.date, date));
return allSlots(date).filter(s => !taken.some(t => t.slot === s));
}
export const appointments = pgTable("appointments", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
date: date("date").notNull(),
slot: varchar("slot", { length: 5 }),
status: text("status").default("confirmed"),
});
/* mobile first */
@media (min-width: 768px) {
.panel { display: grid; gap: 24px; }
}
// routes
app.post("/api/bookings", async (req, res) => {
const data = schema.parse(req.body);
await db.insert(bookings).values(data);
await sendConfirmation(data);
res.status(201).json({ ok: true });
});
// i18n
const lang = detect(navigator.language) ?? "it";
const t = useTranslation(lang);
export function BookingForm() {
const [slot, setSlot] = useState<string | null>(null);
async function submit(e: FormEvent) {
e.preventDefault();
await fetch("/api/bookings", {
method: "POST",
body: JSON.stringify({ slot }),
});
}
return <form onSubmit={submit} />;
}
import { db } from "./db";
import { bookings } from "./schema";
// day availability
export async function getSlots(date: string) {
const taken = await db
.select()
.from(bookings)
.where(eq(bookings.date, date));
return allSlots(date).filter(s => !taken.some(t => t.slot === s));
}
export const appointments = pgTable("appointments", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
date: date("date").notNull(),
slot: varchar("slot", { length: 5 }),
status: text("status").default("confirmed"),
});
/* mobile first */
@media (min-width: 768px) {
.panel { display: grid; gap: 24px; }
}
// routes
app.post("/api/bookings", async (req, res) => {
const data = schema.parse(req.body);
await db.insert(bookings).values(data);
await sendConfirmation(data);
res.status(201).json({ ok: true });
});
// i18n
const lang = detect(navigator.language) ?? "it";
const t = useTranslation(lang);