From 4bbbd94ad2e08d35703d7a97f2803a43588f1ec3 Mon Sep 17 00:00:00 2001 From: Laurent <58115082+naaturel@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:32:21 +0100 Subject: [PATCH] Events can be joined and created --- .../letsmeet/dto/httpRequest/EventDTO.java | 1 + front/src/components/Calendar.vue | 22 ++-- front/src/components/InputField.vue | 1 + front/src/config/ApiConfig.ts | 5 + front/src/dto/AttendeeDto.ts | 4 +- front/src/dto/EventDto.ts | 4 +- front/src/models/Event.ts | 2 +- front/src/requests/EventRequests.ts | 5 +- front/src/stores/EventCreationStore.ts | 103 ++++++++++++++++++ front/src/stores/EventStore.ts | 69 ------------ front/src/views/CreateView.vue | 74 +++++++++++-- front/src/views/EventView.vue | 4 +- 12 files changed, 195 insertions(+), 99 deletions(-) create mode 100644 front/src/stores/EventCreationStore.ts delete mode 100644 front/src/stores/EventStore.ts diff --git a/back/src/main/java/be/naaturel/letsmeet/dto/httpRequest/EventDTO.java b/back/src/main/java/be/naaturel/letsmeet/dto/httpRequest/EventDTO.java index 539e5f9..a93d28f 100644 --- a/back/src/main/java/be/naaturel/letsmeet/dto/httpRequest/EventDTO.java +++ b/back/src/main/java/be/naaturel/letsmeet/dto/httpRequest/EventDTO.java @@ -6,6 +6,7 @@ import java.util.Set; public class EventDTO { public String name; + public String token; public Map> dates; } diff --git a/front/src/components/Calendar.vue b/front/src/components/Calendar.vue index 5514e18..cb5c993 100644 --- a/front/src/components/Calendar.vue +++ b/front/src/components/Calendar.vue @@ -5,25 +5,25 @@ import { datePickerStore } from "@/stores/CalendarStore.ts"; import { Calendar } from "@/models/Calendar.ts"; - const calendar = new Calendar(); - const datePicker = datePickerStore(); - const monthYear = ref(""); - const dates = ref([] as (number | null)[]); - const selectedDays = ref(new Map()); - onMounted(() => { setupCalendar(); }) - watch(selectedDays, (newValue) => { - let dates = Array.from(newValue.values()) - datePicker.update(dates); - }, { deep: true }); + const calendar = new Calendar(); + const monthYear = ref(""); + const dates = ref([] as (number | null)[]); + const selectedDays = ref(new Map()); + + const emit = defineEmits(['update:value']); + const emitNewDay = (timestamp : number) => { + emit('update:value', timestamp); + }; function selectDay(event : Event, day : number | null){ if(!(event.target instanceof HTMLElement) || day == null) return; calendar.setDay(day); toggleSelectedDay(event.target.id, calendar.getDate()); + emitNewDay(calendar.getDate().getTime()); highlightSelectedDay(event.target); } @@ -80,8 +80,6 @@
S
- -
+ public dates : Map - public constructor(name: string, token: string, dates: Map) { + public constructor(name: string, token: string, dates: Map) { this.name = name; this.token = token; this.dates = dates; diff --git a/front/src/models/Event.ts b/front/src/models/Event.ts index a0c28c2..d835c5b 100644 --- a/front/src/models/Event.ts +++ b/front/src/models/Event.ts @@ -29,6 +29,6 @@ export class Event { export interface EventState { name : string token : string - dates: Map; + dates: Map; } diff --git a/front/src/requests/EventRequests.ts b/front/src/requests/EventRequests.ts index e7b2c96..c5bc0f0 100644 --- a/front/src/requests/EventRequests.ts +++ b/front/src/requests/EventRequests.ts @@ -30,14 +30,15 @@ export class EventRequests { .catch(error => console.error(error)); } - public async createEvent(event : EventDto){ + public async createEvent(event : EventDto) : Promise { let url = this.formatUrl([this.baseUrl, this.endpoints.CREATE]); return fetch(url, { method: "POST", + headers: {"Content-Type": "application/json", "Accept": "application/json"}, body : JSON.stringify(event) }) .then(response => response.json()) - .then(data => new EventDto(data.name, data.token, data.attendees)) + .then(data => data.value) .catch(error => console.error(error)); } diff --git a/front/src/stores/EventCreationStore.ts b/front/src/stores/EventCreationStore.ts new file mode 100644 index 0000000..2bfb751 --- /dev/null +++ b/front/src/stores/EventCreationStore.ts @@ -0,0 +1,103 @@ +import {defineStore} from 'pinia' +import {EventRequests} from "@/requests/EventRequests.ts"; +import {EventDto} from "@/dto/EventDto.ts"; +import {Event, type EventState} from "@/models/Event.ts"; +import {Attendee, type AttendeeState} from "@/models/Attendee.ts"; +import type {AttendeeDto} from "@/dto/AttendeeDto.ts"; + +const requests = new EventRequests(); + +function mapToDto(state : EventState) : EventDto{ + let dates : Map = new Map(); + for (let [date, attendeesState] of state.dates.entries()) { + dates.set(date, []); + } + return new EventDto(state.name, state.token, dates); +} + +function mapToModel(state : EventState) : Event{ + let dates: Map = new Map(); + for (let [date, attendeesState] of state.dates.entries()) { + let attendees : Attendee[] = attendeesState.map(attendee => { + return new Attendee(attendee.name); + }) + dates.set(date, attendees); + } + return new Event(state.name, state.token, dates); +} + +function mapToState(dto : EventDto) : EventState { + let event : EventState = {name : "", token : "", dates: new Map()}; + event.name = dto.name; + event.token = dto.token; + Object.entries(dto.dates).forEach(([key, attendees]) => { + event.dates.set(Number(key), attendees); + }); + return event; +} + +export const eventCreationStore = defineStore('eventStore', { + state: (): {event : EventState} => { + return { + event : { + name: "", + token: "", + dates: new Map() + }}; + }, + getters : { + getEvent(state) : Event { + return mapToModel(state.event); + } + }, + actions: { + setName(name : string){ + this.event.name = name; + }, + addDate(timestamp : number){ + this.event.dates.set(timestamp, []); + }, + removeDate(timestamp : number){ + this.event.dates.delete(timestamp); + }, + addAttendee(timestamp : number, name : string){ + let dates :Map = this.event.dates; + if(dates.has(timestamp)){ + dates.get(timestamp)?.push({name : name}); + } else { + let attendees : AttendeeState[] = [{name : name}]; + dates.set(timestamp, attendees); + } + }, + toggleDate(timestamp : number){ + let dates :Map = this.event.dates; + if(dates.has(timestamp)){ + this.removeDate(timestamp); + } else { + this.addDate(timestamp); + } + }, + async fetch(token: string): Promise { + try{ + let data : EventDto | void = await requests.queryEvent(token); + if(!data) throw new Error("No event found"); + this.event = mapToState(data); + } catch (error) { + console.error(error); + throw new Error("Unable to fetch. " + error); + } + }, + async createEvent() : Promise { + try { + let event = mapToDto(this.event); + let res = await requests.createEvent(event) + if(res) return res; + throw new Error("Unable to create event"); + } catch (error){ + console.error(error); + throw new Error("Unable to post. " + error); + } + + } + }, +}); diff --git a/front/src/stores/EventStore.ts b/front/src/stores/EventStore.ts deleted file mode 100644 index 810253b..0000000 --- a/front/src/stores/EventStore.ts +++ /dev/null @@ -1,69 +0,0 @@ -import {defineStore} from 'pinia' -import {EventRequests} from "@/requests/EventRequests.ts"; -import {EventDto} from "@/dto/EventDto.ts"; -import {Event, type EventState} from "@/models/Event.ts"; -import {Attendee, type AttendeeState} from "@/models/Attendee.ts"; -import {EventDate, type EventDateState} from "@/models/EventDate.ts"; - -const requests = new EventRequests(); - -function mapToDto() : EventDto{ - return new EventDto("", "", new Map()); -} - -function mapToModel(state : EventState) : Event{ - let dates: Map = new Map(); - for (let [date, attendeesState] of state.dates.entries()) { - let attendees : Attendee[] = attendeesState.map(attendee => { - return new Attendee(attendee.name); - }) - dates.set(date.value, attendees); - } - return new Event(state.name, state.token, dates); -} - -function mapToState(dto : EventDto) : EventState { - let event : EventState = {name : "", token : "", dates: new Map()}; - event.name = dto.name; - event.token = dto.token; - Object.entries(dto.dates).forEach(([key, attendees]) => { - let dateState : EventDateState = { value: Number(key) }; - event.dates.set(dateState, attendees); - }); - return event; -} - -export const eventStore = defineStore('eventStore', { - state: (): {event : EventState} => { - return { - event : { - name: "", - token: "", - dates: new Map() - }}; - }, - getters : { - getEvent(state) : Event { - return mapToModel(state.event); - } - }, - actions: { - setName(name : string){ - this.event.name = name; - }, - async fetch(token: string): Promise { - try{ - let data : EventDto | void = await requests.queryEvent(token); - if(!data) throw new Error("No event found"); - this.event = mapToState(data); - } catch (error) { - console.error(error); - throw new Error("Unable to fetch. " + error); - } - }, - async create(){ - let event = mapToDto(); - await requests.createEvent(event) - } - }, -}); diff --git a/front/src/views/CreateView.vue b/front/src/views/CreateView.vue index d4ee9d7..7e213e5 100644 --- a/front/src/views/CreateView.vue +++ b/front/src/views/CreateView.vue @@ -2,11 +2,58 @@ import Calendar from "@/components/Calendar.vue"; import TextBlock from "@/components/TextBlock.vue"; -import NavLink from "@/components/NavLink.vue"; import InputField from "@/components/InputField.vue"; -import {eventStore} from "@/stores/EventStore.ts"; +import {eventCreationStore} from "@/stores/EventCreationStore.ts"; +import Button from "@/components/Button.vue"; +import {ref} from "vue"; +import {useRouter} from "vue-router"; +import {API_PATHS} from "@/config/ApiConfig.ts"; -const store = eventStore(); +const router = useRouter(); +const store = eventCreationStore(); +const errorMessage = ref(""); + +async function createEvent() { + if(!store.event.name){ + displayError("Please enter a valid name.", getNameField()); + return; + } + if(store.event.dates.size == 0){ + displayError("Please select at least one date", getCalendar()); + return; + } + + let createdToken = await store.createEvent(); + await router.push({name: API_PATHS.NAMES.EVENTS, params: {token: createdToken}}); +} + +function updateName(value: string) { + resetError(getNameField()); + store.setName(value); +} + +function updateDates(value: number) { + resetError(getCalendar()); + store.toggleDate(value) +} + +function displayError(message: string, target : Element) { + target.style.border = "2px solid red"; + errorMessage.value = message; +} + +function resetError(target : Element){ + target.style.border = "2px solid black"; + errorMessage.value = ""; +} + +function getNameField() : Element { + return document.getElementsByClassName("input-field")[0]; +} + +function getCalendar() : Element { + return document.getElementsByClassName("calendar-container")[0]; +} @@ -17,9 +64,12 @@ const store = eventStore();

Create an event

- - - +
+ +
{{ errorMessage }}
+
+ +
@@ -46,13 +96,21 @@ const store = eventStore(); min-height: 50px; } -.nav-link +.button { width: 50%; height: 50px; min-height: 50px; } +.whatever-the-fuck-this-is +{ + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; +} + /* MEDIA QUERIES */ @media screen and (min-width: 1001px) { @@ -79,7 +137,7 @@ const store = eventStore(); @media screen and (max-width: 1000px) { - .title, .event-form, .input-field, .nav-link { + .title, .event-form, .input-field, .button { width: 100%; } diff --git a/front/src/views/EventView.vue b/front/src/views/EventView.vue index df19c7d..1438fd5 100644 --- a/front/src/views/EventView.vue +++ b/front/src/views/EventView.vue @@ -1,5 +1,5 @@