Compare commits

...

19 commits
v0.1.2 ... main

Author SHA1 Message Date
872cfe363f fix(deps): update dependency react-day-picker to v9.8.0
All checks were successful
container-scan / Container Scan (push) Successful in 8m42s
docker-build / docker (push) Successful in 11m14s
tests / Tests (push) Successful in 5m57s
2025-07-05 10:02:31 +00:00
168fcaa731 fix(deps): update dependency react-hook-form to v7.60.0
All checks were successful
container-scan / Container Scan (push) Successful in 9m15s
docker-build / docker (push) Successful in 11m10s
tests / Tests (push) Successful in 6m8s
2025-07-05 01:06:13 +00:00
be00d68a68 fix(deps): update dependency zod to v3.25.74
All checks were successful
container-scan / Container Scan (push) Successful in 8m34s
docker-build / docker (push) Successful in 10m28s
tests / Tests (push) Successful in 6m1s
2025-07-05 00:02:24 +00:00
984646dfbc Merge pull request 'chore(deps): update cypress/browsers:latest docker digest to 95587c1' (#132)
All checks were successful
container-scan / Container Scan (push) Successful in 8m52s
docker-build / docker (push) Successful in 5m11s
tests / Tests (push) Successful in 5m41s
Reviewed-on: #132
Reviewed-by: Dominik <mail@dominikstahl.dev>
2025-07-03 06:49:41 +00:00
ac7d0d35a6 Merge pull request 'chore(deps): update dependency @types/node to v22.16.0' (#133)
Some checks failed
container-scan / Container Scan (push) Has been cancelled
tests / Tests (push) Waiting to run
docker-build / docker (push) Successful in 10m21s
Reviewed-on: #133
Reviewed-by: Dominik <mail@dominikstahl.dev>
2025-07-03 06:49:34 +00:00
010c7885dd Merge pull request 'fix(deps): update dependency zod to v3.25.71' (#134)
Some checks failed
docker-build / docker (push) Waiting to run
tests / Tests (push) Waiting to run
container-scan / Container Scan (push) Has been cancelled
Reviewed-on: #134
2025-07-03 06:48:15 +00:00
a4d33bf1d0 fix(deps): update dependency zod to v3.25.71
All checks were successful
docker-build / docker (push) Successful in 10m13s
container-scan / Container Scan (pull_request) Successful in 7m45s
docker-build / docker (pull_request) Successful in 1m27s
tests / Tests (push) Successful in 5m5s
tests / Tests (pull_request) Successful in 5m4s
2025-07-03 03:01:29 +00:00
92acd8a32b chore(deps): update dependency @types/node to v22.16.0
All checks were successful
docker-build / docker (push) Successful in 10m42s
tests / Tests (push) Successful in 5m48s
container-scan / Container Scan (pull_request) Successful in 7m40s
docker-build / docker (pull_request) Successful in 1m30s
tests / Tests (pull_request) Successful in 5m28s
2025-07-03 01:02:17 +00:00
583368c1ba chore(deps): update cypress/browsers:latest docker digest to 95587c1
All checks were successful
docker-build / docker (push) Successful in 10m30s
tests / Tests (push) Successful in 5m26s
container-scan / Container Scan (pull_request) Successful in 3m0s
docker-build / docker (pull_request) Successful in 1m13s
tests / Tests (pull_request) Successful in 4m49s
2025-07-03 01:02:10 +00:00
30b0df062f fix(deps): update dependency swagger-ui-react to v5.26.0
All checks were successful
container-scan / Container Scan (push) Successful in 7m47s
docker-build / docker (push) Successful in 10m10s
tests / Tests (push) Successful in 5m12s
2025-07-03 00:01:53 +00:00
7260985de3 chore(deps): update dependency cypress to v14.5.1
All checks were successful
container-scan / Container Scan (push) Successful in 6m38s
docker-build / docker (push) Successful in 9m0s
tests / Tests (push) Successful in 4m2s
2025-07-01 22:01:49 +00:00
de1a80aed8 chore(deps): update dependency eslint to v9.30.1
All checks were successful
container-scan / Container Scan (push) Successful in 7m3s
docker-build / docker (push) Successful in 8m48s
tests / Tests (push) Successful in 4m29s
2025-07-01 21:01:28 +00:00
664c6cf283 fix(deps): update dependency swagger-ui-react to v5.25.4
Some checks failed
container-scan / Container Scan (push) Successful in 9m11s
tests / Tests (push) Successful in 8m9s
docker-build / docker (push) Failing after 23m39s
2025-07-01 14:02:19 +00:00
142ac33e28 Merge pull request 'fix(blocker): disallow blocker end times before start time' (#131)
All checks were successful
container-scan / Container Scan (push) Successful in 2m43s
tests / Tests (push) Successful in 3m36s
docker-build / docker (push) Successful in 1m36s
Reviewed-on: #131
2025-07-01 12:55:03 +00:00
c014b77f9b
fix(blocker): disallow blocker end times before start time
All checks were successful
container-scan / Container Scan (pull_request) Successful in 2m50s
docker-build / docker (pull_request) Successful in 6m16s
tests / Tests (pull_request) Successful in 3m50s
2025-07-01 14:41:45 +02:00
9adcdc274f Merge pull request 'fix: hotfixes' (#130)
All checks were successful
container-scan / Container Scan (push) Successful in 2m46s
tests / Tests (push) Successful in 3m56s
docker-build / docker (push) Successful in 1m10s
Reviewed-on: #130
2025-07-01 10:04:01 +00:00
6ae22a23c7
fix: layout issues
All checks were successful
container-scan / Container Scan (pull_request) Successful in 2m52s
docker-build / docker (pull_request) Successful in 6m10s
tests / Tests (pull_request) Successful in 3m34s
2025-07-01 11:51:02 +02:00
83fe2c772c
fix: event cards layout bugs
Some checks failed
tests / Tests (pull_request) Has been cancelled
docker-build / docker (pull_request) Has been cancelled
container-scan / Container Scan (pull_request) Has been cancelled
2025-07-01 11:45:19 +02:00
d7fdd5d257
fix: event deletion issues 2025-07-01 11:37:49 +02:00
10 changed files with 389 additions and 163 deletions

View file

@ -10,7 +10,7 @@ jobs:
name: Tests
runs-on: docker
container:
image: cypress/browsers:latest@sha256:9daea41366dfd1b72496bf3e8295eda215a6990c2dbe4f9ff4b8ba47342864fb
image: cypress/browsers:latest@sha256:95587c1ce688ce6f59934cc234a753a32a1782ca1c7959707a7d2332e69f6f63
options: --user 1001
steps:
- name: Checkout

View file

@ -1,6 +1,6 @@
{
"name": "meetup",
"version": "0.1.0",
"version": "0.1.3",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
@ -73,15 +73,15 @@
"devDependencies": {
"@eslint/eslintrc": "3.3.1",
"@tailwindcss/postcss": "4.1.11",
"@types/node": "22.15.34",
"@types/node": "22.16.0",
"@types/react": "19.1.8",
"@types/react-big-calendar": "1.16.2",
"@types/react-dom": "19.1.6",
"@types/swagger-ui-react": "5.18.0",
"@types/webpack-env": "1.18.8",
"cypress": "14.5.0",
"cypress": "14.5.1",
"dotenv-cli": "8.0.0",
"eslint": "9.30.0",
"eslint": "9.30.1",
"eslint-config-next": "15.3.4",
"eslint-config-prettier": "10.1.5",
"orval": "7.10.0",

View file

@ -0,0 +1,170 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_blocked_slots" (
"id" TEXT NOT NULL PRIMARY KEY,
"user_id" TEXT NOT NULL,
"start_time" DATETIME NOT NULL,
"end_time" DATETIME NOT NULL,
"reason" TEXT,
"is_recurring" BOOLEAN NOT NULL DEFAULT false,
"rrule" TEXT,
"recurrence_end_date" DATETIME,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL,
CONSTRAINT "blocked_slots_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_blocked_slots" ("created_at", "end_time", "id", "is_recurring", "reason", "recurrence_end_date", "rrule", "start_time", "updated_at", "user_id") SELECT "created_at", "end_time", "id", "is_recurring", "reason", "recurrence_end_date", "rrule", "start_time", "updated_at", "user_id" FROM "blocked_slots";
DROP TABLE "blocked_slots";
ALTER TABLE "new_blocked_slots" RENAME TO "blocked_slots";
CREATE INDEX "blocked_slots_user_id_start_time_end_time_idx" ON "blocked_slots"("user_id", "start_time", "end_time");
CREATE INDEX "blocked_slots_user_id_is_recurring_idx" ON "blocked_slots"("user_id", "is_recurring");
CREATE TABLE "new_calendar_export_tokens" (
"id" TEXT NOT NULL PRIMARY KEY,
"user_id" TEXT NOT NULL,
"token" TEXT NOT NULL,
"scope" TEXT NOT NULL DEFAULT 'MEETINGS_ONLY',
"is_active" BOOLEAN NOT NULL DEFAULT true,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"last_accessed_at" DATETIME,
CONSTRAINT "calendar_export_tokens_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_calendar_export_tokens" ("created_at", "id", "is_active", "last_accessed_at", "scope", "token", "user_id") SELECT "created_at", "id", "is_active", "last_accessed_at", "scope", "token", "user_id" FROM "calendar_export_tokens";
DROP TABLE "calendar_export_tokens";
ALTER TABLE "new_calendar_export_tokens" RENAME TO "calendar_export_tokens";
CREATE UNIQUE INDEX "calendar_export_tokens_token_key" ON "calendar_export_tokens"("token");
CREATE INDEX "calendar_export_tokens_user_id_idx" ON "calendar_export_tokens"("user_id");
CREATE TABLE "new_calendar_subscriptions" (
"id" TEXT NOT NULL PRIMARY KEY,
"user_id" TEXT NOT NULL,
"feed_url" TEXT NOT NULL,
"name" TEXT,
"color" TEXT,
"is_enabled" BOOLEAN NOT NULL DEFAULT true,
"last_synced_at" DATETIME,
"last_sync_error" TEXT,
"sync_frequency_minutes" INTEGER DEFAULT 60,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL,
CONSTRAINT "calendar_subscriptions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_calendar_subscriptions" ("color", "created_at", "feed_url", "id", "is_enabled", "last_sync_error", "last_synced_at", "name", "sync_frequency_minutes", "updated_at", "user_id") SELECT "color", "created_at", "feed_url", "id", "is_enabled", "last_sync_error", "last_synced_at", "name", "sync_frequency_minutes", "updated_at", "user_id" FROM "calendar_subscriptions";
DROP TABLE "calendar_subscriptions";
ALTER TABLE "new_calendar_subscriptions" RENAME TO "calendar_subscriptions";
CREATE INDEX "calendar_subscriptions_user_id_is_enabled_idx" ON "calendar_subscriptions"("user_id", "is_enabled");
CREATE TABLE "new_email_queue" (
"id" TEXT NOT NULL PRIMARY KEY,
"user_id" TEXT NOT NULL,
"subject" TEXT NOT NULL,
"body_html" TEXT NOT NULL,
"body_text" TEXT,
"status" TEXT NOT NULL DEFAULT 'PENDING',
"scheduled_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"attempts" INTEGER NOT NULL DEFAULT 0,
"last_attempt_at" DATETIME,
"sent_at" DATETIME,
"error_message" TEXT,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL,
CONSTRAINT "email_queue_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_email_queue" ("attempts", "body_html", "body_text", "created_at", "error_message", "id", "last_attempt_at", "scheduled_at", "sent_at", "status", "subject", "updated_at", "user_id") SELECT "attempts", "body_html", "body_text", "created_at", "error_message", "id", "last_attempt_at", "scheduled_at", "sent_at", "status", "subject", "updated_at", "user_id" FROM "email_queue";
DROP TABLE "email_queue";
ALTER TABLE "new_email_queue" RENAME TO "email_queue";
CREATE INDEX "idx_email_queue_pending_jobs" ON "email_queue"("status", "scheduled_at");
CREATE INDEX "idx_email_queue_user_history" ON "email_queue"("user_id", "created_at");
CREATE TABLE "new_external_events" (
"id" TEXT NOT NULL PRIMARY KEY,
"subscription_id" TEXT NOT NULL,
"ical_uid" TEXT NOT NULL,
"summary" TEXT,
"description" TEXT,
"start_time" DATETIME NOT NULL,
"end_time" DATETIME NOT NULL,
"is_all_day" BOOLEAN NOT NULL DEFAULT false,
"location" TEXT,
"rrule" TEXT,
"dtstamp" DATETIME,
"sequence" INTEGER,
"show_as_free" BOOLEAN NOT NULL DEFAULT false,
"last_fetched_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "external_events_subscription_id_fkey" FOREIGN KEY ("subscription_id") REFERENCES "calendar_subscriptions" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_external_events" ("description", "dtstamp", "end_time", "ical_uid", "id", "is_all_day", "last_fetched_at", "location", "rrule", "sequence", "show_as_free", "start_time", "subscription_id", "summary") SELECT "description", "dtstamp", "end_time", "ical_uid", "id", "is_all_day", "last_fetched_at", "location", "rrule", "sequence", "show_as_free", "start_time", "subscription_id", "summary" FROM "external_events";
DROP TABLE "external_events";
ALTER TABLE "new_external_events" RENAME TO "external_events";
CREATE INDEX "external_events_subscription_id_start_time_end_time_idx" ON "external_events"("subscription_id", "start_time", "end_time");
CREATE INDEX "external_events_subscription_id_show_as_free_idx" ON "external_events"("subscription_id", "show_as_free");
CREATE UNIQUE INDEX "external_events_subscription_id_ical_uid_key" ON "external_events"("subscription_id", "ical_uid");
CREATE TABLE "new_friendships" (
"user_id_1" TEXT NOT NULL,
"user_id_2" TEXT NOT NULL,
"status" TEXT NOT NULL DEFAULT 'PENDING',
"requested_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"accepted_at" DATETIME,
PRIMARY KEY ("user_id_1", "user_id_2"),
CONSTRAINT "friendships_user_id_1_fkey" FOREIGN KEY ("user_id_1") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "friendships_user_id_2_fkey" FOREIGN KEY ("user_id_2") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_friendships" ("accepted_at", "requested_at", "status", "user_id_1", "user_id_2") SELECT "accepted_at", "requested_at", "status", "user_id_1", "user_id_2" FROM "friendships";
DROP TABLE "friendships";
ALTER TABLE "new_friendships" RENAME TO "friendships";
CREATE INDEX "idx_friendships_user2_status" ON "friendships"("user_id_2", "status");
CREATE TABLE "new_group_members" (
"group_id" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"role" TEXT NOT NULL DEFAULT 'MEMBER',
"added_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ("group_id", "user_id"),
CONSTRAINT "group_members_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "groups" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "group_members_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_group_members" ("added_at", "group_id", "role", "user_id") SELECT "added_at", "group_id", "role", "user_id" FROM "group_members";
DROP TABLE "group_members";
ALTER TABLE "new_group_members" RENAME TO "group_members";
CREATE INDEX "group_members_user_id_idx" ON "group_members"("user_id");
CREATE TABLE "new_meeting_participants" (
"meeting_id" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"status" TEXT NOT NULL DEFAULT 'PENDING',
"added_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ("meeting_id", "user_id"),
CONSTRAINT "meeting_participants_meeting_id_fkey" FOREIGN KEY ("meeting_id") REFERENCES "meetings" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "meeting_participants_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_meeting_participants" ("added_at", "meeting_id", "status", "user_id") SELECT "added_at", "meeting_id", "status", "user_id" FROM "meeting_participants";
DROP TABLE "meeting_participants";
ALTER TABLE "new_meeting_participants" RENAME TO "meeting_participants";
CREATE INDEX "idx_participants_user_status" ON "meeting_participants"("user_id", "status");
CREATE TABLE "new_notifications" (
"id" TEXT NOT NULL PRIMARY KEY,
"user_id" TEXT NOT NULL,
"type" TEXT NOT NULL,
"related_entity_type" TEXT,
"related_entity_id" TEXT,
"message" TEXT NOT NULL,
"is_read" BOOLEAN NOT NULL DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "notifications_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_notifications" ("created_at", "id", "is_read", "message", "related_entity_id", "related_entity_type", "type", "user_id") SELECT "created_at", "id", "is_read", "message", "related_entity_id", "related_entity_type", "type", "user_id" FROM "notifications";
DROP TABLE "notifications";
ALTER TABLE "new_notifications" RENAME TO "notifications";
CREATE INDEX "idx_notifications_user_read_time" ON "notifications"("user_id", "is_read", "created_at");
CREATE TABLE "new_user_notification_preferences" (
"user_id" TEXT NOT NULL,
"notification_type" TEXT NOT NULL,
"email_enabled" BOOLEAN NOT NULL DEFAULT false,
"updated_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ("user_id", "notification_type"),
CONSTRAINT "user_notification_preferences_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_user_notification_preferences" ("email_enabled", "notification_type", "updated_at", "user_id") SELECT "email_enabled", "notification_type", "updated_at", "user_id" FROM "user_notification_preferences";
DROP TABLE "user_notification_preferences";
ALTER TABLE "new_user_notification_preferences" RENAME TO "user_notification_preferences";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View file

@ -8,7 +8,6 @@ import {
useDeleteApiEventEventID,
useGetApiEventEventID,
} from '@/generated/api/event/event';
import { useGetApiUserMe } from '@/generated/api/user/user';
import { RedirectButton } from '@/components/buttons/redirect-button';
import { useSession } from 'next-auth/react';
import ParticipantListEntry from '@/components/custom-ui/participant-list-entry';
@ -35,10 +34,9 @@ export default function ShowEvent() {
// Fetch event data
const { data: eventData, isLoading, error } = useGetApiEventEventID(eventID);
const { data: userData, isLoading: userLoading } = useGetApiUserMe();
const deleteEvent = useDeleteApiEventEventID();
if (isLoading || userLoading) {
if (isLoading) {
return (
<div className='flex justify-center items-center h-full'>Loading...</div>
);
@ -65,7 +63,7 @@ export default function ShowEvent() {
};
return (
<div className='flex items-center justify-center h-full'>
<div>
<Card className='w-[80%] max-w-screen p-0 gap-0 max-xl:w-[95%] mx-auto'>
<CardHeader className='p-0 m-0 gap-0' />
@ -143,7 +141,7 @@ export default function ShowEvent() {
Organiser:
</Label>
<Label size='large'>
{userData?.data.user?.name || 'Unknown User'}
{eventData.data.event.organizer.name || 'Unknown User'}
</Label>
</div>
</div>
@ -160,7 +158,7 @@ export default function ShowEvent() {
<Label className='text-[var(--color-neutral-300)] mb-2'>
Participants
</Label>{' '}
<div className='grid grid-cols-1 mt-3 sm:max-h-60 sm:grid-cols-2 sm:overflow-y-auto sm:mb-0'>
<div className='grid grid-cols-1 mt-3'>
{eventData.data.event.participants?.map((user) => (
<ParticipantListEntry
key={user.user.id}

View file

@ -25,14 +25,6 @@ export const BlockedSlotsSchema = zod
created_at: zod.date(),
updated_at: zod.date(),
})
.refine(
(data) => {
return new Date(data.start_time) < new Date(data.end_time);
},
{
message: 'Start time must be before end time',
},
)
.openapi('BlockedSlotsSchema', {
description: 'Blocked time slot in the user calendar',
});
@ -47,11 +39,37 @@ export const BlockedSlotResponseSchema = zod.object({
blocked_slot: BlockedSlotsSchema,
});
export const createBlockedSlotSchema = BlockedSlotsSchema.omit({
id: true,
created_at: true,
updated_at: true,
});
export const createBlockedSlotSchema = zod
.object({
start_time: eventStartTimeSchema,
end_time: eventEndTimeSchema,
reason: zod.string().nullish(),
})
.refine(
(data) => {
return new Date(data.start_time) < new Date(data.end_time);
},
{
message: 'Start time must be before end time',
path: ['end_time'],
},
);
export const createBlockedSlotClientSchema = zod
.object({
start_time: zod.iso.datetime({ local: true }),
end_time: zod.iso.datetime({ local: true }),
reason: zod.string().nullish(),
})
.refine(
(data) => {
return new Date(data.start_time) < new Date(data.end_time);
},
{
message: 'Start time must be before end time',
path: ['end_time'],
},
);
export const updateBlockedSlotSchema = zod.object({
start_time: eventStartTimeSchema.optional(),

View file

@ -3,7 +3,7 @@
import useZodForm from '@/lib/hooks/useZodForm';
import {
updateBlockedSlotSchema,
createBlockedSlotSchema,
createBlockedSlotClientSchema,
} from '@/app/api/blocked_slots/validation';
import {
useGetApiBlockedSlotsSlotID,
@ -40,12 +40,7 @@ export default function BlockedSlotForm({
handleSubmit: handleCreateSubmit,
formState: formStateCreate,
reset: resetCreate,
} = useZodForm(
createBlockedSlotSchema.extend({
start_time: eventStartTimeSchema.or(zod.iso.datetime({ local: true })),
end_time: eventStartTimeSchema.or(zod.iso.datetime({ local: true })),
}),
);
} = useZodForm(createBlockedSlotClientSchema);
const {
register: registerUpdate,
@ -145,100 +140,146 @@ export default function BlockedSlotForm({
});
});
return (
<div className='flex items-center justify-center h-full'>
<Card className='w-[max(80%, 500px)] max-w-screen p-0 gap-0 max-xl:w-[95%] mx-auto'>
<CardHeader className='p-0 m-0 gap-0 px-6'>
<div className='h-full mt-0 ml-2 mb-16 flex items-center justify-between max-sm:grid max-sm:grid-row-start:auto max-sm:mb-6 max-sm:mt-10 max-sm:ml-0'>
<div className='w-[100px] max-sm:w-full max-sm:flex max-sm:justify-center'>
<Logo colorType='monochrome' logoType='submark' width={50} />
if (existingBlockedSlotId)
return (
<div className='flex items-center justify-center h-full'>
<Card className='w-[max(80%, 500px)] max-w-screen p-0 gap-0 max-xl:w-[95%] mx-auto'>
<CardHeader className='p-0 m-0 gap-0 px-6'>
<div className='h-full mt-0 ml-2 mb-16 flex items-center justify-between max-sm:grid max-sm:grid-row-start:auto max-sm:mb-6 max-sm:mt-10 max-sm:ml-0'>
<div className='w-[100px] max-sm:w-full max-sm:flex max-sm:justify-center'>
<Logo colorType='monochrome' logoType='submark' width={50} />
</div>
<div className='items-center ml-auto mr-auto max-sm:mb-6 max-sm:w-full max-sm:flex max-sm:justify-center'>
<h1 className='text-center'>{'Update Blocker'}</h1>
</div>
<div className='w-0 sm:w-[100px]'></div>
</div>
<div className='items-center ml-auto mr-auto max-sm:mb-6 max-sm:w-full max-sm:flex max-sm:justify-center'>
<h1 className='text-center'>
{existingBlockedSlotId ? 'Update Blocker' : 'Create Blocker'}
</h1>
</div>
<div className='w-0 sm:w-[100px]'></div>
</div>
</CardHeader>
<CardContent>
<form
onSubmit={existingBlockedSlotId ? onUpdateSubmit : onCreateSubmit}
>
<div className='grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3'>
<LabeledInput
label='Start Time'
type='datetime-local'
id='start_time'
{...(existingBlockedSlotId
? registerUpdate('start_time')
: registerCreate('start_time'))}
error={
formStateCreate.errors.start_time?.message ||
formStateUpdate.errors.start_time?.message
}
required
/>
<LabeledInput
label='End Time'
type='datetime-local'
id='end_time'
{...(existingBlockedSlotId
? registerUpdate('end_time')
: registerCreate('end_time'))}
error={
formStateCreate.errors.end_time?.message ||
formStateUpdate.errors.end_time?.message
}
required
/>
<LabeledInput
label='Reason'
type='text'
id='reason'
{...(existingBlockedSlotId
? registerUpdate('reason')
: registerCreate('reason'))}
error={
formStateCreate.errors.reason?.message ||
formStateUpdate.errors.reason?.message
}
placeholder='Optional reason for blocking this slot'
/>
</div>
<div className='flex justify-end gap-2 p-4'>
<Button
type='submit'
variant='primary'
disabled={
formStateCreate.isSubmitting || formStateUpdate.isSubmitting
}
>
{existingBlockedSlotId ? 'Update Blocker' : 'Create Blocker'}
</Button>
{existingBlockedSlotId && (
</CardHeader>
<CardContent>
<form onSubmit={onUpdateSubmit}>
<div className='grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3'>
<LabeledInput
label='Start Time'
type='datetime-local'
id='start_time'
{...registerUpdate('start_time')}
error={formStateUpdate.errors.start_time?.message}
required
/>
<LabeledInput
label='End Time'
type='datetime-local'
id='end_time'
{...registerUpdate('end_time')}
error={formStateUpdate.errors.end_time?.message}
required
/>
<LabeledInput
label='Reason'
type='text'
id='reason'
{...registerUpdate('reason')}
error={formStateUpdate.errors.reason?.message}
placeholder='Optional reason for blocking this slot'
/>
</div>
<div className='flex justify-end gap-2 p-4'>
<Button
type='button'
variant='destructive'
onClick={onDeleteSubmit}
type='submit'
variant='primary'
disabled={formStateUpdate.isSubmitting}
>
Delete Blocker
{'Update Blocker'}
</Button>
{existingBlockedSlotId && (
<Button
type='button'
variant='destructive'
onClick={onDeleteSubmit}
>
Delete Blocker
</Button>
)}
</div>
{formStateUpdate.errors.root && (
<p className='text-red-500 text-sm mt-1'>
{formStateUpdate.errors.root.message}
</p>
)}
</form>
</CardContent>
</Card>
</div>
);
else
return (
<div className='flex items-center justify-center h-full'>
<Card className='w-[max(80%, 500px)] max-w-screen p-0 gap-0 max-xl:w-[95%] mx-auto'>
<CardHeader className='p-0 m-0 gap-0 px-6'>
<div className='h-full mt-0 ml-2 mb-16 flex items-center justify-between max-sm:grid max-sm:grid-row-start:auto max-sm:mb-6 max-sm:mt-10 max-sm:ml-0'>
<div className='w-[100px] max-sm:w-full max-sm:flex max-sm:justify-center'>
<Logo colorType='monochrome' logoType='submark' width={50} />
</div>
<div className='items-center ml-auto mr-auto max-sm:mb-6 max-sm:w-full max-sm:flex max-sm:justify-center'>
<h1 className='text-center'>{'Create Blocker'}</h1>
</div>
<div className='w-0 sm:w-[100px]'></div>
</div>
{formStateCreate.errors.root && (
<p className='text-red-500 text-sm mt-1'>
{formStateCreate.errors.root.message}
</p>
)}
{formStateUpdate.errors.root && (
<p className='text-red-500 text-sm mt-1'>
{formStateUpdate.errors.root.message}
</p>
)}
</form>
</CardContent>
</Card>
</div>
);
</CardHeader>
<CardContent>
<form onSubmit={onCreateSubmit}>
<div className='grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3'>
<LabeledInput
label='Start Time'
type='datetime-local'
id='start_time'
{...registerCreate('start_time')}
error={formStateCreate.errors.start_time?.message}
required
/>
<LabeledInput
label='End Time'
type='datetime-local'
id='end_time'
{...registerCreate('end_time')}
error={formStateCreate.errors.end_time?.message}
required
/>
<LabeledInput
label='Reason'
type='text'
id='reason'
{...registerCreate('reason')}
error={formStateCreate.errors.reason?.message}
placeholder='Optional reason for blocking this slot'
/>
</div>
<div className='flex justify-end gap-2 p-4'>
<Button
type='submit'
variant='primary'
disabled={formStateCreate.isSubmitting}
>
{'Create Blocker'}
</Button>
{existingBlockedSlotId && (
<Button
type='button'
variant='destructive'
onClick={onDeleteSubmit}
>
Delete Blocker
</Button>
)}
</div>
{formStateCreate.errors.root && (
<p className='text-red-500 text-sm mt-1'>
{formStateCreate.errors.root.message}
</p>
)}
</form>
</CardContent>
</Card>
</div>
);
}

View file

@ -5,7 +5,6 @@ import { Button } from '@/components/ui/button';
import Logo from '@/components/misc/logo';
import TimePicker from '@/components/time-picker';
import { Label } from '@/components/ui/label';
import { useGetApiUserMe } from '@/generated/api/user/user';
import {
usePostApiEvent,
useGetApiEventEventID,
@ -31,6 +30,7 @@ import {
DialogTitle,
DialogTrigger,
} from '../ui/dialog';
import { useGetApiUserMe } from '@/generated/api/user/user';
type User = zod.output<typeof PublicUserSchema>;
@ -57,10 +57,10 @@ const EventForm: React.FC<EventFormProps> = (props) => {
isSuccess,
error,
} = usePostApiEvent();
const { data, isLoading, error: fetchError } = useGetApiUserMe();
const { data: eventData } = useGetApiEventEventID(props.eventId!, {
query: { enabled: props.type === 'edit' },
});
const { data, isLoading, isError } = useGetApiUserMe();
const patchEvent = usePatchApiEventEventID();
const router = useRouter();
@ -210,8 +210,7 @@ const EventForm: React.FC<EventFormProps> = (props) => {
}, []);
if (props.type === 'edit' && isLoading) return <div>Loading...</div>;
if (props.type === 'edit' && fetchError)
return <div>Error loading event.</div>;
if (props.type === 'edit' && isError) return <div>Error loading event.</div>;
return (
<Dialog open={calendarOpen} onOpenChange={setCalendarOpen}>
@ -298,7 +297,7 @@ const EventForm: React.FC<EventFormProps> = (props) => {
<p className='text-[var(--color-neutral-300)]'>
{!isClient || isLoading
? 'Loading...'
: data?.data.user?.name || 'Unknown User'}
: data?.data.user.name || 'Unknown User'}
</p>
</div>
</div>
@ -335,7 +334,7 @@ const EventForm: React.FC<EventFormProps> = (props) => {
<DialogTrigger asChild>
<Button variant='primary'>Calendar</Button>
</DialogTrigger>
<div className='grid grid-cols-1 mt-3 sm:max-h-60 sm:grid-cols-2 sm:overflow-y-auto sm:mb-0'>
<div className='grid grid-cols-1 mt-3'>
{selectedParticipants.map((user) => (
<ParticipantListEntry
key={user.id}

View file

@ -32,7 +32,7 @@ export default function Header({
<span className='flex justify-start'>
<SidebarTrigger variant='outline_primary' size='icon' />
</span>
<span className='flex justify-center'>Search</span>
<span className='flex justify-center'></span>
<span className='flex gap-1 justify-end'>
<ThemePicker />
{items.map((item) => (

View file

@ -32,8 +32,8 @@ export default function TimePicker({
const [open, setOpen] = React.useState(false);
return (
<div className='flex gap-4' {...props}>
<div className='flex flex-col gap-3'>
<div className='grid grid-cols-2 gap-4' {...props}>
<div className='grid grid-rows-2 gap-2'>
<Label htmlFor='date' className='px-1'>
{dateLabel}
</Label>
@ -69,7 +69,7 @@ export default function TimePicker({
</PopoverContent>
</Popover>
</div>
<div className='flex flex-col gap-3'>
<div className='grid grid-rows-2 gap-2'>
<Label htmlFor='time' className='px-1'>
{timeLabel}
</Label>

View file

@ -489,10 +489,10 @@ __metadata:
languageName: node
linkType: hard
"@eslint/js@npm:9.30.0":
version: 9.30.0
resolution: "@eslint/js@npm:9.30.0"
checksum: 10c0/aec2df7f4e4e884d693dc27dbf4713c1a48afa327bfadac25ebd0e61a2797ce906f2f2a9be0d7d922acb68ccd68cc88779737811f9769eb4933d1f5e574c469e
"@eslint/js@npm:9.30.1":
version: 9.30.1
resolution: "@eslint/js@npm:9.30.1"
checksum: 10c0/17fc382a0deafdb1cadac1269d9c2f2464f025bde6e4d12fc4f4775eb9886b41340d4650b72e85a53423644fdc89bf59c987a852f27379ad25feecf2c5bbc1c9
languageName: node
linkType: hard
@ -3387,12 +3387,12 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:22.15.34":
version: 22.15.34
resolution: "@types/node@npm:22.15.34"
"@types/node@npm:22.16.0":
version: 22.16.0
resolution: "@types/node@npm:22.16.0"
dependencies:
undici-types: "npm:~6.21.0"
checksum: 10c0/fb6a6b36daaa1b484aaba3d33b4d1e7b37ea993e29f20b7a676affa76ed6ff6acd2ded4d5003469bc8dbc815b3d224533b4560896037ef6d5b5d552721ab7d57
checksum: 10c0/6219b521062f6c38d4d85ebd25807bd7f2bc703a5acba24e2c6716938d9d6cefd6fafd7b5156f61580eb58a0d82e8921751b778655675389631d813e5f261c03
languageName: node
linkType: hard
@ -4786,9 +4786,9 @@ __metadata:
languageName: node
linkType: hard
"cypress@npm:14.5.0":
version: 14.5.0
resolution: "cypress@npm:14.5.0"
"cypress@npm:14.5.1":
version: 14.5.1
resolution: "cypress@npm:14.5.1"
dependencies:
"@cypress/request": "npm:^3.0.8"
"@cypress/xvfb": "npm:^1.2.4"
@ -4836,7 +4836,7 @@ __metadata:
yauzl: "npm:^2.10.0"
bin:
cypress: bin/cypress
checksum: 10c0/b76b05c029625357fbc34f22b632c55f9f981f86c3a568a88ea3d8982b8299e4bd4275e966b2ec767f9a989c6e9059fb03a4a8086048b4e990079b1cab19ba11
checksum: 10c0/23c87cafcd2fe949af1b3297cc4c9c8f8d741f5dfa8119ff54b387227dba8dc0dbcfb2d160c4df5d4f281374524753598f3501f0fdf0b1ea66c5b8047484c0d2
languageName: node
linkType: hard
@ -5676,9 +5676,9 @@ __metadata:
languageName: node
linkType: hard
"eslint@npm:9.30.0":
version: 9.30.0
resolution: "eslint@npm:9.30.0"
"eslint@npm:9.30.1":
version: 9.30.1
resolution: "eslint@npm:9.30.1"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.2.0"
"@eslint-community/regexpp": "npm:^4.12.1"
@ -5686,7 +5686,7 @@ __metadata:
"@eslint/config-helpers": "npm:^0.3.0"
"@eslint/core": "npm:^0.14.0"
"@eslint/eslintrc": "npm:^3.3.1"
"@eslint/js": "npm:9.30.0"
"@eslint/js": "npm:9.30.1"
"@eslint/plugin-kit": "npm:^0.3.1"
"@humanfs/node": "npm:^0.16.6"
"@humanwhocodes/module-importer": "npm:^1.0.1"
@ -5722,7 +5722,7 @@ __metadata:
optional: true
bin:
eslint: bin/eslint.js
checksum: 10c0/ebc4b17cfd96f308ebaeb12dfab133a551eb03200c80109ecf663fbeb9af83c4eb3c143407c1b04522d23b5f5844fe9a629b00d409adfc460c1aadf5108da86a
checksum: 10c0/5a5867078e03ea56a1b6d1ee1548659abc38a6d5136c7ef94e21c5dbeb28e3ed50b15d2e0da25fce85600f6cf7ea7715eae650c41e8ae826c34490e9ec73d5d6
languageName: node
linkType: hard
@ -7717,7 +7717,7 @@ __metadata:
"@radix-ui/react-tooltip": "npm:^1.2.7"
"@tailwindcss/postcss": "npm:4.1.11"
"@tanstack/react-query": "npm:^5.80.7"
"@types/node": "npm:22.15.34"
"@types/node": "npm:22.16.0"
"@types/react": "npm:19.1.8"
"@types/react-big-calendar": "npm:1.16.2"
"@types/react-dom": "npm:19.1.6"
@ -7727,10 +7727,10 @@ __metadata:
class-variance-authority: "npm:^0.7.1"
clsx: "npm:^2.1.1"
cmdk: "npm:^1.1.1"
cypress: "npm:14.5.0"
cypress: "npm:14.5.1"
date-fns: "npm:^4.1.0"
dotenv-cli: "npm:8.0.0"
eslint: "npm:9.30.0"
eslint: "npm:9.30.1"
eslint-config-next: "npm:15.3.4"
eslint-config-prettier: "npm:10.1.5"
lucide-react: "npm:^0.525.0"
@ -8988,15 +8988,15 @@ __metadata:
linkType: hard
"react-day-picker@npm:^9.7.0":
version: 9.7.0
resolution: "react-day-picker@npm:9.7.0"
version: 9.8.0
resolution: "react-day-picker@npm:9.8.0"
dependencies:
"@date-fns/tz": "npm:1.2.0"
date-fns: "npm:4.1.0"
date-fns-jalali: "npm:4.1.0-0"
peerDependencies:
react: ">=16.8.0"
checksum: 10c0/c08c45a53aebceda1c938d2e4c95eb1702dcf149715e3457739f8930dce19a3be5780e5bad12dcc9d244d50b7e0efb226c336d81c1c062f616cf422e6a3804a6
checksum: 10c0/910dfbc59e9fece7f5365a2a23ed497e07f227a733289e8141b858b6ce482087df6b01f2ba4f9f7e452ebc3465af0e227f192708a673396221865df07e5ab2ac
languageName: node
linkType: hard
@ -9035,11 +9035,11 @@ __metadata:
linkType: hard
"react-hook-form@npm:^7.56.4":
version: 7.59.0
resolution: "react-hook-form@npm:7.59.0"
version: 7.60.0
resolution: "react-hook-form@npm:7.60.0"
peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19
checksum: 10c0/6be30ce65121f4be0f491c2929142e2d9a390a8802f58fb7a41ab978ab8daa6fcd2c442258dbd1b053e6864a83c8f4b1d83de9c95f0efdf5c2120d3c21bd838e
checksum: 10c0/eb8518d42a074d9e115d4b414bac18ae72708b2d047a9453dcc7588b00df300b32cebf6ecb7f2c8aa534808b3dc54bde4124af95c1e432b6691f9aba07c93b11
languageName: node
linkType: hard
@ -10214,8 +10214,8 @@ __metadata:
linkType: hard
"swagger-ui-react@npm:^5.24.1":
version: 5.25.3
resolution: "swagger-ui-react@npm:5.25.3"
version: 5.26.0
resolution: "swagger-ui-react@npm:5.26.0"
dependencies:
"@babel/runtime-corejs3": "npm:^7.27.1"
"@scarf/scarf": "npm:=1.4.0"
@ -10253,7 +10253,7 @@ __metadata:
peerDependencies:
react: ">=16.8.0 <19"
react-dom: ">=16.8.0 <19"
checksum: 10c0/9d6542d0d1bd2533e87853d4deef5507d30b35941c697d50c763428533a88cbd9c2e3abe1af5946e35aa7fa3568dc14b9da4363f09bdf6d8023e0699efceb5cf
checksum: 10c0/4ce665f46171d724050435db86ce046d5a7777b5601d4ae6b418245e1fc9792591d6cb54fc583c074855f9890ff5b0e986b0a5601f47b79cfc8377dee8a3e3cc
languageName: node
linkType: hard
@ -11314,8 +11314,8 @@ __metadata:
linkType: hard
"zod@npm:^3.25.60":
version: 3.25.67
resolution: "zod@npm:3.25.67"
checksum: 10c0/80a0cab3033272c4ab9312198081f0c4ea88e9673c059aa36dc32024906363729db54bdb78f3dc9d5529bd1601f74974d5a56c0a23e40c6f04a9270c9ff22336
version: 3.25.74
resolution: "zod@npm:3.25.74"
checksum: 10c0/59e38b046ac333b5bd1ba325a83b6798721227cbfb1e69dfc7159bd7824b904241ab923026edb714fafefec3624265ae374a70aee9a5a45b365bd31781ffa105
languageName: node
linkType: hard