diff --git a/src/Evently.Server/Common/Domains/Models/GatheringCategoryDetailDto.cs b/src/Evently.Server/Common/Domains/Models/GatheringCategoryDetailDto.cs new file mode 100644 index 0000000..e20c703 --- /dev/null +++ b/src/Evently.Server/Common/Domains/Models/GatheringCategoryDetailDto.cs @@ -0,0 +1,4 @@ +namespace Evently.Server.Common.Domains.Models; + +// [{"categoryId":1,"gatheringId":22},{"categoryId":2,"gatheringId":22}] +public sealed record GatheringCategoryDetailDto(long GatheringId, long CategoryId); \ No newline at end of file diff --git a/src/Evently.Server/Common/Domains/Models/GatheringReqDto.cs b/src/Evently.Server/Common/Domains/Models/GatheringReqDto.cs index e5bb67c..1f45531 100644 --- a/src/Evently.Server/Common/Domains/Models/GatheringReqDto.cs +++ b/src/Evently.Server/Common/Domains/Models/GatheringReqDto.cs @@ -9,5 +9,6 @@ public sealed record GatheringReqDto( DateTimeOffset? CancellationDateTime, string Location, string OrganiserId, - string? CoverSrc + string? CoverSrc, + List GatheringCategoryDetails ); \ No newline at end of file diff --git a/src/Evently.Server/Common/Extensions/MapperExtension.cs b/src/Evently.Server/Common/Extensions/MapperExtension.cs index 01d0eee..9b85774 100644 --- a/src/Evently.Server/Common/Extensions/MapperExtension.cs +++ b/src/Evently.Server/Common/Extensions/MapperExtension.cs @@ -5,6 +5,12 @@ namespace Evently.Server.Common.Extensions; public static class MapperExtension { public static Gathering ToGathering(this GatheringReqDto gatheringReqDto) { + List gatheringCategoryDetails = gatheringReqDto.GatheringCategoryDetails + .Select((detail) => new GatheringCategoryDetail { + GatheringId = gatheringReqDto.GatheringId, + CategoryId = detail.CategoryId, + }) + .ToList(); Gathering gathering = new() { GatheringId = gatheringReqDto.GatheringId, Name = gatheringReqDto.Name, @@ -15,11 +21,15 @@ public static Gathering ToGathering(this GatheringReqDto gatheringReqDto) { Location = gatheringReqDto.Location, OrganiserId = gatheringReqDto.OrganiserId, CoverSrc = gatheringReqDto.CoverSrc, + GatheringCategoryDetails = gatheringCategoryDetails, }; return gathering; } public static GatheringReqDto ToGatheringDto(this Gathering gathering) { + List gatheringCategoryDetails = gathering.GatheringCategoryDetails + .Select(detail => new GatheringCategoryDetailDto(detail.GatheringId, detail.CategoryId)) + .ToList(); GatheringReqDto reqDto = new( gathering.GatheringId, gathering.Name, @@ -29,7 +39,8 @@ public static GatheringReqDto ToGatheringDto(this Gathering gathering) { gathering.CancellationDateTime, gathering.Location, gathering.OrganiserId, - gathering.CoverSrc + gathering.CoverSrc, + gatheringCategoryDetails ); return reqDto; } diff --git a/src/Evently.Server/Features/Accounts/AccountController.cs b/src/Evently.Server/Features/Accounts/Controllers/AccountController.cs similarity index 98% rename from src/Evently.Server/Features/Accounts/AccountController.cs rename to src/Evently.Server/Features/Accounts/Controllers/AccountController.cs index 45c5770..553897a 100644 --- a/src/Evently.Server/Features/Accounts/AccountController.cs +++ b/src/Evently.Server/Features/Accounts/Controllers/AccountController.cs @@ -9,7 +9,7 @@ using Microsoft.AspNetCore.Mvc; using System.Security.Claims; -namespace Evently.Server.Features.Accounts; +namespace Evently.Server.Features.Accounts.Controllers; // Based on https://tinyurl.com/26arz8vk [ApiController] diff --git a/src/Evently.Server/Features/Bookings/BookingsController.cs b/src/Evently.Server/Features/Bookings/Controllers/BookingsController.cs similarity index 98% rename from src/Evently.Server/Features/Bookings/BookingsController.cs rename to src/Evently.Server/Features/Bookings/Controllers/BookingsController.cs index 1a7d71a..8c90526 100644 --- a/src/Evently.Server/Features/Bookings/BookingsController.cs +++ b/src/Evently.Server/Features/Bookings/Controllers/BookingsController.cs @@ -7,7 +7,7 @@ using System.Globalization; using System.Threading.Channels; -namespace Evently.Server.Features.Bookings; +namespace Evently.Server.Features.Bookings.Controllers; [ApiController] [Route("api/v1/[controller]")] diff --git a/src/Evently.Server/Features/Bookings/Services/BookingService.cs b/src/Evently.Server/Features/Bookings/Services/BookingService.cs index 08868be..f752d76 100644 --- a/src/Evently.Server/Features/Bookings/Services/BookingService.cs +++ b/src/Evently.Server/Features/Bookings/Services/BookingService.cs @@ -70,7 +70,7 @@ public async Task CreateBooking(BookingReqDto bookingReqDto) { if (!validationResult.IsValid) { throw new ArgumentException($"Account has already booked this gathering (GatheringId: {booking.GatheringId})"); } - + booking.BookingId = $"book_{await Nanoid.GenerateAsync(size: 10)}"; await db.Bookings.AddAsync(booking); await db.SaveChangesAsync(); diff --git a/src/Evently.Server/Features/Categories/CategoriesController.cs b/src/Evently.Server/Features/Categories/Controllers/CategoriesController.cs similarity index 94% rename from src/Evently.Server/Features/Categories/CategoriesController.cs rename to src/Evently.Server/Features/Categories/Controllers/CategoriesController.cs index f094205..032ada0 100644 --- a/src/Evently.Server/Features/Categories/CategoriesController.cs +++ b/src/Evently.Server/Features/Categories/Controllers/CategoriesController.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc; using System.Globalization; -namespace Evently.Server.Features.Categories; +namespace Evently.Server.Features.Categories.Controllers; [ApiController] [Route("api/v1/[controller]")] diff --git a/src/Evently.Server/Features/Gatherings/GatheringsController.cs b/src/Evently.Server/Features/Gatherings/Controllers/GatheringsController.cs similarity index 98% rename from src/Evently.Server/Features/Gatherings/GatheringsController.cs rename to src/Evently.Server/Features/Gatherings/Controllers/GatheringsController.cs index 37dd544..93fa591 100644 --- a/src/Evently.Server/Features/Gatherings/GatheringsController.cs +++ b/src/Evently.Server/Features/Gatherings/Controllers/GatheringsController.cs @@ -3,14 +3,13 @@ using Evently.Server.Common.Domains.Models; using Evently.Server.Common.Extensions; using Evently.Server.Features.Accounts.Services; -using FluentValidation; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using MimeKit; using System.Globalization; -namespace Evently.Server.Features.Gatherings; +namespace Evently.Server.Features.Gatherings.Controllers; [ApiController] [Route("api/v1/[controller]")] diff --git a/src/Evently.Server/Features/Gatherings/Services/GatheringService.cs b/src/Evently.Server/Features/Gatherings/Services/GatheringService.cs index aa43552..377528c 100644 --- a/src/Evently.Server/Features/Gatherings/Services/GatheringService.cs +++ b/src/Evently.Server/Features/Gatherings/Services/GatheringService.cs @@ -78,6 +78,7 @@ public async Task UpdateGathering(long gatheringId, GatheringReqDto g } Gathering current = await db.Gatherings.AsTracking() + .Include((g) => g.GatheringCategoryDetails) .FirstOrDefaultAsync((ex) => ex.GatheringId == gatheringId) ?? throw new KeyNotFoundException($"{gatheringId} not found"); @@ -87,6 +88,7 @@ public async Task UpdateGathering(long gatheringId, GatheringReqDto g current.End = gathering.End; current.Location = gathering.Location; current.CoverSrc = gathering.CoverSrc; + current.GatheringCategoryDetails = gathering.GatheringCategoryDetails; await db.SaveChangesAsync(); return current; diff --git a/src/Evently.Server/Features/HealthChecks/HealthChecksController.cs b/src/Evently.Server/Features/HealthChecks/Controllers/HealthChecksController.cs similarity index 94% rename from src/Evently.Server/Features/HealthChecks/HealthChecksController.cs rename to src/Evently.Server/Features/HealthChecks/Controllers/HealthChecksController.cs index 199acc7..4de00bb 100644 --- a/src/Evently.Server/Features/HealthChecks/HealthChecksController.cs +++ b/src/Evently.Server/Features/HealthChecks/Controllers/HealthChecksController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Diagnostics.HealthChecks; -namespace Evently.Server.Features.HealthChecks; +namespace Evently.Server.Features.HealthChecks.Controllers; [ApiController] [Route("api/v1/[controller]")] diff --git a/src/evently.client/src/lib/components/card.tsx b/src/evently.client/src/lib/components/card.tsx index 9bfcffb..512083f 100644 --- a/src/evently.client/src/lib/components/card.tsx +++ b/src/evently.client/src/lib/components/card.tsx @@ -55,7 +55,7 @@ export function Card({ gathering, accountId }: CardProps): JSX.Element { {`${start.toLocaleString(DateTime.DATETIME_MED)} — ${end.toLocaleString(DateTime.DATETIME_MED)}`} -
+
{categories.map((category) => (
{category.categoryName} diff --git a/src/evently.client/src/lib/domains/models/upsert-dtos.ts b/src/evently.client/src/lib/domains/models/upsert-dtos.ts index 07becc4..66b7b63 100644 --- a/src/evently.client/src/lib/domains/models/upsert-dtos.ts +++ b/src/evently.client/src/lib/domains/models/upsert-dtos.ts @@ -1,11 +1,11 @@ export class BookingReqDto { - public bookingId = ""; - public attendeeId = ""; - public gatheringId = 0; - public creationDateTime = new Date(); - public checkInDateTime: Date | null = null; - public checkoutDateTime: Date | null = null; - public cancellationDateTime: Date | null = null; + bookingId = ""; + attendeeId = ""; + gatheringId = 0; + creationDateTime = new Date(); + checkInDateTime: Date | null = null; + checkoutDateTime: Date | null = null; + cancellationDateTime: Date | null = null; constructor(partial: Partial = {}) { Object.assign(this, partial); @@ -13,17 +13,23 @@ } export class GatheringReqDto { - public gatheringId = 0; - public name = ""; - public description = ""; - public start = new Date(); - public end = new Date(); - public location = ""; - public organiserId = ""; - public coverSrc?: string | null = null; - public cancellationDateTime: Date | null = null; + gatheringId = 0; + name = ""; + description = ""; + start = new Date(); + end = new Date(); + location = ""; + organiserId = ""; + coverSrc?: string | null = null; + cancellationDateTime: Date | null = null; + gatheringCategoryDetails: GatheringCategoryDetailReqDto[] = []; constructor(partial: Partial = {}) { Object.assign(this, partial); } } + +export class GatheringCategoryDetailReqDto { + gatheringId = 0; + categoryId = 0; +} diff --git a/src/evently.client/src/lib/services/category-service.ts b/src/evently.client/src/lib/services/category-service.ts new file mode 100644 index 0000000..1bc3152 --- /dev/null +++ b/src/evently.client/src/lib/services/category-service.ts @@ -0,0 +1,7 @@ +import { Category } from "~/lib/domains/entities"; +import axios from "axios"; + +export async function getCategories(): Promise { + const response = await axios.get("/api/v1/Categories"); + return response.data; +} diff --git a/src/evently.client/src/lib/services/gathering-service.mock.ts b/src/evently.client/src/lib/services/gathering-service.mock.ts index 30029ab..e380ace 100644 --- a/src/evently.client/src/lib/services/gathering-service.mock.ts +++ b/src/evently.client/src/lib/services/gathering-service.mock.ts @@ -1,4 +1,4 @@ -import { Booking, Gathering, Category } from "~/lib/domains/entities"; +import { Booking, Gathering, Category, GatheringCategoryDetail } from "~/lib/domains/entities"; import { GatheringReqDto } from "~/lib/domains/models"; import type { GetGatheringsParams } from "./gathering-service"; import type { PageResult } from "~/lib/domains/interfaces"; @@ -101,7 +101,11 @@ export async function createMockGathering( ): Promise { return { ...new Gathering(), - ...gatheringDto + ...gatheringDto, + gatheringCategoryDetails: gatheringDto.gatheringCategoryDetails.map((detail) => ({ + ...detail, + ...new GatheringCategoryDetail() + })) }; } @@ -114,6 +118,10 @@ export async function updateMockGathering( return { ...new Gathering(), ...gatheringDto, - gatheringId: gatheringId + gatheringId: gatheringId, + gatheringCategoryDetails: gatheringDto.gatheringCategoryDetails.map((detail) => ({ + ...detail, + ...new GatheringCategoryDetail() + })) }; } diff --git a/src/evently.client/src/lib/services/gathering-service.ts b/src/evently.client/src/lib/services/gathering-service.ts index cc3c1d6..8e9f1fe 100644 --- a/src/evently.client/src/lib/services/gathering-service.ts +++ b/src/evently.client/src/lib/services/gathering-service.ts @@ -1,6 +1,6 @@ import type { Gathering } from "~/lib/domains/entities"; import axios from "axios"; -import { GatheringReqDto } from "~/lib/domains/models"; +import { GatheringCategoryDetailReqDto, GatheringReqDto } from "~/lib/domains/models"; import type { PageResult } from "~/lib/domains/interfaces"; export interface GetGatheringsParams { @@ -43,17 +43,7 @@ export async function createGathering( gatheringDto: GatheringReqDto, coverImg?: File | null ): Promise { - const formData = new FormData(); - for (const [key, value] of Object.entries(gatheringDto)) { - if (value != null) { - formData.set(key, value); - } - } - if (coverImg != null) { - formData.set("coverImg", coverImg, coverImg.name); - } - formData.set("start", gatheringDto.start.toISOString()); - formData.set("end", gatheringDto.end.toISOString()); + const formData: FormData = toFormData(gatheringDto, coverImg); const response = await axios.post(`/api/v1/Gatherings`, formData, { headers: { "Content-Type": "multipart/form-data" } @@ -66,12 +56,30 @@ export async function updateGathering( gatheringDto: GatheringReqDto, coverImg?: File | null ): Promise { + const formData: FormData = toFormData(gatheringDto, coverImg); + + const response = await axios.put(`/api/v1/Gatherings/${gatheringId}`, formData, { + headers: { "Content-Type": "multipart/form-data" } + }); + return response.data; +} + +function toFormData(gatheringDto: GatheringReqDto, coverImg?: File | null): FormData { const formData = new FormData(); for (const [key, value] of Object.entries(gatheringDto)) { if (value != null) { formData.set(key, value); } } + formData.delete("gatheringCategoryDetails"); + + for (let i = 0; i < gatheringDto.gatheringCategoryDetails.length; i++) { + const detail: GatheringCategoryDetailReqDto = gatheringDto.gatheringCategoryDetails[i]; + for (const [key, value] of Object.entries(detail)) { + formData.set(`gatheringCategoryDetails[${i}].${key}`, value); + } + } + if (coverImg != null) { formData.set("coverImg", coverImg, coverImg.name); } @@ -80,9 +88,5 @@ export async function updateGathering( if (gatheringDto.cancellationDateTime != null) { formData.set("cancellationDateTime", gatheringDto.cancellationDateTime.toISOString()); } - - const response = await axios.put(`/api/v1/Gatherings/${gatheringId}`, formData, { - headers: { "Content-Type": "multipart/form-data" } - }); - return response.data; + return formData; } diff --git a/src/evently.client/src/lib/services/index.ts b/src/evently.client/src/lib/services/index.ts index 079c99d..11e4e61 100644 --- a/src/evently.client/src/lib/services/index.ts +++ b/src/evently.client/src/lib/services/index.ts @@ -3,3 +3,4 @@ export * from "./auth-service"; export * from "./store"; export * from "./gathering-service.ts"; export * from "./booking-service"; +export * from "./category-service.ts"; diff --git a/src/evently.client/src/lib/services/util-service.ts b/src/evently.client/src/lib/services/util-service.ts index d1dd599..80822a1 100644 --- a/src/evently.client/src/lib/services/util-service.ts +++ b/src/evently.client/src/lib/services/util-service.ts @@ -47,3 +47,18 @@ export function toIsoString(date: Date | null): string { const dateTime: DateTime = DateTime.fromJSDate(date); return dateTime.toFormat("yyyy-MM-dd'T'HH:mm"); } + +export async function fetchFile(src: string, fileName?: string): Promise { + const urlObj = new URL(src); + if (fileName == null) { + fileName = urlObj.pathname.split("/").pop() ?? ""; + } + + const response = await fetch(src); + if (!response.ok) { + throw new Error(`Failed to fetch ${src}`); + } + const dataBlob: Blob = await response.blob(); + const file: File = new File([dataBlob], fileName, { type: dataBlob.type }); + return file; +} diff --git a/src/evently.client/src/routeTree.gen.ts b/src/evently.client/src/routeTree.gen.ts index 65e370f..c3c8e8c 100644 --- a/src/evently.client/src/routeTree.gen.ts +++ b/src/evently.client/src/routeTree.gen.ts @@ -8,328 +8,330 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { Route as rootRouteImport } from "./routes/__root"; -import { Route as IndexRouteImport } from "./routes/index"; -import { Route as LoginIndexRouteImport } from "./routes/login/index"; -import { Route as HealthcheckIndexRouteImport } from "./routes/healthcheck/index"; -import { Route as GatheringsIndexRouteImport } from "./routes/gatherings/index"; -import { Route as authGatheringsRouteRouteImport } from "./routes/(auth)/gatherings/route"; -import { Route as authBookingsRouteRouteImport } from "./routes/(auth)/bookings/route"; -import { Route as GatheringsGatheringIdIndexRouteImport } from "./routes/gatherings/$gatheringId/index"; -import { Route as authGatheringsCreateRouteImport } from "./routes/(auth)/gatherings/create"; -import { Route as authBookingsHostingIndexRouteImport } from "./routes/(auth)/bookings/hosting/index"; -import { Route as authBookingsAttendingIndexRouteImport } from "./routes/(auth)/bookings/attending/index"; -import { Route as authGatheringsGatheringIdUpdateRouteImport } from "./routes/(auth)/gatherings/$gatheringId/update"; -import { Route as authBookingsHostingGatheringIdDashboardIndexRouteImport } from "./routes/(auth)/bookings/hosting/$gatheringId/dashboard.index"; -import { Route as authBookingsHostingGatheringIdDashboardScanRouteImport } from "./routes/(auth)/bookings/hosting/$gatheringId/dashboard.scan"; +import { Route as rootRouteImport } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' +import { Route as LoginIndexRouteImport } from './routes/login/index' +import { Route as HealthcheckIndexRouteImport } from './routes/healthcheck/index' +import { Route as GatheringsIndexRouteImport } from './routes/gatherings/index' +import { Route as authGatheringsRouteRouteImport } from './routes/(auth)/gatherings/route' +import { Route as authBookingsRouteRouteImport } from './routes/(auth)/bookings/route' +import { Route as GatheringsGatheringIdIndexRouteImport } from './routes/gatherings/$gatheringId/index' +import { Route as authGatheringsCreateRouteImport } from './routes/(auth)/gatherings/create' +import { Route as authBookingsHostingIndexRouteImport } from './routes/(auth)/bookings/hosting/index' +import { Route as authBookingsAttendingIndexRouteImport } from './routes/(auth)/bookings/attending/index' +import { Route as authGatheringsGatheringIdUpdateRouteImport } from './routes/(auth)/gatherings/$gatheringId/update' +import { Route as authBookingsHostingGatheringIdDashboardIndexRouteImport } from './routes/(auth)/bookings/hosting/$gatheringId/dashboard.index' +import { Route as authBookingsHostingGatheringIdDashboardScanRouteImport } from './routes/(auth)/bookings/hosting/$gatheringId/dashboard.scan' const IndexRoute = IndexRouteImport.update({ - id: "/", - path: "/", - getParentRoute: () => rootRouteImport -} as any); + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) const LoginIndexRoute = LoginIndexRouteImport.update({ - id: "/login/", - path: "/login/", - getParentRoute: () => rootRouteImport -} as any); + id: '/login/', + path: '/login/', + getParentRoute: () => rootRouteImport, +} as any) const HealthcheckIndexRoute = HealthcheckIndexRouteImport.update({ - id: "/healthcheck/", - path: "/healthcheck/", - getParentRoute: () => rootRouteImport -} as any); + id: '/healthcheck/', + path: '/healthcheck/', + getParentRoute: () => rootRouteImport, +} as any) const GatheringsIndexRoute = GatheringsIndexRouteImport.update({ - id: "/gatherings/", - path: "/gatherings/", - getParentRoute: () => rootRouteImport -} as any); + id: '/gatherings/', + path: '/gatherings/', + getParentRoute: () => rootRouteImport, +} as any) const authGatheringsRouteRoute = authGatheringsRouteRouteImport.update({ - id: "/(auth)/gatherings", - path: "/gatherings", - getParentRoute: () => rootRouteImport -} as any); + id: '/(auth)/gatherings', + path: '/gatherings', + getParentRoute: () => rootRouteImport, +} as any) const authBookingsRouteRoute = authBookingsRouteRouteImport.update({ - id: "/(auth)/bookings", - path: "/bookings", - getParentRoute: () => rootRouteImport -} as any); -const GatheringsGatheringIdIndexRoute = GatheringsGatheringIdIndexRouteImport.update({ - id: "/gatherings/$gatheringId/", - path: "/gatherings/$gatheringId/", - getParentRoute: () => rootRouteImport -} as any); + id: '/(auth)/bookings', + path: '/bookings', + getParentRoute: () => rootRouteImport, +} as any) +const GatheringsGatheringIdIndexRoute = + GatheringsGatheringIdIndexRouteImport.update({ + id: '/gatherings/$gatheringId/', + path: '/gatherings/$gatheringId/', + getParentRoute: () => rootRouteImport, + } as any) const authGatheringsCreateRoute = authGatheringsCreateRouteImport.update({ - id: "/create", - path: "/create", - getParentRoute: () => authGatheringsRouteRoute -} as any); -const authBookingsHostingIndexRoute = authBookingsHostingIndexRouteImport.update({ - id: "/hosting/", - path: "/hosting/", - getParentRoute: () => authBookingsRouteRoute -} as any); -const authBookingsAttendingIndexRoute = authBookingsAttendingIndexRouteImport.update({ - id: "/attending/", - path: "/attending/", - getParentRoute: () => authBookingsRouteRoute -} as any); -const authGatheringsGatheringIdUpdateRoute = authGatheringsGatheringIdUpdateRouteImport.update({ - id: "/$gatheringId/update", - path: "/$gatheringId/update", - getParentRoute: () => authGatheringsRouteRoute -} as any); + id: '/create', + path: '/create', + getParentRoute: () => authGatheringsRouteRoute, +} as any) +const authBookingsHostingIndexRoute = + authBookingsHostingIndexRouteImport.update({ + id: '/hosting/', + path: '/hosting/', + getParentRoute: () => authBookingsRouteRoute, + } as any) +const authBookingsAttendingIndexRoute = + authBookingsAttendingIndexRouteImport.update({ + id: '/attending/', + path: '/attending/', + getParentRoute: () => authBookingsRouteRoute, + } as any) +const authGatheringsGatheringIdUpdateRoute = + authGatheringsGatheringIdUpdateRouteImport.update({ + id: '/$gatheringId/update', + path: '/$gatheringId/update', + getParentRoute: () => authGatheringsRouteRoute, + } as any) const authBookingsHostingGatheringIdDashboardIndexRoute = - authBookingsHostingGatheringIdDashboardIndexRouteImport.update({ - id: "/hosting/$gatheringId/dashboard/", - path: "/hosting/$gatheringId/dashboard/", - getParentRoute: () => authBookingsRouteRoute - } as any); + authBookingsHostingGatheringIdDashboardIndexRouteImport.update({ + id: '/hosting/$gatheringId/dashboard/', + path: '/hosting/$gatheringId/dashboard/', + getParentRoute: () => authBookingsRouteRoute, + } as any) const authBookingsHostingGatheringIdDashboardScanRoute = - authBookingsHostingGatheringIdDashboardScanRouteImport.update({ - id: "/hosting/$gatheringId/dashboard/scan", - path: "/hosting/$gatheringId/dashboard/scan", - getParentRoute: () => authBookingsRouteRoute - } as any); + authBookingsHostingGatheringIdDashboardScanRouteImport.update({ + id: '/hosting/$gatheringId/dashboard/scan', + path: '/hosting/$gatheringId/dashboard/scan', + getParentRoute: () => authBookingsRouteRoute, + } as any) export interface FileRoutesByFullPath { - "/": typeof IndexRoute; - "/bookings": typeof authBookingsRouteRouteWithChildren; - "/gatherings": typeof GatheringsIndexRoute; - "/healthcheck": typeof HealthcheckIndexRoute; - "/login": typeof LoginIndexRoute; - "/gatherings/create": typeof authGatheringsCreateRoute; - "/gatherings/$gatheringId": typeof GatheringsGatheringIdIndexRoute; - "/gatherings/$gatheringId/update": typeof authGatheringsGatheringIdUpdateRoute; - "/bookings/attending": typeof authBookingsAttendingIndexRoute; - "/bookings/hosting": typeof authBookingsHostingIndexRoute; - "/bookings/hosting/$gatheringId/dashboard/scan": typeof authBookingsHostingGatheringIdDashboardScanRoute; - "/bookings/hosting/$gatheringId/dashboard": typeof authBookingsHostingGatheringIdDashboardIndexRoute; + '/': typeof IndexRoute + '/bookings': typeof authBookingsRouteRouteWithChildren + '/gatherings': typeof GatheringsIndexRoute + '/healthcheck': typeof HealthcheckIndexRoute + '/login': typeof LoginIndexRoute + '/gatherings/create': typeof authGatheringsCreateRoute + '/gatherings/$gatheringId': typeof GatheringsGatheringIdIndexRoute + '/gatherings/$gatheringId/update': typeof authGatheringsGatheringIdUpdateRoute + '/bookings/attending': typeof authBookingsAttendingIndexRoute + '/bookings/hosting': typeof authBookingsHostingIndexRoute + '/bookings/hosting/$gatheringId/dashboard/scan': typeof authBookingsHostingGatheringIdDashboardScanRoute + '/bookings/hosting/$gatheringId/dashboard': typeof authBookingsHostingGatheringIdDashboardIndexRoute } export interface FileRoutesByTo { - "/": typeof IndexRoute; - "/bookings": typeof authBookingsRouteRouteWithChildren; - "/gatherings": typeof GatheringsIndexRoute; - "/healthcheck": typeof HealthcheckIndexRoute; - "/login": typeof LoginIndexRoute; - "/gatherings/create": typeof authGatheringsCreateRoute; - "/gatherings/$gatheringId": typeof GatheringsGatheringIdIndexRoute; - "/gatherings/$gatheringId/update": typeof authGatheringsGatheringIdUpdateRoute; - "/bookings/attending": typeof authBookingsAttendingIndexRoute; - "/bookings/hosting": typeof authBookingsHostingIndexRoute; - "/bookings/hosting/$gatheringId/dashboard/scan": typeof authBookingsHostingGatheringIdDashboardScanRoute; - "/bookings/hosting/$gatheringId/dashboard": typeof authBookingsHostingGatheringIdDashboardIndexRoute; + '/': typeof IndexRoute + '/bookings': typeof authBookingsRouteRouteWithChildren + '/gatherings': typeof GatheringsIndexRoute + '/healthcheck': typeof HealthcheckIndexRoute + '/login': typeof LoginIndexRoute + '/gatherings/create': typeof authGatheringsCreateRoute + '/gatherings/$gatheringId': typeof GatheringsGatheringIdIndexRoute + '/gatherings/$gatheringId/update': typeof authGatheringsGatheringIdUpdateRoute + '/bookings/attending': typeof authBookingsAttendingIndexRoute + '/bookings/hosting': typeof authBookingsHostingIndexRoute + '/bookings/hosting/$gatheringId/dashboard/scan': typeof authBookingsHostingGatheringIdDashboardScanRoute + '/bookings/hosting/$gatheringId/dashboard': typeof authBookingsHostingGatheringIdDashboardIndexRoute } export interface FileRoutesById { - __root__: typeof rootRouteImport; - "/": typeof IndexRoute; - "/(auth)/bookings": typeof authBookingsRouteRouteWithChildren; - "/(auth)/gatherings": typeof authGatheringsRouteRouteWithChildren; - "/gatherings/": typeof GatheringsIndexRoute; - "/healthcheck/": typeof HealthcheckIndexRoute; - "/login/": typeof LoginIndexRoute; - "/(auth)/gatherings/create": typeof authGatheringsCreateRoute; - "/gatherings/$gatheringId/": typeof GatheringsGatheringIdIndexRoute; - "/(auth)/gatherings/$gatheringId/update": typeof authGatheringsGatheringIdUpdateRoute; - "/(auth)/bookings/attending/": typeof authBookingsAttendingIndexRoute; - "/(auth)/bookings/hosting/": typeof authBookingsHostingIndexRoute; - "/(auth)/bookings/hosting/$gatheringId/dashboard/scan": typeof authBookingsHostingGatheringIdDashboardScanRoute; - "/(auth)/bookings/hosting/$gatheringId/dashboard/": typeof authBookingsHostingGatheringIdDashboardIndexRoute; + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/(auth)/bookings': typeof authBookingsRouteRouteWithChildren + '/(auth)/gatherings': typeof authGatheringsRouteRouteWithChildren + '/gatherings/': typeof GatheringsIndexRoute + '/healthcheck/': typeof HealthcheckIndexRoute + '/login/': typeof LoginIndexRoute + '/(auth)/gatherings/create': typeof authGatheringsCreateRoute + '/gatherings/$gatheringId/': typeof GatheringsGatheringIdIndexRoute + '/(auth)/gatherings/$gatheringId/update': typeof authGatheringsGatheringIdUpdateRoute + '/(auth)/bookings/attending/': typeof authBookingsAttendingIndexRoute + '/(auth)/bookings/hosting/': typeof authBookingsHostingIndexRoute + '/(auth)/bookings/hosting/$gatheringId/dashboard/scan': typeof authBookingsHostingGatheringIdDashboardScanRoute + '/(auth)/bookings/hosting/$gatheringId/dashboard/': typeof authBookingsHostingGatheringIdDashboardIndexRoute } export interface FileRouteTypes { - fileRoutesByFullPath: FileRoutesByFullPath; - fullPaths: - | "/" - | "/bookings" - | "/gatherings" - | "/healthcheck" - | "/login" - | "/gatherings/create" - | "/gatherings/$gatheringId" - | "/gatherings/$gatheringId/update" - | "/bookings/attending" - | "/bookings/hosting" - | "/bookings/hosting/$gatheringId/dashboard/scan" - | "/bookings/hosting/$gatheringId/dashboard"; - fileRoutesByTo: FileRoutesByTo; - to: - | "/" - | "/bookings" - | "/gatherings" - | "/healthcheck" - | "/login" - | "/gatherings/create" - | "/gatherings/$gatheringId" - | "/gatherings/$gatheringId/update" - | "/bookings/attending" - | "/bookings/hosting" - | "/bookings/hosting/$gatheringId/dashboard/scan" - | "/bookings/hosting/$gatheringId/dashboard"; - id: - | "__root__" - | "/" - | "/(auth)/bookings" - | "/(auth)/gatherings" - | "/gatherings/" - | "/healthcheck/" - | "/login/" - | "/(auth)/gatherings/create" - | "/gatherings/$gatheringId/" - | "/(auth)/gatherings/$gatheringId/update" - | "/(auth)/bookings/attending/" - | "/(auth)/bookings/hosting/" - | "/(auth)/bookings/hosting/$gatheringId/dashboard/scan" - | "/(auth)/bookings/hosting/$gatheringId/dashboard/"; - fileRoutesById: FileRoutesById; + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '/bookings' + | '/gatherings' + | '/healthcheck' + | '/login' + | '/gatherings/create' + | '/gatherings/$gatheringId' + | '/gatherings/$gatheringId/update' + | '/bookings/attending' + | '/bookings/hosting' + | '/bookings/hosting/$gatheringId/dashboard/scan' + | '/bookings/hosting/$gatheringId/dashboard' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '/bookings' + | '/gatherings' + | '/healthcheck' + | '/login' + | '/gatherings/create' + | '/gatherings/$gatheringId' + | '/gatherings/$gatheringId/update' + | '/bookings/attending' + | '/bookings/hosting' + | '/bookings/hosting/$gatheringId/dashboard/scan' + | '/bookings/hosting/$gatheringId/dashboard' + id: + | '__root__' + | '/' + | '/(auth)/bookings' + | '/(auth)/gatherings' + | '/gatherings/' + | '/healthcheck/' + | '/login/' + | '/(auth)/gatherings/create' + | '/gatherings/$gatheringId/' + | '/(auth)/gatherings/$gatheringId/update' + | '/(auth)/bookings/attending/' + | '/(auth)/bookings/hosting/' + | '/(auth)/bookings/hosting/$gatheringId/dashboard/scan' + | '/(auth)/bookings/hosting/$gatheringId/dashboard/' + fileRoutesById: FileRoutesById } export interface RootRouteChildren { - IndexRoute: typeof IndexRoute; - authBookingsRouteRoute: typeof authBookingsRouteRouteWithChildren; - authGatheringsRouteRoute: typeof authGatheringsRouteRouteWithChildren; - GatheringsIndexRoute: typeof GatheringsIndexRoute; - HealthcheckIndexRoute: typeof HealthcheckIndexRoute; - LoginIndexRoute: typeof LoginIndexRoute; - GatheringsGatheringIdIndexRoute: typeof GatheringsGatheringIdIndexRoute; + IndexRoute: typeof IndexRoute + authBookingsRouteRoute: typeof authBookingsRouteRouteWithChildren + authGatheringsRouteRoute: typeof authGatheringsRouteRouteWithChildren + GatheringsIndexRoute: typeof GatheringsIndexRoute + HealthcheckIndexRoute: typeof HealthcheckIndexRoute + LoginIndexRoute: typeof LoginIndexRoute + GatheringsGatheringIdIndexRoute: typeof GatheringsGatheringIdIndexRoute } -declare module "@tanstack/react-router" { - interface FileRoutesByPath { - "/": { - id: "/"; - path: "/"; - fullPath: "/"; - preLoaderRoute: typeof IndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/login/": { - id: "/login/"; - path: "/login"; - fullPath: "/login"; - preLoaderRoute: typeof LoginIndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/healthcheck/": { - id: "/healthcheck/"; - path: "/healthcheck"; - fullPath: "/healthcheck"; - preLoaderRoute: typeof HealthcheckIndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/gatherings/": { - id: "/gatherings/"; - path: "/gatherings"; - fullPath: "/gatherings"; - preLoaderRoute: typeof GatheringsIndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/(auth)/gatherings": { - id: "/(auth)/gatherings"; - path: "/gatherings"; - fullPath: "/gatherings"; - preLoaderRoute: typeof authGatheringsRouteRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/(auth)/bookings": { - id: "/(auth)/bookings"; - path: "/bookings"; - fullPath: "/bookings"; - preLoaderRoute: typeof authBookingsRouteRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/gatherings/$gatheringId/": { - id: "/gatherings/$gatheringId/"; - path: "/gatherings/$gatheringId"; - fullPath: "/gatherings/$gatheringId"; - preLoaderRoute: typeof GatheringsGatheringIdIndexRouteImport; - parentRoute: typeof rootRouteImport; - }; - "/(auth)/gatherings/create": { - id: "/(auth)/gatherings/create"; - path: "/create"; - fullPath: "/gatherings/create"; - preLoaderRoute: typeof authGatheringsCreateRouteImport; - parentRoute: typeof authGatheringsRouteRoute; - }; - "/(auth)/bookings/hosting/": { - id: "/(auth)/bookings/hosting/"; - path: "/hosting"; - fullPath: "/bookings/hosting"; - preLoaderRoute: typeof authBookingsHostingIndexRouteImport; - parentRoute: typeof authBookingsRouteRoute; - }; - "/(auth)/bookings/attending/": { - id: "/(auth)/bookings/attending/"; - path: "/attending"; - fullPath: "/bookings/attending"; - preLoaderRoute: typeof authBookingsAttendingIndexRouteImport; - parentRoute: typeof authBookingsRouteRoute; - }; - "/(auth)/gatherings/$gatheringId/update": { - id: "/(auth)/gatherings/$gatheringId/update"; - path: "/$gatheringId/update"; - fullPath: "/gatherings/$gatheringId/update"; - preLoaderRoute: typeof authGatheringsGatheringIdUpdateRouteImport; - parentRoute: typeof authGatheringsRouteRoute; - }; - "/(auth)/bookings/hosting/$gatheringId/dashboard/": { - id: "/(auth)/bookings/hosting/$gatheringId/dashboard/"; - path: "/hosting/$gatheringId/dashboard"; - fullPath: "/bookings/hosting/$gatheringId/dashboard"; - preLoaderRoute: typeof authBookingsHostingGatheringIdDashboardIndexRouteImport; - parentRoute: typeof authBookingsRouteRoute; - }; - "/(auth)/bookings/hosting/$gatheringId/dashboard/scan": { - id: "/(auth)/bookings/hosting/$gatheringId/dashboard/scan"; - path: "/hosting/$gatheringId/dashboard/scan"; - fullPath: "/bookings/hosting/$gatheringId/dashboard/scan"; - preLoaderRoute: typeof authBookingsHostingGatheringIdDashboardScanRouteImport; - parentRoute: typeof authBookingsRouteRoute; - }; - } +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/login/': { + id: '/login/' + path: '/login' + fullPath: '/login' + preLoaderRoute: typeof LoginIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/healthcheck/': { + id: '/healthcheck/' + path: '/healthcheck' + fullPath: '/healthcheck' + preLoaderRoute: typeof HealthcheckIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/gatherings/': { + id: '/gatherings/' + path: '/gatherings' + fullPath: '/gatherings' + preLoaderRoute: typeof GatheringsIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/(auth)/gatherings': { + id: '/(auth)/gatherings' + path: '/gatherings' + fullPath: '/gatherings' + preLoaderRoute: typeof authGatheringsRouteRouteImport + parentRoute: typeof rootRouteImport + } + '/(auth)/bookings': { + id: '/(auth)/bookings' + path: '/bookings' + fullPath: '/bookings' + preLoaderRoute: typeof authBookingsRouteRouteImport + parentRoute: typeof rootRouteImport + } + '/gatherings/$gatheringId/': { + id: '/gatherings/$gatheringId/' + path: '/gatherings/$gatheringId' + fullPath: '/gatherings/$gatheringId' + preLoaderRoute: typeof GatheringsGatheringIdIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/(auth)/gatherings/create': { + id: '/(auth)/gatherings/create' + path: '/create' + fullPath: '/gatherings/create' + preLoaderRoute: typeof authGatheringsCreateRouteImport + parentRoute: typeof authGatheringsRouteRoute + } + '/(auth)/bookings/hosting/': { + id: '/(auth)/bookings/hosting/' + path: '/hosting' + fullPath: '/bookings/hosting' + preLoaderRoute: typeof authBookingsHostingIndexRouteImport + parentRoute: typeof authBookingsRouteRoute + } + '/(auth)/bookings/attending/': { + id: '/(auth)/bookings/attending/' + path: '/attending' + fullPath: '/bookings/attending' + preLoaderRoute: typeof authBookingsAttendingIndexRouteImport + parentRoute: typeof authBookingsRouteRoute + } + '/(auth)/gatherings/$gatheringId/update': { + id: '/(auth)/gatherings/$gatheringId/update' + path: '/$gatheringId/update' + fullPath: '/gatherings/$gatheringId/update' + preLoaderRoute: typeof authGatheringsGatheringIdUpdateRouteImport + parentRoute: typeof authGatheringsRouteRoute + } + '/(auth)/bookings/hosting/$gatheringId/dashboard/': { + id: '/(auth)/bookings/hosting/$gatheringId/dashboard/' + path: '/hosting/$gatheringId/dashboard' + fullPath: '/bookings/hosting/$gatheringId/dashboard' + preLoaderRoute: typeof authBookingsHostingGatheringIdDashboardIndexRouteImport + parentRoute: typeof authBookingsRouteRoute + } + '/(auth)/bookings/hosting/$gatheringId/dashboard/scan': { + id: '/(auth)/bookings/hosting/$gatheringId/dashboard/scan' + path: '/hosting/$gatheringId/dashboard/scan' + fullPath: '/bookings/hosting/$gatheringId/dashboard/scan' + preLoaderRoute: typeof authBookingsHostingGatheringIdDashboardScanRouteImport + parentRoute: typeof authBookingsRouteRoute + } + } } interface authBookingsRouteRouteChildren { - authBookingsAttendingIndexRoute: typeof authBookingsAttendingIndexRoute; - authBookingsHostingIndexRoute: typeof authBookingsHostingIndexRoute; - authBookingsHostingGatheringIdDashboardScanRoute: typeof authBookingsHostingGatheringIdDashboardScanRoute; - authBookingsHostingGatheringIdDashboardIndexRoute: typeof authBookingsHostingGatheringIdDashboardIndexRoute; + authBookingsAttendingIndexRoute: typeof authBookingsAttendingIndexRoute + authBookingsHostingIndexRoute: typeof authBookingsHostingIndexRoute + authBookingsHostingGatheringIdDashboardScanRoute: typeof authBookingsHostingGatheringIdDashboardScanRoute + authBookingsHostingGatheringIdDashboardIndexRoute: typeof authBookingsHostingGatheringIdDashboardIndexRoute } const authBookingsRouteRouteChildren: authBookingsRouteRouteChildren = { - authBookingsAttendingIndexRoute: authBookingsAttendingIndexRoute, - authBookingsHostingIndexRoute: authBookingsHostingIndexRoute, - authBookingsHostingGatheringIdDashboardScanRoute: - authBookingsHostingGatheringIdDashboardScanRoute, - authBookingsHostingGatheringIdDashboardIndexRoute: - authBookingsHostingGatheringIdDashboardIndexRoute -}; + authBookingsAttendingIndexRoute: authBookingsAttendingIndexRoute, + authBookingsHostingIndexRoute: authBookingsHostingIndexRoute, + authBookingsHostingGatheringIdDashboardScanRoute: + authBookingsHostingGatheringIdDashboardScanRoute, + authBookingsHostingGatheringIdDashboardIndexRoute: + authBookingsHostingGatheringIdDashboardIndexRoute, +} -const authBookingsRouteRouteWithChildren = authBookingsRouteRoute._addFileChildren( - authBookingsRouteRouteChildren -); +const authBookingsRouteRouteWithChildren = + authBookingsRouteRoute._addFileChildren(authBookingsRouteRouteChildren) interface authGatheringsRouteRouteChildren { - authGatheringsCreateRoute: typeof authGatheringsCreateRoute; - authGatheringsGatheringIdUpdateRoute: typeof authGatheringsGatheringIdUpdateRoute; + authGatheringsCreateRoute: typeof authGatheringsCreateRoute + authGatheringsGatheringIdUpdateRoute: typeof authGatheringsGatheringIdUpdateRoute } const authGatheringsRouteRouteChildren: authGatheringsRouteRouteChildren = { - authGatheringsCreateRoute: authGatheringsCreateRoute, - authGatheringsGatheringIdUpdateRoute: authGatheringsGatheringIdUpdateRoute -}; + authGatheringsCreateRoute: authGatheringsCreateRoute, + authGatheringsGatheringIdUpdateRoute: authGatheringsGatheringIdUpdateRoute, +} -const authGatheringsRouteRouteWithChildren = authGatheringsRouteRoute._addFileChildren( - authGatheringsRouteRouteChildren -); +const authGatheringsRouteRouteWithChildren = + authGatheringsRouteRoute._addFileChildren(authGatheringsRouteRouteChildren) const rootRouteChildren: RootRouteChildren = { - IndexRoute: IndexRoute, - authBookingsRouteRoute: authBookingsRouteRouteWithChildren, - authGatheringsRouteRoute: authGatheringsRouteRouteWithChildren, - GatheringsIndexRoute: GatheringsIndexRoute, - HealthcheckIndexRoute: HealthcheckIndexRoute, - LoginIndexRoute: LoginIndexRoute, - GatheringsGatheringIdIndexRoute: GatheringsGatheringIdIndexRoute -}; + IndexRoute: IndexRoute, + authBookingsRouteRoute: authBookingsRouteRouteWithChildren, + authGatheringsRouteRoute: authGatheringsRouteRouteWithChildren, + GatheringsIndexRoute: GatheringsIndexRoute, + HealthcheckIndexRoute: HealthcheckIndexRoute, + LoginIndexRoute: LoginIndexRoute, + GatheringsGatheringIdIndexRoute: GatheringsGatheringIdIndexRoute, +} export const routeTree = rootRouteImport - ._addFileChildren(rootRouteChildren) - ._addFileTypes(); + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/src/evently.client/src/routes/(auth)/gatherings/$gatheringId/update.tsx b/src/evently.client/src/routes/(auth)/gatherings/$gatheringId/update.tsx index 64bf440..1b2c602 100644 --- a/src/evently.client/src/routes/(auth)/gatherings/$gatheringId/update.tsx +++ b/src/evently.client/src/routes/(auth)/gatherings/$gatheringId/update.tsx @@ -1,7 +1,7 @@ import { createFileRoute } from "@tanstack/react-router"; -import { Gathering } from "~/lib/domains/entities"; -import { useState, type JSX } from "react"; -import { getGathering, sleep, updateGathering } from "~/lib/services"; +import { Category, Gathering } from "~/lib/domains/entities"; +import { useEffect, useState, type JSX } from "react"; +import { fetchFile, getCategories, getGathering, sleep, updateGathering } from "~/lib/services"; import { useGatheringForm, type GatheringForm as IGatheringForm @@ -12,14 +12,16 @@ import { GatheringForm } from "~/routes/(auth)/gatherings/-components"; export const Route = createFileRoute("/(auth)/gatherings/$gatheringId/update")({ loader: async ({ params }) => { const gatheringId: number = parseInt(params.gatheringId); - const gathering: Gathering | null = await getGathering(gatheringId); - return gathering ?? new Gathering(); + let gathering: Gathering | null = await getGathering(gatheringId); + gathering = gathering ?? new Gathering(); + const categories: Category[] = await getCategories(); + return { gathering, categories }; }, component: UpdateGatheringPage }); function UpdateGatheringPage(): JSX.Element { - const gathering: Gathering = Route.useLoaderData(); + const { gathering, categories } = Route.useLoaderData(); const navigate = Route.useNavigate(); const defaultGathering: GatheringReqDto = { ...gathering @@ -36,9 +38,21 @@ function UpdateGatheringPage(): JSX.Element { navigate({ to: `/gatherings/${gathering.gatheringId}` }); }; const form: IGatheringForm = useGatheringForm(defaultGathering, onSubmit); + + useEffect(() => { + // set the initial file + (async () => { + const coverSrc: string | null = gathering.coverSrc ?? null; + if (coverSrc == null) { + return; + } + const file: File = await fetchFile(coverSrc); + setFile(file); + })(); + }, [gathering]); return ( <> - + {toastMsg.show && (
diff --git a/src/evently.client/src/routes/(auth)/gatherings/-components/gathering-form.tsx b/src/evently.client/src/routes/(auth)/gatherings/-components/gathering-form.tsx index 8f528c4..07f5df7 100644 --- a/src/evently.client/src/routes/(auth)/gatherings/-components/gathering-form.tsx +++ b/src/evently.client/src/routes/(auth)/gatherings/-components/gathering-form.tsx @@ -3,22 +3,34 @@ import { compressImage, type GatheringForm as IGatheringForm } from "../-service import { FieldErrMsg as FieldInfo } from "~/lib/components"; import { Icon } from "@iconify/react"; import { DateTime } from "luxon"; -import { GatheringReqDto, ToastContent } from "~/lib/domains/models"; +import { GatheringCategoryDetailReqDto, GatheringReqDto, ToastContent } from "~/lib/domains/models"; import { useRouter } from "@tanstack/react-router"; import { toIsoString } from "~/lib/services"; +import { Category } from "~/lib/domains/entities"; + interface GatheringFormProps { file: File | null; setFile: (file: File | null) => void; form: IGatheringForm; + categories: Category[]; } -export function GatheringForm({ file, setFile, form }: GatheringFormProps): JSX.Element { +export function GatheringForm({ + file, + setFile, + form, + categories +}: GatheringFormProps): JSX.Element { const router = useRouter(); const fileName: string = file?.name ?? ""; - const coverSrc: string = - file != null ? URL.createObjectURL(file) : (form.state.values.coverSrc ?? ""); + const coverSrc = file != null ? URL.createObjectURL(file) : (form.state.values.coverSrc ?? ""); + const gathering: GatheringReqDto = form.state.values; const [toastMsg, setToastMsg] = useState(new ToastContent(false)); + const categoryDict: Record = {}; + for (const category of categories) { + categoryDict[category.categoryId] = category; + } useEffect(() => { // prevent memory leak @@ -97,6 +109,61 @@ export function GatheringForm({ file, setFile, form }: GatheringFormProps): JSX. )} /> + ( + <> +
+ Categories +
    + {categories.map((category) => { + const wasChecked = field.state.value.some( + (detail) => detail.categoryId === category.categoryId + ); + return ( +
  • + +
  • + ); + })} +
+
+
+ {field.state.value.map((detail) => ( +
+ {categoryDict[detail.categoryId]?.categoryName} +
+ ))} +
+ + )} + /> + -

{fileName}

{coverSrc != null && coverSrc.trim() !== "" && ( - Floor Plan + <> + Floor Plan +
+ {fileName} + {" "} +
+ )}
diff --git a/src/evently.client/src/routes/(auth)/gatherings/create.tsx b/src/evently.client/src/routes/(auth)/gatherings/create.tsx index bd4985a..b2c3abf 100644 --- a/src/evently.client/src/routes/(auth)/gatherings/create.tsx +++ b/src/evently.client/src/routes/(auth)/gatherings/create.tsx @@ -1,16 +1,21 @@ import { createFileRoute } from "@tanstack/react-router"; -import { Gathering } from "~/lib/domains/entities"; +import { Category, Gathering } from "~/lib/domains/entities"; import { useState, type JSX } from "react"; -import { createGathering, sleep } from "~/lib/services"; +import { createGathering, getCategories, sleep } from "~/lib/services"; import { useGatheringForm, type GatheringForm as IGatheringForm } from "./-services"; import { GatheringReqDto, ToastContent } from "~/lib/domains/models"; import { GatheringForm } from "~/routes/(auth)/gatherings/-components"; export const Route = createFileRoute("/(auth)/gatherings/create")({ + loader: async () => { + const categories: Category[] = await getCategories(); + return { categories }; + }, component: CreateGatheringPage }); function CreateGatheringPage(): JSX.Element { + const { categories } = Route.useLoaderData(); const { account } = Route.useRouteContext(); const accountId: string | undefined = account?.id; @@ -36,7 +41,7 @@ function CreateGatheringPage(): JSX.Element { const form: IGatheringForm = useGatheringForm(defaultGathering, onSubmit); return ( <> - + {toastMsg.show && (
diff --git a/src/evently.client/src/routes/gatherings/index.tsx b/src/evently.client/src/routes/gatherings/index.tsx index 63e176c..4eecb98 100644 --- a/src/evently.client/src/routes/gatherings/index.tsx +++ b/src/evently.client/src/routes/gatherings/index.tsx @@ -22,7 +22,7 @@ export function GatheringsPage(): JSX.Element { const pageSize = 6; const [queryParams, setQueryParams] = useState({ - startDateAfter: new Date(), + endDateAfter: new Date(), offset: 0, limit: pageSize });