From ed2584d0abe609d3ac1f9e5fab538af8e75be44b Mon Sep 17 00:00:00 2001 From: Felix Ruf Date: Wed, 7 Aug 2024 17:12:44 +0200 Subject: [PATCH 1/4] added check for max meals in backend --- .../Repository/ParticipantRepository.php | 15 +++++++++++++++ .../Repository/ParticipantRepositoryInterface.php | 5 +++++ .../MealBundle/Service/ParticipationService.php | 4 ++++ .../src/components/dashboard/CombiButtonGroup.vue | 6 +++--- .../src/components/dashboard/CombiModal.vue | 9 ++++++--- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/Mealz/MealBundle/Repository/ParticipantRepository.php b/src/Mealz/MealBundle/Repository/ParticipantRepository.php index 8ffa4435b..7f471bcb6 100644 --- a/src/Mealz/MealBundle/Repository/ParticipantRepository.php +++ b/src/Mealz/MealBundle/Repository/ParticipantRepository.php @@ -535,4 +535,19 @@ public function getParticipationsOfSlot(Slot $slot): array return $participations; } + + public function getParticipationCountByProfile(Profile $profile, DateTime $date): int + { + $queryBuilder = $this->createQueryBuilder('p') + ->select('p.id') + ->join('p.meal', 'm') + ->where('p.profile = :profile') + ->andWhere('m.dateTime = :day') + ->setParameter('profile' , $profile->getUsername()) + ->setParameter('day', $date, Types::DATE_MUTABLE); + + $participations = $queryBuilder->getQuery()->getArrayResult(); + + return count($participations); + } } diff --git a/src/Mealz/MealBundle/Repository/ParticipantRepositoryInterface.php b/src/Mealz/MealBundle/Repository/ParticipantRepositoryInterface.php index 57e15193a..8f2aeef86 100644 --- a/src/Mealz/MealBundle/Repository/ParticipantRepositoryInterface.php +++ b/src/Mealz/MealBundle/Repository/ParticipantRepositoryInterface.php @@ -95,4 +95,9 @@ public function removeFutureMealsByProfile(Profile $profile): void; * Returns an array of all the participations for a given slot starting from the current week. */ public function getParticipationsOfSlot(Slot $slot): array; + + /** + * Returns the number of participations a profile has on a date. + */ + public function getParticipationCountByProfile(Profile $profile, DateTime $date): int; } diff --git a/src/Mealz/MealBundle/Service/ParticipationService.php b/src/Mealz/MealBundle/Service/ParticipationService.php index f6b0c8291..0eceaf2af 100644 --- a/src/Mealz/MealBundle/Service/ParticipationService.php +++ b/src/Mealz/MealBundle/Service/ParticipationService.php @@ -50,6 +50,10 @@ public function __construct( */ public function join(Profile $profile, Meal $meal, ?Slot $slot = null, array $dishSlugs = []): ?array { + if (2 <= $this->participantRepo->getParticipationCountByProfile($profile, $meal->getDateTime())) { + return null; + } + // user is attempting to take over an already booked meal by some participant if (true === $this->mealIsOffered($meal) && true === $this->allowedToAccept($meal)) { return $this->reassignOfferedMeal($meal, $profile, $dishSlugs); diff --git a/src/Resources/src/components/dashboard/CombiButtonGroup.vue b/src/Resources/src/components/dashboard/CombiButtonGroup.vue index d1a8dd423..418c3b00e 100644 --- a/src/Resources/src/components/dashboard/CombiButtonGroup.vue +++ b/src/Resources/src/components/dashboard/CombiButtonGroup.vue @@ -64,13 +64,13 @@ interface DishInfo { } const props = defineProps<{ - weekID: number | string; - dayID: number | string; + weekID?: number | string; + dayID?: number | string; mealID: number | string; meal: Meal; }>(); -const meal = props.meal ?? dashboardStore.getMeal(props.weekID, props.dayID, props.mealID); +const meal = props.meal ?? dashboardStore.getMeal(props.weekID ?? -1, props.dayID ?? -1, props.mealID); const emit = defineEmits(['addEntry', 'removeEntry']); const selected = ref(); let dishes: DishInfo[] = []; diff --git a/src/Resources/src/components/dashboard/CombiModal.vue b/src/Resources/src/components/dashboard/CombiModal.vue index af9f1b647..a0bf14b28 100644 --- a/src/Resources/src/components/dashboard/CombiModal.vue +++ b/src/Resources/src/components/dashboard/CombiModal.vue @@ -48,7 +48,6 @@ class="mt-2 grid" > meals[mealID].dishSlug !== 'combined-dish'); +const keys = computed(() => Object.keys(meals).filter((mealID) => meals[mealID].dishSlug !== 'combined-dish')); const slugs = ref([]); const bookingDisabled = computed(() => slugs.value.length < 2); +onMounted(() => { + console.log(`open(${props.open}), weekId(${props.weekID}), dayID(${props.dayID}), \nMeals: ${JSON.stringify(Object.keys(props.meals))}`); +}) + function resolveModal(mode: string) { if (mode === 'cancel') { slugs.value = []; From 3e5275393912a171538b6dd2f947547207a9f268 Mon Sep 17 00:00:00 2001 From: Felix Ruf Date: Thu, 8 Aug 2024 14:09:02 +0200 Subject: [PATCH 2/4] added verification in guest component and added flashmessage to inform users when they exceed the max number of meals per day --- .../Repository/ParticipantRepository.php | 8 +- .../src/components/dashboard/CombiModal.vue | 6 +- .../src/components/dashboard/Day.vue | 14 ++++ .../src/components/guest/GuestCheckbox.vue | 75 +++++++++++++++---- .../src/components/guest/GuestDay.vue | 4 + .../src/components/guest/GuestMeal.vue | 4 +- .../src/components/guest/GuestVariation.vue | 5 +- src/Resources/src/locales/de.json | 3 + src/Resources/src/locales/en.json | 3 + src/Resources/src/views/Guest.vue | 17 ++++- 10 files changed, 110 insertions(+), 29 deletions(-) diff --git a/src/Mealz/MealBundle/Repository/ParticipantRepository.php b/src/Mealz/MealBundle/Repository/ParticipantRepository.php index 7f471bcb6..3bf3d4c66 100644 --- a/src/Mealz/MealBundle/Repository/ParticipantRepository.php +++ b/src/Mealz/MealBundle/Repository/ParticipantRepository.php @@ -540,13 +540,13 @@ public function getParticipationCountByProfile(Profile $profile, DateTime $date) { $queryBuilder = $this->createQueryBuilder('p') ->select('p.id') - ->join('p.meal', 'm') + ->join('p.meal', 'm', 'ON') ->where('p.profile = :profile') ->andWhere('m.dateTime = :day') - ->setParameter('profile' , $profile->getUsername()) - ->setParameter('day', $date, Types::DATE_MUTABLE); + ->setParameter('profile', $profile->getUsername()) + ->setParameter('day', $date->format('Y-m-d H:i:s.u')); - $participations = $queryBuilder->getQuery()->getArrayResult(); + $participations = $queryBuilder->getQuery()->execute(); return count($participations); } diff --git a/src/Resources/src/components/dashboard/CombiModal.vue b/src/Resources/src/components/dashboard/CombiModal.vue index a0bf14b28..1e191d67e 100644 --- a/src/Resources/src/components/dashboard/CombiModal.vue +++ b/src/Resources/src/components/dashboard/CombiModal.vue @@ -89,7 +89,7 @@ import { Dialog, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'; import CombiButtonGroup from '@/components/dashboard/CombiButtonGroup.vue'; import { dashboardStore } from '@/stores/dashboardStore'; -import { computed, onMounted, ref } from 'vue'; +import { computed, ref } from 'vue'; import { useI18n } from 'vue-i18n'; import { type Meal } from '@/api/getDashboardData'; import { type Dictionary } from '@/types/types'; @@ -108,10 +108,6 @@ const keys = computed(() => Object.keys(meals).filter((mealID) => meals[mealID]. const slugs = ref([]); const bookingDisabled = computed(() => slugs.value.length < 2); -onMounted(() => { - console.log(`open(${props.open}), weekId(${props.weekID}), dayID(${props.dayID}), \nMeals: ${JSON.stringify(Object.keys(props.meals))}`); -}) - function resolveModal(mode: string) { if (mode === 'cancel') { slugs.value = []; diff --git a/src/Resources/src/components/dashboard/Day.vue b/src/Resources/src/components/dashboard/Day.vue index 3047d2c5c..ab8ad7ae5 100644 --- a/src/Resources/src/components/dashboard/Day.vue +++ b/src/Resources/src/components/dashboard/Day.vue @@ -153,6 +153,20 @@ const dateString = computed(() => { }); }); +// const participationCount = computed(() => { +// let count = 0; +// Object.values(day?.meals ?? {}).forEach(meal => { +// if (meal.variations) { +// Object.values(meal.variations).forEach(variation => { +// if (variation.isParticipating) count++; +// }); +// } else { +// if (meal.isParticipating) count++; +// } +// }); +// return count; +// }); + async function closeParticipantsModal() { openParticipantsModal.value = false; } diff --git a/src/Resources/src/components/guest/GuestCheckbox.vue b/src/Resources/src/components/guest/GuestCheckbox.vue index dd527b9a0..cc6396dc6 100644 --- a/src/Resources/src/components/guest/GuestCheckbox.vue +++ b/src/Resources/src/components/guest/GuestCheckbox.vue @@ -1,14 +1,12 @@