added entering availabilities in the dashboard
This commit is contained in:
@@ -266,3 +266,10 @@ func User(userName string) ([]EventWithAssignment, error) {
|
|||||||
return nil, nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/johannesbuehl/golunteer/backend/pkg/db/events"
|
"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() {
|
func (a *Handler) deleteEvent() {
|
||||||
// check for admin
|
// check for admin
|
||||||
if !a.Admin {
|
if !a.Admin {
|
||||||
|
|||||||
@@ -107,7 +107,8 @@ func init() {
|
|||||||
"tasks": (*Handler).patchTask, // modify a task
|
"tasks": (*Handler).patchTask, // modify a task
|
||||||
},
|
},
|
||||||
"PUT": {
|
"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": {
|
"DELETE": {
|
||||||
"event": (*Handler).deleteEvent, // remove an event
|
"event": (*Handler).deleteEvent, // remove an event
|
||||||
|
|||||||
@@ -41,6 +41,15 @@ export default function PengingEvents() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function setAvailability(eventID: number, availabilityID: number) {
|
||||||
|
await apiCall(
|
||||||
|
"PUT",
|
||||||
|
"events/user/availability",
|
||||||
|
{ eventID },
|
||||||
|
availabilityID,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center gap-4">
|
<div className="flex justify-center gap-4">
|
||||||
{events.items.map((e) => (
|
{events.items.map((e) => (
|
||||||
@@ -60,6 +69,9 @@ export default function PengingEvents() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
onSelectionChange={(a) =>
|
||||||
|
setAvailability(e.eventID, parseInt(a.anchorKey ?? ""))
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{(availability) => (
|
{(availability) => (
|
||||||
<SelectItem
|
<SelectItem
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ export type AllString<T> = { [K in keyof T]: string };
|
|||||||
|
|
||||||
type QueryParams = Record<string, string | { toString(): string }>;
|
type QueryParams = Record<string, string | { toString(): string }>;
|
||||||
|
|
||||||
|
type Body = object | string | number | boolean;
|
||||||
|
|
||||||
export type APICallResult<T> = Omit<Response, "json"> & {
|
export type APICallResult<T> = Omit<Response, "json"> & {
|
||||||
json: () => Promise<T>;
|
json: () => Promise<T>;
|
||||||
};
|
};
|
||||||
@@ -19,19 +21,19 @@ export async function apiCall<K>(
|
|||||||
method: "POST" | "PATCH" | "PUT",
|
method: "POST" | "PATCH" | "PUT",
|
||||||
api: string,
|
api: string,
|
||||||
query?: QueryParams,
|
query?: QueryParams,
|
||||||
body?: object,
|
body?: Body,
|
||||||
): Promise<APICallResult<K>>;
|
): Promise<APICallResult<K>>;
|
||||||
export async function apiCall<K>(
|
export async function apiCall<K>(
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
api: string,
|
api: string,
|
||||||
query?: QueryParams,
|
query?: QueryParams,
|
||||||
body?: object,
|
body?: Body,
|
||||||
): Promise<APICallResult<K>>;
|
): Promise<APICallResult<K>>;
|
||||||
export async function apiCall<K>(
|
export async function apiCall<K>(
|
||||||
method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE",
|
method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE",
|
||||||
api: string,
|
api: string,
|
||||||
query?: QueryParams,
|
query?: QueryParams,
|
||||||
body?: object,
|
body?: Body,
|
||||||
): Promise<APICallResult<K>> {
|
): Promise<APICallResult<K>> {
|
||||||
let url = window.origin + "/api/" + api;
|
let url = window.origin + "/api/" + api;
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ export async function apiCall<K>(
|
|||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json; charset=UTF-8",
|
"Content-Type": `${getContentType(typeof body)}; charset=UTF-8`,
|
||||||
},
|
},
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
method,
|
method,
|
||||||
@@ -63,6 +65,20 @@ export async function apiCall<K>(
|
|||||||
return response;
|
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, boolean>): string {
|
export function classNames(classNames: Record<string, boolean>): string {
|
||||||
return Object.entries(classNames)
|
return Object.entries(classNames)
|
||||||
.map(([classString, value]) => {
|
.map(([classString, value]) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user