Implement lists module and dev login setup
This commit is contained in:
@@ -4,11 +4,7 @@ import FullCalendar from "@fullcalendar/react";
|
||||
import dayGridPlugin from "@fullcalendar/daygrid";
|
||||
import interactionPlugin from "@fullcalendar/interaction";
|
||||
import timeGridPlugin from "@fullcalendar/timegrid";
|
||||
import type {
|
||||
DateSelectArg,
|
||||
EventClickArg,
|
||||
EventDropArg,
|
||||
} from "@fullcalendar/core";
|
||||
import type { DateSelectArg, EventClickArg, EventDropArg } from "@fullcalendar/core";
|
||||
import type { EventResizeDoneArg } from "@fullcalendar/interaction";
|
||||
import { CalendarPlus, Check, Eye, EyeOff, Plus, Trash2 } from "lucide-react";
|
||||
import { useMemo, useState, useTransition } from "react";
|
||||
@@ -221,9 +217,7 @@ export function CalendarShell({
|
||||
|
||||
function updateCalendar(calendar: CalendarDto, values: Partial<CalendarDto>) {
|
||||
const next = { ...calendar, ...values };
|
||||
setCalendarRows((current) =>
|
||||
current.map((item) => (item.id === calendar.id ? next : item)),
|
||||
);
|
||||
setCalendarRows((current) => current.map((item) => (item.id === calendar.id ? next : item)));
|
||||
startTransition(async () => {
|
||||
if (values.name !== undefined) {
|
||||
await renameCalendar({ id: calendar.id, name: values.name });
|
||||
@@ -367,7 +361,7 @@ export function CalendarShell({
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<Button className="w-full" onClick={addCalendar} disabled={!calendarName || isPending}>
|
||||
<Button className="w-full" onClick={addCalendar} disabled={!calendarName}>
|
||||
<Check />
|
||||
Create calendar
|
||||
</Button>
|
||||
|
||||
@@ -14,20 +14,31 @@ const calendarInput = z.object({
|
||||
visibility: z.enum(["private", "household"]).default("household"),
|
||||
});
|
||||
|
||||
const eventInput = z
|
||||
.object({
|
||||
calendarId: z.string().uuid(),
|
||||
title: z.string().trim().min(1).max(200),
|
||||
startAt: z.coerce.date(),
|
||||
endAt: z.coerce.date(),
|
||||
allDay: z.boolean().default(false),
|
||||
location: z.string().trim().max(300).nullable().optional(),
|
||||
notes: z.string().trim().max(3000).nullable().optional(),
|
||||
})
|
||||
.refine((value) => value.endAt >= value.startAt, {
|
||||
const eventBaseInput = z.object({
|
||||
calendarId: z.string().uuid(),
|
||||
title: z.string().trim().min(1).max(200),
|
||||
startAt: z.coerce.date(),
|
||||
endAt: z.coerce.date(),
|
||||
allDay: z.boolean().default(false),
|
||||
location: z.string().trim().max(300).nullable().optional(),
|
||||
notes: z.string().trim().max(3000).nullable().optional(),
|
||||
});
|
||||
|
||||
const eventInput = eventBaseInput.refine((value) => value.endAt >= value.startAt, {
|
||||
path: ["endAt"],
|
||||
message: "End must be after start",
|
||||
});
|
||||
|
||||
const eventUpdateInput = eventBaseInput.partial().refine(
|
||||
(value) => {
|
||||
if (!value.startAt || !value.endAt) return true;
|
||||
return value.endAt >= value.startAt;
|
||||
},
|
||||
{
|
||||
path: ["endAt"],
|
||||
message: "End must be after start",
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
export async function createCalendar(input: z.input<typeof calendarInput>) {
|
||||
const parsed = calendarInput.parse(input);
|
||||
@@ -79,9 +90,7 @@ export async function setCalendarVisibility(input: {
|
||||
|
||||
export async function setCalendarColor(input: { id: string; color: string | null }) {
|
||||
const { user } = await getCurrentSession();
|
||||
const parsed = z
|
||||
.object({ id: z.string().uuid(), color: calendarInput.shape.color })
|
||||
.parse(input);
|
||||
const parsed = z.object({ id: z.string().uuid(), color: calendarInput.shape.color }).parse(input);
|
||||
await assertOwnsCalendar(user.id, parsed.id);
|
||||
await db
|
||||
.update(calendars)
|
||||
@@ -124,10 +133,7 @@ export async function createEvent(input: z.input<typeof eventInput>) {
|
||||
}
|
||||
|
||||
export async function updateEvent(input: { id: string } & Partial<z.input<typeof eventInput>>) {
|
||||
const parsed = z
|
||||
.object({ id: z.string().uuid() })
|
||||
.and(eventInput.partial())
|
||||
.parse(input);
|
||||
const parsed = z.object({ id: z.string().uuid() }).and(eventUpdateInput).parse(input);
|
||||
const { user } = await getCurrentSession();
|
||||
const [existing] = await db
|
||||
.select({ calendarId: calendarEvents.calendarId })
|
||||
|
||||
Reference in New Issue
Block a user