diff --git a/backend/pkg/db/events/events.go b/backend/pkg/db/events/events.go index 835903b..28d6a54 100644 --- a/backend/pkg/db/events/events.go +++ b/backend/pkg/db/events/events.go @@ -266,3 +266,10 @@ func User(userName string) ([]EventWithAssignment, error) { return nil, nil } } + +// set the availability of an user for a specific event +func UserAvailability(userName string, eventID, availabilityID int) error { + _, err := db.DB.Exec("INSERT INTO USER_AVAILABILITIES (userName, eventID, availabilityID) VALUES ($1, $2, $3) ON CONFLICT (userName, eventID) DO UPDATE SET availabilityID = $3", userName, eventID, availabilityID) + + return err +} diff --git a/backend/pkg/router/events.go b/backend/pkg/router/events.go index 0709b0d..51c9912 100644 --- a/backend/pkg/router/events.go +++ b/backend/pkg/router/events.go @@ -1,6 +1,8 @@ package router import ( + "strconv" + "github.com/gofiber/fiber/v2" "github.com/johannesbuehl/golunteer/backend/pkg/db/events" ) @@ -119,6 +121,32 @@ func (a *Handler) getEventsUserAssigned() { } } +func (a *Handler) putEventUserAvailability() { + // parse the query + if eventID := a.C.QueryInt("eventID", -1); eventID == -1 { + a.Status = fiber.StatusBadRequest + + logger.Log().Msg("setting user-event-availability failed: query is missing \"eventID\"") + } else { + // parse the body + body := a.C.Body() + + if availabilityID, err := strconv.Atoi(string(body)); err != nil { + a.Status = fiber.StatusBadRequest + + logger.Log().Msgf("setting user-event-availability failed: can't get parse: %v", err) + + // insert the availability into the database + } else if err := events.UserAvailability(a.UserName, eventID, availabilityID); err != nil { + a.Status = fiber.StatusInternalServerError + + logger.Error().Msgf("setting user-event-availability failed: can't write availability to database: %v", err) + } + } + + // parse the body +} + func (a *Handler) deleteEvent() { // check for admin if !a.Admin { diff --git a/backend/pkg/router/router.go b/backend/pkg/router/router.go index 1a67414..00c8820 100644 --- a/backend/pkg/router/router.go +++ b/backend/pkg/router/router.go @@ -107,7 +107,8 @@ func init() { "tasks": (*Handler).patchTask, // modify a task }, "PUT": { - "users/password": (*Handler).putPassword, // change the password + "users/password": (*Handler).putPassword, // change the password + "events/user/availability": (*Handler).putEventUserAvailability, // set or change the users availability for a specific event }, "DELETE": { "event": (*Handler).deleteEvent, // remove an event diff --git a/client/src/app/PendingEvents.tsx b/client/src/app/PendingEvents.tsx index ceaf47e..504b40d 100644 --- a/client/src/app/PendingEvents.tsx +++ b/client/src/app/PendingEvents.tsx @@ -41,6 +41,15 @@ export default function PengingEvents() { }, }); + async function setAvailability(eventID: number, availabilityID: number) { + await apiCall( + "PUT", + "events/user/availability", + { eventID }, + availabilityID, + ); + } + return (
{events.items.map((e) => ( @@ -60,6 +69,9 @@ export default function PengingEvents() { )}
)} + onSelectionChange={(a) => + setAvailability(e.eventID, parseInt(a.anchorKey ?? "")) + } > {(availability) => ( = { [K in keyof T]: string }; type QueryParams = Record; +type Body = object | string | number | boolean; + export type APICallResult = Omit & { json: () => Promise; }; @@ -19,19 +21,19 @@ export async function apiCall( method: "POST" | "PATCH" | "PUT", api: string, query?: QueryParams, - body?: object, + body?: Body, ): Promise>; export async function apiCall( method: "DELETE", api: string, query?: QueryParams, - body?: object, + body?: Body, ): Promise>; export async function apiCall( method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE", api: string, query?: QueryParams, - body?: object, + body?: Body, ): Promise> { let url = window.origin + "/api/" + api; @@ -53,7 +55,7 @@ export async function apiCall( const response = await fetch(url, { headers: { - "Content-Type": "application/json; charset=UTF-8", + "Content-Type": `${getContentType(typeof body)}; charset=UTF-8`, }, credentials: "include", method, @@ -63,6 +65,20 @@ export async function apiCall( return response; } +function getContentType(type: string): string { + switch (type) { + case "object": + return "application/json"; + case "string": + case "number": + case "bigint": + case "boolean": + return "text/plain"; + default: + return "application/octet-stream"; + } +} + export function classNames(classNames: Record): string { return Object.entries(classNames) .map(([classString, value]) => {