@@ -66,7 +69,7 @@
+
+
+
+
+title: 'Calendar Settings'
+
+fields:
+ dayStart:
+ label: 'Day start'
+ hint: ''
+ dayEnd:
+ label: 'Day end'
+ hint: ''
+ timeInterval:
+ label: 'Time interval'
+ hint: 'How many minutes should one interval have'
+
+actions:
+ save: 'Save'
+ cancel: 'Cancel'
+
+
+
diff --git a/frontend/src/pages/campManagement/ProgramPlannerPage.vue b/frontend/src/pages/campManagement/ProgramPlannerPage.vue
index 867f2482..bd3df29c 100644
--- a/frontend/src/pages/campManagement/ProgramPlannerPage.vue
+++ b/frontend/src/pages/campManagement/ProgramPlannerPage.vue
@@ -34,6 +34,7 @@ const { data: camp } = storeToRefs(campDetailsStore);
onMounted(async () => {
await campDetailsStore.fetchData();
+ await programPlannerStore.fetchData();
});
const loading = computed
(() => {
diff --git a/frontend/src/services/ProgramEventService.ts b/frontend/src/services/ProgramEventService.ts
index e305bb0b..c86f6cbf 100644
--- a/frontend/src/services/ProgramEventService.ts
+++ b/frontend/src/services/ProgramEventService.ts
@@ -1,4 +1,8 @@
-import type { ProgramEvent } from '@camp-registration/common/entities';
+import type {
+ ProgramEvent,
+ ProgramEventCreateData,
+ ProgramEventUpdateData,
+} from '@camp-registration/common/entities';
import { api } from 'boot/axios';
export function useProgramEventService() {
@@ -21,7 +25,7 @@ export function useProgramEventService() {
async function createProgramEvent(
campId: string,
- data: ProgramEvent,
+ data: ProgramEventCreateData,
): Promise {
const response = await api.post(`camps/${campId}/program-events/`, data);
@@ -31,7 +35,7 @@ export function useProgramEventService() {
async function updateProgramEvent(
campId: string,
programEventId: string,
- data: ProgramEvent,
+ data: ProgramEventUpdateData,
): Promise {
const response = await api.put(
`camps/${campId}/program-events/${programEventId}/`,
diff --git a/frontend/src/stores/program-planner-store.ts b/frontend/src/stores/program-planner-store.ts
index d65322f4..6b9b3f6c 100644
--- a/frontend/src/stores/program-planner-store.ts
+++ b/frontend/src/stores/program-planner-store.ts
@@ -47,13 +47,17 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
const campId = route.params.camp as string;
checkNotNullWithError(campId);
+ // When we do optimistic updates, we do not know the id of the event before the requests finishes.
+ // Generate a temporary ID and replace it later
+ const tmpId = `#${crypto.randomUUID()}`;
+
asyncAction(() =>
withErrorNotification('create', async () => {
const result = await apiService.createProgramEvent(campId, event);
// Add item to data
data.value = data.value?.map((value) =>
- value.id === event.id ? result : value,
+ value.id === tmpId ? result : value,
);
return result;
@@ -62,7 +66,7 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
// Optimistic update
const tmpEvent = {
- id: `#${crypto.randomUUID()}`,
+ id: tmpId,
...event,
};
@@ -73,7 +77,7 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
return id.startsWith('#');
}
- async function updateEntry(id: string, event: ProgramEventCreateData) {
+ async function updateEntry(id: string, event: ProgramEventUpdateData) {
const campId = route.params.camp as string;
checkNotNullWithError(campId);
@@ -99,7 +103,7 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
...event,
};
data.value = data.value?.map((value) =>
- value.id === event.id ? resultEvent : value,
+ value.id === id ? resultEvent : value,
);
}
From 6642392a8bdf36095613c7c111b1d9275a89cd26 Mon Sep 17 00:00:00 2001
From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com>
Date: Fri, 8 Mar 2024 03:37:36 +0100
Subject: [PATCH 05/13] Add database migration
---
.../migration.sql | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 backend/prisma/migrations/20240208064303_add_program_events_table/migration.sql
diff --git a/backend/prisma/migrations/20240208064303_add_program_events_table/migration.sql b/backend/prisma/migrations/20240208064303_add_program_events_table/migration.sql
new file mode 100644
index 00000000..78370950
--- /dev/null
+++ b/backend/prisma/migrations/20240208064303_add_program_events_table/migration.sql
@@ -0,0 +1,19 @@
+-- CreateTable
+CREATE TABLE `program_events` (
+ `id` CHAR(26) NOT NULL,
+ `camp_id` CHAR(36) NOT NULL,
+ `title` JSON NOT NULL,
+ `details` JSON NULL,
+ `location` JSON NULL,
+ `date` VARCHAR(191) NULL,
+ `duration` INTEGER NULL,
+ `time` VARCHAR(191) NULL,
+ `background_color` VARCHAR(191) NULL,
+ `side` VARCHAR(191) NULL,
+
+ UNIQUE INDEX `program_event_id_unique`(`id`),
+ PRIMARY KEY (`id`)
+) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+-- AddForeignKey
+ALTER TABLE `program_events` ADD CONSTRAINT `program_events_camp_id_fkey` FOREIGN KEY (`camp_id`) REFERENCES `camps`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
From 994a40425eaa2dbea5866a1e4efab65dad54fb3a Mon Sep 17 00:00:00 2001
From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com>
Date: Wed, 9 Oct 2024 06:07:05 +0200
Subject: [PATCH 06/13] fix remove log
---
backend/tests/integration/camp.test.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/backend/tests/integration/camp.test.ts b/backend/tests/integration/camp.test.ts
index b7f0858f..c039f97a 100644
--- a/backend/tests/integration/camp.test.ts
+++ b/backend/tests/integration/camp.test.ts
@@ -225,8 +225,6 @@ describe('/api/v1/camps', () => {
expect(status).toBe(200);
- console.log(body.data);
-
expect(body).toHaveProperty('data');
expect(body.data.length).toBe(2);
});
From cf30bd001b0a6dcf1f54bdc0977631da649d0c31 Mon Sep 17 00:00:00 2001
From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com>
Date: Wed, 9 Oct 2024 06:08:04 +0200
Subject: [PATCH 07/13] wip: program planner
---
backend/prisma/schema.prisma | 2 +-
.../controllers/program-event.controller.ts | 6 +-
.../api/v1/camps/program-event.routes.ts | 19 +-
.../src/services/program-planner.service.ts | 8 +-
.../validations/program-event.validation.ts | 26 +-
common/src/entities/ProgramEvent.ts | 5 +-
frontend/package.json | 1 +
.../programPlanner/CalendarDayItem.vue | 2 +-
.../programPlanner/CalendarItem.vue | 37 +-
.../programPlanner/ProgramCalendar.vue | 76 +--
.../dialogs/ProgramEventAddDialog.vue | 490 ++++++++++++++++++
.../campManagement/ProgramPlannerPage.vue | 6 +-
frontend/src/stores/program-planner-store.ts | 34 +-
package-lock.json | 10 +
14 files changed, 627 insertions(+), 95 deletions(-)
create mode 100644 frontend/src/components/campManagement/programPlanner/dialogs/ProgramEventAddDialog.vue
diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma
index 77b75680..6603039a 100644
--- a/backend/prisma/schema.prisma
+++ b/backend/prisma/schema.prisma
@@ -198,7 +198,7 @@ model ProgramEvent {
date String?
duration Int?
time String?
- color String? @map("background_color")
+ color String? @map("color")
side String?
camp Camp? @relation(fields: [campId], references: [id], onDelete: Cascade)
diff --git a/backend/src/controllers/program-event.controller.ts b/backend/src/controllers/program-event.controller.ts
index 2c4d5966..c602790b 100644
--- a/backend/src/controllers/program-event.controller.ts
+++ b/backend/src/controllers/program-event.controller.ts
@@ -22,6 +22,7 @@ const index = catchRequestAsync(async (req, res) => {
const store = catchRequestAsync(async (req, res) => {
const { campId } = req.params;
const data = req.body;
+
const event = await programPlannerService.createProgramEvent(campId, {
title: data.title,
details: data.details,
@@ -36,9 +37,10 @@ const store = catchRequestAsync(async (req, res) => {
});
const update = catchRequestAsync(async (req, res) => {
- const { roomId } = req.params;
+ const { programEventId: id } = req.params;
const data = req.body;
- const event = await programPlannerService.updateProgramEventById(roomId, {
+
+ const event = await programPlannerService.updateProgramEventById(id, {
title: data.title,
details: data.details,
location: data.location,
diff --git a/backend/src/routes/api/v1/camps/program-event.routes.ts b/backend/src/routes/api/v1/camps/program-event.routes.ts
index 3a040a73..24036439 100644
--- a/backend/src/routes/api/v1/camps/program-event.routes.ts
+++ b/backend/src/routes/api/v1/camps/program-event.routes.ts
@@ -11,40 +11,45 @@ const router = express.Router({ mergeParams: true });
router.param(
'programEventId',
- catchParamAsync(async (req, res, next, id) => {
+ catchParamAsync(async (req, res, id) => {
const camp = routeModel(req.models.camp);
const event = await programPlannerService.getProgramEventById(camp.id, id);
req.models.programEvent = verifyModelExists(event);
- next();
}),
);
router.get(
'/',
auth(),
- guard([campManager]),
+ guard(campManager),
validate(programEventValidation.index),
programEventController.index,
);
router.get(
'/:programEventId',
auth(),
- guard([campManager]),
+ guard(campManager),
validate(programEventValidation.show),
programEventController.show,
);
-router.post('/', auth(), guard([campManager]), programEventController.store);
+router.post(
+ '/',
+ auth(),
+ guard(campManager),
+ validate(programEventValidation.store),
+ programEventController.store,
+);
router.put(
'/:programEventId',
auth(),
- guard([campManager]),
+ guard(campManager),
validate(programEventValidation.update),
programEventController.update,
);
router.delete(
'/:programEventId',
auth(),
- guard([campManager]),
+ guard(campManager),
validate(programEventValidation.destroy),
programEventController.destroy,
);
diff --git a/backend/src/services/program-planner.service.ts b/backend/src/services/program-planner.service.ts
index 84ec2e3c..859f1f15 100644
--- a/backend/src/services/program-planner.service.ts
+++ b/backend/src/services/program-planner.service.ts
@@ -28,12 +28,12 @@ const createProgramEvent = async (
};
const updateProgramEventById = async (
- roomId: string,
- updateBody: Omit,
+ id: string,
+ data: Omit,
) => {
return prisma.programEvent.update({
- where: { id: roomId },
- data: updateBody,
+ where: { id: id },
+ data,
});
};
diff --git a/backend/src/validations/program-event.validation.ts b/backend/src/validations/program-event.validation.ts
index cf533bcc..a6a1c769 100644
--- a/backend/src/validations/program-event.validation.ts
+++ b/backend/src/validations/program-event.validation.ts
@@ -8,7 +8,7 @@ const translatableSchema = Joi.alternatives()
.try(Joi.string(), Joi.object().pattern(Joi.string(), Joi.string()))
.required();
const timeSchema = Joi.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/);
-const dateSchema = extendedJoi.date().format('YYYY-MM-DD');
+const dateSchema = extendedJoi.date().format('YYYY-MM-DD').raw();
const show = {
params: Joi.object({
@@ -29,13 +29,13 @@ const store = {
}),
body: Joi.object({
title: translatableSchema.required(),
- details: translatableSchema.optional(),
- location: translatableSchema.optional(),
+ details: translatableSchema.optional().allow(null),
+ location: translatableSchema.optional().allow(null),
date: dateSchema.optional(),
- time: timeSchema.optional(),
- duration: Joi.number().min(0).optional(),
- color: Joi.string().required(),
- side: Joi.string().optional(),
+ time: timeSchema.optional().allow(null),
+ duration: Joi.number().min(0).optional().allow(null),
+ color: Joi.string().optional().allow(null),
+ side: Joi.string().optional().allow(null),
}),
};
@@ -46,13 +46,13 @@ const update = {
}),
body: Joi.object({
title: translatableSchema.optional(),
- details: translatableSchema.optional(),
- location: translatableSchema.optional(),
+ details: translatableSchema.optional().allow(null),
+ location: translatableSchema.optional().allow(null),
date: dateSchema.optional(),
- time: timeSchema.optional(),
- duration: Joi.number().min(0).optional(),
- color: Joi.string().optional(),
- side: Joi.string().optional(),
+ time: timeSchema.optional().allow(null),
+ duration: Joi.number().min(0).optional().allow(null),
+ color: Joi.string().optional().allow(null),
+ side: Joi.string().optional().allow(null),
}),
};
diff --git a/common/src/entities/ProgramEvent.ts b/common/src/entities/ProgramEvent.ts
index 7bd0ddac..aa1669b5 100644
--- a/common/src/entities/ProgramEvent.ts
+++ b/common/src/entities/ProgramEvent.ts
@@ -12,6 +12,9 @@ export interface ProgramEvent extends Identifiable {
side: 'left' | 'right' | 'auto' | null;
}
-export type ProgramEventCreateData = Omit;
+export type ProgramEventCreateData = Partial<
+ Omit
+> &
+ Pick;
export type ProgramEventUpdateData = Partial;
diff --git a/frontend/package.json b/frontend/package.json
index 1b0af6bb..e87d480f 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -26,6 +26,7 @@
"dependencies": {
"@camp-registration/common": "*",
"@quasar/extras": "^1.16.12",
+ "@quasar/quasar-ui-qcalendar": "^4.0.0-beta.16",
"apexcharts": "^3.50.0",
"axios": "^1.7.4",
"dom-to-image": "^2.6.0",
diff --git a/frontend/src/components/campManagement/programPlanner/CalendarDayItem.vue b/frontend/src/components/campManagement/programPlanner/CalendarDayItem.vue
index 8d05f246..480c794f 100644
--- a/frontend/src/components/campManagement/programPlanner/CalendarDayItem.vue
+++ b/frontend/src/components/campManagement/programPlanner/CalendarDayItem.vue
@@ -21,7 +21,7 @@ const props = defineProps();
const { to } = useObjectTranslation();
const backgroundColor = computed(() => {
- return props.event.backgroundColor ?? '#0000ff';
+ return props.event.color ?? '#0000ff';
});
const badgeStyles = computed(() => {
diff --git a/frontend/src/components/campManagement/programPlanner/CalendarItem.vue b/frontend/src/components/campManagement/programPlanner/CalendarItem.vue
index 503fa35c..de0a9019 100644
--- a/frontend/src/components/campManagement/programPlanner/CalendarItem.vue
+++ b/frontend/src/components/campManagement/programPlanner/CalendarItem.vue
@@ -1,13 +1,17 @@
{{ to(props.event.title) }}
-
+
{{ to(props.event.details) }}
@@ -18,6 +22,7 @@
import type { ProgramEvent } from '@camp-registration/common/entities';
import { computed, StyleValue } from 'vue';
import { useObjectTranslation } from 'src/composables/objectTranslation';
+
interface Props {
event: ProgramEvent;
timeStartPosition?: (time?: string) => number;
@@ -29,12 +34,12 @@ const props = defineProps
();
const { to } = useObjectTranslation();
const backgroundColor = computed(() => {
- return props.event.backgroundColor ?? '#0000ff';
+ return props.event.color ?? '#0000ff';
});
const badgeClasses = computed>(() => {
return {
- [`text-white bg-${props.event.backgroundColor}`]: true,
+ [`text-white bg-${props.event.color}`]: true,
'full-width': !props.event.side || props.event.side === 'auto',
'left-side': props.event.side === 'left',
'right-side': props.event.side === 'right',
@@ -43,14 +48,22 @@ const badgeClasses = computed>(() => {
});
const badgeStyles = computed(() => {
- const s: StyleValue = {};
- if (props.timeStartPosition && props.timeDurationHeight) {
- s.top = props.timeStartPosition(props.event.time) + 'px';
- s.height = props.timeDurationHeight(props.event.duration) + 'px';
- }
- s.backgroundColor = backgroundColor.value;
- s.alignItems = 'flex-start';
- return s;
+ const top =
+ props.timeStartPosition && props.event.time
+ ? props.timeStartPosition(props.event.time) + 'px'
+ : undefined;
+
+ const height =
+ props.timeDurationHeight && props.event.duration
+ ? props.timeDurationHeight(props.event.duration) + 'px'
+ : undefined;
+
+ return {
+ backgroundColor: backgroundColor.value,
+ alignItems: 'flex-start',
+ top,
+ height,
+ };
});
diff --git a/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue b/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue
index ae24baf0..a38a4fc9 100644
--- a/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue
+++ b/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue
@@ -28,6 +28,7 @@
:interval-minutes="props.timeInterval"
:interval-height="intervalHeight"
hour24-format
+ time-clicks-clamped
bordered
hoverable
animated
@@ -69,6 +70,7 @@
+
+
+
+
+title: 'Add Event'
+
+field:
+ details:
+ label: 'Details'
+ end:
+ label: 'End time'
+ rule:
+ later: 'End must be after start time'
+ fullDay:
+ label: 'Full Day'
+ location:
+ label: 'Location'
+ side:
+ left: 'Left'
+ auto: 'Auto'
+ right: 'Right'
+ start:
+ label: 'Start time'
+ title:
+ label: 'Title'
+ rule:
+ required: 'The title is required'
+
+action:
+ cancel: 'Cancel'
+ close: 'Close'
+ ok: 'Create'
+
+
+
+title: 'Ereignis hinzufügen'
+
+field:
+ details:
+ label: 'Details'
+ end:
+ label: 'Endzeit'
+ rule:
+ later: 'Das Ende muss nach der Startzeit liegen'
+ fullDay:
+ label: 'Ganztägig'
+ location:
+ label: 'Ort'
+ side:
+ left: 'Links'
+ auto: 'Automatisch'
+ right: 'Rechts'
+ start:
+ label: 'Startzeit'
+ title:
+ label: 'Titel'
+ rule:
+ required: 'Der Titel ist erforderlich'
+
+action:
+ cancel: 'Abbrechen'
+ close: 'Schließen'
+ ok: 'Erstellen'
+
+
+
+title: 'Ajouter un événement'
+
+field:
+ details:
+ label: 'Détails'
+ end:
+ label: 'Heure de fin'
+ rule:
+ later: "La fin doit être après l'heure de début"
+ fullDay:
+ label: 'Journée entière'
+ location:
+ label: 'Lieu'
+ side:
+ left: 'Gauche'
+ auto: 'Automatique'
+ right: 'Droit'
+ start:
+ label: 'Heure de début'
+ title:
+ label: 'Titre'
+ rule:
+ required: 'Le titre est requis'
+
+action:
+ cancel: 'Annuler'
+ close: 'Fermer'
+ ok: 'Créer'
+
+
+
diff --git a/frontend/src/pages/campManagement/ProgramPlannerPage.vue b/frontend/src/pages/campManagement/ProgramPlannerPage.vue
index bd3df29c..a703645b 100644
--- a/frontend/src/pages/campManagement/ProgramPlannerPage.vue
+++ b/frontend/src/pages/campManagement/ProgramPlannerPage.vue
@@ -22,8 +22,8 @@ import { useCampDetailsStore } from 'stores/camp-details-store';
import ProgramCalendar from 'components/campManagement/programPlanner/ProgramCalendar.vue';
import { storeToRefs } from 'pinia';
import type {
- ProgramEvent,
ProgramEventCreateData,
+ ProgramEventUpdateData,
} from '@camp-registration/common/entities';
import { useProgramPlannerStore } from 'stores/program-planner-store';
@@ -41,7 +41,7 @@ const loading = computed(() => {
return campDetailsStore.isLoading || programPlannerStore.isLoading;
});
-const error = computed(() => {
+const error = computed(() => {
return campDetailsStore.error ?? programPlannerStore.error;
});
@@ -49,7 +49,7 @@ function onEventAdd(event: ProgramEventCreateData) {
programPlannerStore.createEntry(event);
}
-function onEventUpdate(id: string, eventUpdate: Partial) {
+function onEventUpdate(id: string, eventUpdate: ProgramEventUpdateData) {
programPlannerStore.updateEntry(id, eventUpdate);
}
diff --git a/frontend/src/stores/program-planner-store.ts b/frontend/src/stores/program-planner-store.ts
index 6b9b3f6c..e0a8fa4f 100644
--- a/frontend/src/stores/program-planner-store.ts
+++ b/frontend/src/stores/program-planner-store.ts
@@ -22,10 +22,12 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
invalidate,
withErrorNotification,
lazyFetch,
- asyncAction,
checkNotNullWithError,
} = useServiceHandler('programPlanner');
+ // TODO Force fetch on update error after all pending requests finished
+ // --> Set loading to true while waiting
+
// TODO Add translations
authBus.on('logout', () => {
@@ -51,18 +53,16 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
// Generate a temporary ID and replace it later
const tmpId = `#${crypto.randomUUID()}`;
- asyncAction(() =>
- withErrorNotification('create', async () => {
- const result = await apiService.createProgramEvent(campId, event);
+ withErrorNotification('create', async () => {
+ const result = await apiService.createProgramEvent(campId, event);
- // Add item to data
- data.value = data.value?.map((value) =>
- value.id === tmpId ? result : value,
- );
+ // Add item to data
+ data.value = data.value?.map((value) =>
+ value.id === tmpId ? result : value,
+ );
- return result;
- }),
- );
+ return result;
+ });
// Optimistic update
const tmpEvent = {
@@ -87,10 +87,8 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
});
}
- asyncAction(() =>
- withErrorNotification('update', () =>
- apiService.updateProgramEvent(campId, id, event),
- ),
+ withErrorNotification('update', () =>
+ apiService.updateProgramEvent(campId, id, event),
);
// Optimistic update
@@ -117,10 +115,8 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
});
}
- asyncAction(() =>
- withErrorNotification('delete', () =>
- apiService.deleteProgramEvent(campId, id),
- ),
+ withErrorNotification('delete', () =>
+ apiService.deleteProgramEvent(campId, id),
);
data.value = data.value?.filter((event) => event.id === id);
diff --git a/package-lock.json b/package-lock.json
index ab8f7dd0..6e34fddc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -258,6 +258,7 @@
"dependencies": {
"@camp-registration/common": "*",
"@quasar/extras": "^1.16.12",
+ "@quasar/quasar-ui-qcalendar": "^4.0.0-beta.16",
"apexcharts": "^3.50.0",
"axios": "^1.7.4",
"dom-to-image": "^2.6.0",
@@ -2963,6 +2964,15 @@
}
}
},
+ "node_modules/@quasar/quasar-ui-qcalendar": {
+ "version": "4.0.0-beta.16",
+ "resolved": "https://registry.npmjs.org/@quasar/quasar-ui-qcalendar/-/quasar-ui-qcalendar-4.0.0-beta.16.tgz",
+ "integrity": "sha512-KVbFJD1HQp91tiklv+6XsG7bq8FKK6mhhnoVzmjgoyhUAEb9csfbDPbpegy1/FzXy3o0wITe6mmRZ8nbaiMEZg==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/hawkeye64"
+ }
+ },
"node_modules/@quasar/render-ssr-error": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@quasar/render-ssr-error/-/render-ssr-error-1.0.3.tgz",
From 3f70db88ff4c6e45ad6cf288a8eea2e755488753 Mon Sep 17 00:00:00 2001
From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com>
Date: Thu, 10 Oct 2024 05:16:32 +0200
Subject: [PATCH 08/13] wip: program planner
---
.../controllers/program-event.controller.ts | 9 +-
.../programPlanner/CalendarDayItem.vue | 28 +++-
.../programPlanner/CalendarItem.vue | 24 +++-
.../programPlanner/CalendarItemPopup.vue | 129 ++++++++++++++++++
.../programPlanner/CalendarNavigationBar.vue | 37 ++++-
.../programPlanner/ProgramCalendar.vue | 73 +++++++++-
frontend/src/stores/program-planner-store.ts | 11 +-
7 files changed, 287 insertions(+), 24 deletions(-)
create mode 100644 frontend/src/components/campManagement/programPlanner/CalendarItemPopup.vue
diff --git a/backend/src/controllers/program-event.controller.ts b/backend/src/controllers/program-event.controller.ts
index c602790b..20ed54f5 100644
--- a/backend/src/controllers/program-event.controller.ts
+++ b/backend/src/controllers/program-event.controller.ts
@@ -13,6 +13,7 @@ const show = catchRequestAsync(async (req, res) => {
const index = catchRequestAsync(async (req, res) => {
const { campId } = req.params;
+
const events = await programPlannerService.queryProgramEvent(campId);
const resources = events.map((value) => programEventResource(value));
@@ -33,6 +34,7 @@ const store = catchRequestAsync(async (req, res) => {
color: data.color,
side: data.side,
});
+
res.status(httpStatus.CREATED).json(resource(programEventResource(event)));
});
@@ -50,12 +52,15 @@ const update = catchRequestAsync(async (req, res) => {
color: data.color,
side: data.side,
});
+
res.json(resource(programEventResource(event)));
});
const destroy = catchRequestAsync(async (req, res) => {
- const { roomId } = req.params;
- await programPlannerService.deleteProgramEventById(roomId);
+ const { programEventId: id } = req.params;
+
+ await programPlannerService.deleteProgramEventById(id);
+
res.status(httpStatus.NO_CONTENT).send();
});
diff --git a/frontend/src/components/campManagement/programPlanner/CalendarDayItem.vue b/frontend/src/components/campManagement/programPlanner/CalendarDayItem.vue
index 480c794f..4d35cfe0 100644
--- a/frontend/src/components/campManagement/programPlanner/CalendarDayItem.vue
+++ b/frontend/src/components/campManagement/programPlanner/CalendarDayItem.vue
@@ -1,9 +1,17 @@
{{ to(event.title) }}
+
+
+
+
@@ -11,12 +19,16 @@
import type { ProgramEvent } from '@camp-registration/common/entities';
import { computed, StyleValue } from 'vue';
import { useObjectTranslation } from 'src/composables/objectTranslation';
+import CalendarItemPopup from 'components/campManagement/programPlanner/CalendarItemPopup.vue';
-interface Props {
+const props = defineProps<{
event: ProgramEvent;
-}
+}>();
-const props = defineProps();
+const emit = defineEmits<{
+ (e: 'edit'): void;
+ (e: 'delete'): void;
+}>();
const { to } = useObjectTranslation();
@@ -29,6 +41,14 @@ const badgeStyles = computed(() => {
backgroundColor: backgroundColor.value,
};
});
+
+function onDelete() {
+ emit('delete');
+}
+
+function onEdit() {
+ emit('edit');
+}
diff --git a/frontend/src/components/campManagement/programPlanner/CalendarItem.vue b/frontend/src/components/campManagement/programPlanner/CalendarItem.vue
index de0a9019..06728977 100644
--- a/frontend/src/components/campManagement/programPlanner/CalendarItem.vue
+++ b/frontend/src/components/campManagement/programPlanner/CalendarItem.vue
@@ -15,6 +15,12 @@
{{ to(props.event.details) }}
+
+
@@ -22,14 +28,18 @@
import type { ProgramEvent } from '@camp-registration/common/entities';
import { computed, StyleValue } from 'vue';
import { useObjectTranslation } from 'src/composables/objectTranslation';
+import CalendarItemPopup from 'components/campManagement/programPlanner/CalendarItemPopup.vue';
-interface Props {
+const props = defineProps<{
event: ProgramEvent;
timeStartPosition?: (time?: string) => number;
timeDurationHeight?: (duration?: number) => number;
-}
+}>();
-const props = defineProps();
+const emit = defineEmits<{
+ (e: 'edit'): void;
+ (e: 'delete'): void;
+}>();
const { to } = useObjectTranslation();
@@ -65,6 +75,14 @@ const badgeStyles = computed(() => {
height,
};
});
+
+function onDelete() {
+ emit('delete');
+}
+
+function onEdit() {
+ emit('edit');
+}
diff --git a/frontend/src/components/campManagement/programPlanner/CalendarNavigationBar.vue b/frontend/src/components/campManagement/programPlanner/CalendarNavigationBar.vue
index 4d9dbd6b..f37fc55d 100644
--- a/frontend/src/components/campManagement/programPlanner/CalendarNavigationBar.vue
+++ b/frontend/src/components/campManagement/programPlanner/CalendarNavigationBar.vue
@@ -5,12 +5,14 @@
();
const emit = defineEmits<{
- (e: 'update:modelValue', val: number);
+ (e: 'update:modelValue', val: number): void;
(e: 'next'): void;
(e: 'previous'): void;
}>();
onMounted(() => {
- daysRange.value = maxDays.value;
+ if (daysRange.value > maxDays.value) {
+ daysRange.value = maxDays.value;
+ }
});
-const daysRange = computed({
+const daysRange = computed({
get: () => props.modelValue,
- set: (val: number) => emit('update:modelValue', val),
+ set: (val) => emit('update:modelValue', val),
+});
+
+const prevDisabled = computed(() => {
+ const startDate = new Date(props.start);
+ startDate.setHours(0, 0);
+ const currentDate = new Date(props.current);
+
+ return startDate.getTime() >= currentDate.getTime();
+});
+
+const DAY_IN_MY = 24 * 60 * 60 * 1000;
+const nextDisabled = computed(() => {
+ const endDate = new Date(props.end);
+ endDate.setHours(0, 0);
+ const currentDate = new Date(props.current);
+
+ return (
+ endDate.getTime() <=
+ currentDate.getTime() + (daysRange.value - 1) * DAY_IN_MY
+ );
});
function next() {
diff --git a/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue b/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue
index a38a4fc9..af0ba782 100644
--- a/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue
+++ b/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue
@@ -1,10 +1,14 @@
-
+
@@ -13,7 +17,7 @@
@@ -62,6 +68,8 @@
:time-duration-height="timeDurationHeight"
:draggable="true"
@dragstart="onDragStart($event, event)"
+ @edit="onEventEdit(event)"
+ @delete="onEventDelete(event)"
/>
@@ -111,9 +119,9 @@ const emit = defineEmits<{
const { t, locale } = useI18n();
const quasar = useQuasar();
+const calendarRef = ref
(null);
const selectedDate = ref(initialSelectedDate());
-
-const range = ref(1);
+const range = ref(initialRange());
onMounted(() => {
// TODO Find better solution
@@ -162,8 +170,22 @@ function updateIntervalHeight() {
intervalHeight.value = height / intervalCount.value;
}
+function initialRange(): number {
+ switch (quasar.screen.name) {
+ case 'xs':
+ return 1;
+ case 'sm':
+ return 3;
+ case 'md':
+ return 5;
+ case 'lg':
+ case 'xl':
+ return 7;
+ }
+}
+
function initialSelectedDate(): string {
- return props.camp.startAt.split('T')[0];
+ return formatDate(new Date(props.camp.startAt));
}
const eventsMap = computed>(() => {
@@ -235,6 +257,15 @@ function onTimeEventAdd({ scope }: CalendarEvent) {
});
}
+function onEventEdit(event: ProgramEvent) {
+ // TODO
+}
+
+function onEventDelete(event: ProgramEvent) {
+ // TODO Maybe add conform
+ emit('delete', event.id);
+}
+
function onDragStart(e: DragEvent, event: ProgramEvent): void {
if (!e.dataTransfer) {
return;
@@ -298,12 +329,14 @@ function onDrop(e: DragEvent, type: string, scope: DragAndDropScope): boolean {
eventUpdate = {
date: scope.timestamp.date,
time: null,
+ duration: null,
};
break;
default:
eventUpdate = {
date: null,
time: null,
+ duration: null,
};
}
@@ -324,12 +357,38 @@ function onWeekdayClass({ scope }: { scope: DragAndDropScope }) {
};
}
+const DAY_IN_MY = 24 * 60 * 60 * 1000;
+
function onNextNavigation() {
- // TODO How to shift
+ const endDate = new Date(props.camp.endAt);
+ endDate.setHours(0, 0);
+
+ const endTime = endDate.getTime();
+ const currentTime = new Date(selectedDate.value).getTime();
+
+ const rangeTime = range.value * DAY_IN_MY;
+ const maxTime = endTime - (rangeTime - DAY_IN_MY);
+ const updateMs = Math.min(maxTime, currentTime + rangeTime);
+
+ selectedDate.value = formatDate(new Date(updateMs));
}
function onPreciousNavigation() {
- // TODO How to shift
+ const startDate = new Date(props.camp.startAt);
+ startDate.setHours(0, 0);
+
+ const startTime = startDate.getTime();
+ const currentTime = new Date(selectedDate.value).getTime();
+
+ const rangeTime = range.value * DAY_IN_MY;
+ const minTime = currentTime - rangeTime;
+ const updateMs = Math.max(startTime, minTime);
+
+ selectedDate.value = formatDate(new Date(updateMs));
+}
+
+function formatDate(date: Date): string {
+ return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
}
diff --git a/frontend/src/stores/program-planner-store.ts b/frontend/src/stores/program-planner-store.ts
index e0a8fa4f..25e4b5bc 100644
--- a/frontend/src/stores/program-planner-store.ts
+++ b/frontend/src/stores/program-planner-store.ts
@@ -65,9 +65,16 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
});
// Optimistic update
- const tmpEvent = {
+ const tmpEvent: ProgramEvent = {
id: tmpId,
...event,
+ details: event.details ?? null,
+ location: event.location ?? null,
+ date: event.date ?? null,
+ time: event.time ?? null,
+ duration: event.duration ?? null,
+ color: event.color ?? null,
+ side: event.side ?? null,
};
data.value?.push(tmpEvent);
@@ -119,7 +126,7 @@ export const useProgramPlannerStore = defineStore('program-planner', () => {
apiService.deleteProgramEvent(campId, id),
);
- data.value = data.value?.filter((event) => event.id === id);
+ data.value = data.value?.filter((event) => event.id !== id);
}
return {
From 78d6705b23335db80c252f29538500c5750b9dec Mon Sep 17 00:00:00 2001
From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com>
Date: Sat, 12 Oct 2024 05:43:15 +0200
Subject: [PATCH 09/13] feat: Accept null for empty translated input
---
.../common/inputs/TranslatedInput.vue | 24 ++++++++++++-------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/frontend/src/components/common/inputs/TranslatedInput.vue b/frontend/src/components/common/inputs/TranslatedInput.vue
index 223f9ec5..95a81cc6 100644
--- a/frontend/src/components/common/inputs/TranslatedInput.vue
+++ b/frontend/src/components/common/inputs/TranslatedInput.vue
@@ -95,8 +95,10 @@ type Translations = Record;
const { t } = useI18n();
+type ModelValue = Translations | string | number | undefined | null;
+
interface Props {
- modelValue: undefined | string | number | Translations;
+ modelValue: ModelValue;
modelModifiers?: Record;
label?: string;
locales?: string[];
@@ -106,14 +108,12 @@ interface Props {
const props = withDefaults(defineProps(), {
modelModifiers: undefined,
label: '',
- locales: undefined, // TODO Why cant I make it an empty array?
+ locales: undefined,
always: false,
});
+
const emit = defineEmits<{
- (
- e: 'update:modelValue',
- value: string | number | Translations | undefined,
- ): void;
+ (e: 'update:modelValue', value: ModelValue): void;
}>();
const useTranslations = ref(defaultUseTranslations());
@@ -131,7 +131,11 @@ function defaultUseTranslations(): boolean {
function defaultValue(): string | number {
// If the model value if an object and there is only one locale, we assume that the object is a translation and
// contains a translation for the given locale
- if (props.locales?.length === 1 && typeof props.modelValue === 'object') {
+ if (
+ props.locales?.length === 1 &&
+ props.modelValue &&
+ typeof props.modelValue === 'object'
+ ) {
return props.modelValue[props.locales[0]];
}
@@ -142,7 +146,9 @@ function defaultValue(): string | number {
}
function defaultTranslations(): Translations {
- return typeof props.modelValue === 'object' ? props.modelValue : {};
+ return props.modelValue && typeof props.modelValue === 'object'
+ ? props.modelValue
+ : {};
}
watch(
@@ -167,7 +173,7 @@ watch(
if (typeof newValue === 'string' || typeof newValue === 'number') {
value.value = newValue;
useTranslations.value = false;
- } else if (typeof newValue === 'object') {
+ } else if (newValue && typeof newValue === 'object') {
translations.value = newValue;
useTranslations.value = true;
}
From 1b85e8e87b390085b0a0783a0dc269cf97382b8c Mon Sep 17 00:00:00 2001
From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com>
Date: Sat, 12 Oct 2024 05:44:40 +0200
Subject: [PATCH 10/13] wip: Add program event edit dialog
---
.../programPlanner/CalendarItemPopup.vue | 1 +
.../programPlanner/ProgramCalendar.vue | 23 +-
.../dialogs/ProgramEventEditDialog.vue | 495 ++++++++++++++++++
.../ProgramEventModificationDialog.vue | 129 -----
4 files changed, 512 insertions(+), 136 deletions(-)
create mode 100644 frontend/src/components/campManagement/programPlanner/dialogs/ProgramEventEditDialog.vue
delete mode 100644 frontend/src/components/campManagement/programPlanner/dialogs/ProgramEventModificationDialog.vue
diff --git a/frontend/src/components/campManagement/programPlanner/CalendarItemPopup.vue b/frontend/src/components/campManagement/programPlanner/CalendarItemPopup.vue
index 364ea01c..4689c676 100644
--- a/frontend/src/components/campManagement/programPlanner/CalendarItemPopup.vue
+++ b/frontend/src/components/campManagement/programPlanner/CalendarItemPopup.vue
@@ -12,6 +12,7 @@
size="sm"
flat
rounded
+ @click="onEdit"
/>
();
-const { t, locale } = useI18n();
+const { locale } = useI18n();
const quasar = useQuasar();
const calendarRef = ref(null);
@@ -211,11 +213,7 @@ function getFullDayEvents(date: string) {
}
function getEvents(date: string) {
- const events = eventsMap.value[date] || [];
-
- // TODO Apply side when side is auto
-
- return events;
+ return eventsMap.value[date] || [];
}
interface CalendarEvent {
@@ -258,7 +256,18 @@ function onTimeEventAdd({ scope }: CalendarEvent) {
}
function onEventEdit(event: ProgramEvent) {
- // TODO
+ quasar
+ .dialog({
+ component: ProgramEventEditDialog,
+ componentProps: {
+ event,
+ dateTimeMin: props.camp.startAt,
+ dateTimeMax: props.camp.endAt,
+ },
+ })
+ .onOk((programEvent: ProgramEventCreateData) => {
+ emit('update', event.id, programEvent);
+ });
}
function onEventDelete(event: ProgramEvent) {
diff --git a/frontend/src/components/campManagement/programPlanner/dialogs/ProgramEventEditDialog.vue b/frontend/src/components/campManagement/programPlanner/dialogs/ProgramEventEditDialog.vue
new file mode 100644
index 00000000..3215296e
--- /dev/null
+++ b/frontend/src/components/campManagement/programPlanner/dialogs/ProgramEventEditDialog.vue
@@ -0,0 +1,495 @@
+
+
+
+
+
+
+ {{ t('title') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+title: 'Edit Event'
+
+field:
+ details:
+ label: 'Details'
+ end:
+ label: 'End time'
+ rule:
+ later: 'End must be after start time'
+ fullDay:
+ label: 'Full Day'
+ location:
+ label: 'Location'
+ side:
+ left: 'Left'
+ auto: 'Auto'
+ right: 'Right'
+ start:
+ label: 'Start time'
+ title:
+ label: 'Title'
+ rule:
+ required: 'The title is required'
+
+action:
+ cancel: 'Cancel'
+ close: 'Close'
+ ok: 'Save'
+
+
+
+title: 'Ereignis bearbeiten'
+
+field:
+ details:
+ label: 'Details'
+ end:
+ label: 'Endzeit'
+ rule:
+ later: 'Das Ende muss nach der Startzeit liegen'
+ fullDay:
+ label: 'Ganztägig'
+ location:
+ label: 'Ort'
+ side:
+ left: 'Links'
+ auto: 'Automatisch'
+ right: 'Rechts'
+ start:
+ label: 'Startzeit'
+ title:
+ label: 'Titel'
+ rule:
+ required: 'Der Titel ist erforderlich'
+
+action:
+ cancel: 'Abbrechen'
+ close: 'Schließen'
+ ok: 'Speichern'
+
+
+
+title: "Modifier l'événement"
+
+field:
+ details:
+ label: 'Détails'
+ end:
+ label: 'Heure de fin'
+ rule:
+ later: "La fin doit être après l'heure de début"
+ fullDay:
+ label: 'Journée entière'
+ location:
+ label: 'Lieu'
+ side:
+ left: 'Gauche'
+ auto: 'Automatique'
+ right: 'Droit'
+ start:
+ label: 'Heure de début'
+ title:
+ label: 'Titre'
+ rule:
+ required: 'Le titre est requis'
+
+action:
+ cancel: 'Annuler'
+ close: 'Fermer'
+ ok: 'Enregistrer'
+
+
+
diff --git a/frontend/src/components/campManagement/programPlanner/dialogs/ProgramEventModificationDialog.vue b/frontend/src/components/campManagement/programPlanner/dialogs/ProgramEventModificationDialog.vue
deleted file mode 100644
index b56b3938..00000000
--- a/frontend/src/components/campManagement/programPlanner/dialogs/ProgramEventModificationDialog.vue
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
-
-
-
-
- {{ t('title') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-title: 'Calendar Settings'
-
-fields:
- dayStart:
- label: 'Day start'
- hint: ''
- dayEnd:
- label: 'Day end'
- hint: ''
- timeInterval:
- label: 'Time interval'
- hint: 'How many minutes should one interval have'
-
-actions:
- save: 'Save'
- cancel: 'Cancel'
-
-
-
From 6e9f6e1acc7119bc02777a42a020b2ce4acba44d Mon Sep 17 00:00:00 2001
From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com>
Date: Sat, 12 Oct 2024 05:44:57 +0200
Subject: [PATCH 11/13] fix: Accept empty string
---
backend/src/validations/program-event.validation.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/src/validations/program-event.validation.ts b/backend/src/validations/program-event.validation.ts
index a6a1c769..061008e0 100644
--- a/backend/src/validations/program-event.validation.ts
+++ b/backend/src/validations/program-event.validation.ts
@@ -6,7 +6,7 @@ const extendedJoi = Joi.extend(JoiDate);
const translatableSchema = Joi.alternatives()
.try(Joi.string(), Joi.object().pattern(Joi.string(), Joi.string()))
- .required();
+ .allow('');
const timeSchema = Joi.string().regex(/^([01]\d|2[0-3]):([0-5]\d)$/);
const dateSchema = extendedJoi.date().format('YYYY-MM-DD').raw();
From 3db3e328f99512d4bd28ba2a8180a7854b7882f2 Mon Sep 17 00:00:00 2001
From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com>
Date: Sat, 12 Oct 2024 05:50:35 +0200
Subject: [PATCH 12/13] fix lint errors
---
.../campManagement/programPlanner/ProgramCalendar.vue | 1 -
frontend/src/stores/room-planner-store.ts | 4 ++--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue b/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue
index dd4c1436..f05acb9f 100644
--- a/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue
+++ b/frontend/src/components/campManagement/programPlanner/ProgramCalendar.vue
@@ -94,7 +94,6 @@ import CalendarNavigationBar from 'components/campManagement/programPlanner/Cale
import CalendarItem from 'components/campManagement/programPlanner/CalendarItem.vue';
import CalendarDayItem from 'components/campManagement/programPlanner/CalendarDayItem.vue';
import { DragAndDropScope } from 'components/campManagement/programPlanner/DragAndDropScope';
-import PointerEvent from 'happy-dom/lib/event/events/PointerEvent';
import ProgramEventAddDialog from 'components/campManagement/programPlanner/dialogs/ProgramEventAddDialog.vue';
import ProgramEventEditDialog from 'components/campManagement/programPlanner/dialogs/ProgramEventEditDialog.vue';
diff --git a/frontend/src/stores/room-planner-store.ts b/frontend/src/stores/room-planner-store.ts
index 7955892e..e81a66ba 100644
--- a/frontend/src/stores/room-planner-store.ts
+++ b/frontend/src/stores/room-planner-store.ts
@@ -31,7 +31,7 @@ export const useRoomPlannerStore = defineStore('room-planner', () => {
withProgressNotification,
withErrorNotification,
lazyFetch,
- asyncAction,
+ asyncUpdate,
requestPending,
checkNotNullWithError,
checkNotNullWithNotification,
@@ -125,7 +125,7 @@ export const useRoomPlannerStore = defineStore('room-planner', () => {
const bedId = room.beds[position].id;
const registrationId = person?.id ?? null;
- asyncAction(() => {
+ asyncUpdate(() => {
return withErrorNotification('update-bed', () => {
return apiService.updateBed(campId, roomId, bedId, registrationId);
});
From 9c7e3cbb8c98c4cbaa61ad711c1ce13e4d37e3ab Mon Sep 17 00:00:00 2001
From: marvin-wtt <31454580+marvin-wtt@users.noreply.github.com>
Date: Mon, 14 Oct 2024 07:49:06 +0200
Subject: [PATCH 13/13] Merge main into feat/program-planner
---
backend/src/app/camp/camp.routes.ts | 2 ++
.../programEvent}/program-event.controller.ts | 14 +++++++-------
.../programEvent}/program-event.resource.ts | 0
.../{camp => programEvent}/program-event.routes.ts | 6 +++---
.../programEvent/program-event.service.ts} | 0
.../programEvent}/program-event.validation.ts | 0
backend/src/controllers/index.ts | 0
backend/src/resources/index.ts | 0
backend/src/routes/api/v1/camps/index.ts | 0
backend/src/services/index.ts | 0
backend/src/validations/index.ts | 0
11 files changed, 12 insertions(+), 10 deletions(-)
rename backend/src/{controllers => app/programEvent}/program-event.controller.ts (77%)
rename backend/src/{resources => app/programEvent}/program-event.resource.ts (100%)
rename backend/src/app/{camp => programEvent}/program-event.routes.ts (87%)
rename backend/src/{services/program-planner.service.ts => app/programEvent/program-event.service.ts} (100%)
rename backend/src/{validations => app/programEvent}/program-event.validation.ts (100%)
delete mode 100644 backend/src/controllers/index.ts
delete mode 100644 backend/src/resources/index.ts
delete mode 100644 backend/src/routes/api/v1/camps/index.ts
delete mode 100644 backend/src/services/index.ts
delete mode 100644 backend/src/validations/index.ts
diff --git a/backend/src/app/camp/camp.routes.ts b/backend/src/app/camp/camp.routes.ts
index d4e49dfa..43f88eca 100644
--- a/backend/src/app/camp/camp.routes.ts
+++ b/backend/src/app/camp/camp.routes.ts
@@ -13,6 +13,7 @@ import registrationRoutes from 'app/registration/registration.routes';
import tableTemplateRoutes from 'app/tableTemplate/table-template.routes';
import roomRoutes from 'app/room/room.routes';
import campFileRoutes from './camp-files.routes';
+import programEventRoutes from 'app/programEvent/program-event.routes';
import { CampCreateData, CampQuery } from '@camp-registration/common/entities';
const router = express.Router();
@@ -51,6 +52,7 @@ router.use('/:campId/templates', tableTemplateRoutes);
router.use('/:campId/managers', managerRoutes);
router.use('/:campId/rooms', roomRoutes);
router.use('/:campId/files', campFileRoutes);
+router.use('/:campId/program-events', programEventRoutes);
router.get(
'/',
diff --git a/backend/src/controllers/program-event.controller.ts b/backend/src/app/programEvent/program-event.controller.ts
similarity index 77%
rename from backend/src/controllers/program-event.controller.ts
rename to backend/src/app/programEvent/program-event.controller.ts
index 20ed54f5..6bdcc1ee 100644
--- a/backend/src/controllers/program-event.controller.ts
+++ b/backend/src/app/programEvent/program-event.controller.ts
@@ -1,8 +1,8 @@
import { catchRequestAsync } from 'utils/catchAsync';
import httpStatus from 'http-status';
-import { collection, resource } from 'resources/resource';
-import { programPlannerService } from 'services';
-import { programEventResource } from 'resources';
+import { collection, resource } from 'app/resource';
+import programEventService from './program-event.service';
+import programEventResource from './program-event.resource';
import { routeModel } from 'utils/verifyModel';
const show = catchRequestAsync(async (req, res) => {
@@ -14,7 +14,7 @@ const show = catchRequestAsync(async (req, res) => {
const index = catchRequestAsync(async (req, res) => {
const { campId } = req.params;
- const events = await programPlannerService.queryProgramEvent(campId);
+ const events = await programEventService.queryProgramEvent(campId);
const resources = events.map((value) => programEventResource(value));
res.json(collection(resources));
@@ -24,7 +24,7 @@ const store = catchRequestAsync(async (req, res) => {
const { campId } = req.params;
const data = req.body;
- const event = await programPlannerService.createProgramEvent(campId, {
+ const event = await programEventService.createProgramEvent(campId, {
title: data.title,
details: data.details,
location: data.location,
@@ -42,7 +42,7 @@ const update = catchRequestAsync(async (req, res) => {
const { programEventId: id } = req.params;
const data = req.body;
- const event = await programPlannerService.updateProgramEventById(id, {
+ const event = await programEventService.updateProgramEventById(id, {
title: data.title,
details: data.details,
location: data.location,
@@ -59,7 +59,7 @@ const update = catchRequestAsync(async (req, res) => {
const destroy = catchRequestAsync(async (req, res) => {
const { programEventId: id } = req.params;
- await programPlannerService.deleteProgramEventById(id);
+ await programEventService.deleteProgramEventById(id);
res.status(httpStatus.NO_CONTENT).send();
});
diff --git a/backend/src/resources/program-event.resource.ts b/backend/src/app/programEvent/program-event.resource.ts
similarity index 100%
rename from backend/src/resources/program-event.resource.ts
rename to backend/src/app/programEvent/program-event.resource.ts
diff --git a/backend/src/app/camp/program-event.routes.ts b/backend/src/app/programEvent/program-event.routes.ts
similarity index 87%
rename from backend/src/app/camp/program-event.routes.ts
rename to backend/src/app/programEvent/program-event.routes.ts
index 24036439..78d4a1a1 100644
--- a/backend/src/app/camp/program-event.routes.ts
+++ b/backend/src/app/programEvent/program-event.routes.ts
@@ -3,9 +3,9 @@ import { auth, guard, validate } from 'middlewares';
import { campManager } from 'guards';
import { routeModel, verifyModelExists } from 'utils/verifyModel';
import { catchParamAsync } from 'utils/catchAsync';
-import { programPlannerService } from 'services';
-import { programEventController } from 'controllers';
-import { programEventValidation } from 'validations';
+import programPlannerService from './program-event.service';
+import programEventController from './program-event.controller';
+import programEventValidation from './program-event.validation';
const router = express.Router({ mergeParams: true });
diff --git a/backend/src/services/program-planner.service.ts b/backend/src/app/programEvent/program-event.service.ts
similarity index 100%
rename from backend/src/services/program-planner.service.ts
rename to backend/src/app/programEvent/program-event.service.ts
diff --git a/backend/src/validations/program-event.validation.ts b/backend/src/app/programEvent/program-event.validation.ts
similarity index 100%
rename from backend/src/validations/program-event.validation.ts
rename to backend/src/app/programEvent/program-event.validation.ts
diff --git a/backend/src/controllers/index.ts b/backend/src/controllers/index.ts
deleted file mode 100644
index e69de29b..00000000
diff --git a/backend/src/resources/index.ts b/backend/src/resources/index.ts
deleted file mode 100644
index e69de29b..00000000
diff --git a/backend/src/routes/api/v1/camps/index.ts b/backend/src/routes/api/v1/camps/index.ts
deleted file mode 100644
index e69de29b..00000000
diff --git a/backend/src/services/index.ts b/backend/src/services/index.ts
deleted file mode 100644
index e69de29b..00000000
diff --git a/backend/src/validations/index.ts b/backend/src/validations/index.ts
deleted file mode 100644
index e69de29b..00000000