diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5418d7f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,66 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${file}" + }, + { + "name": "NPM Start Admin", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}/admin", + "runtimeExecutable": "npm", + "runtimeArgs": [ + "run", + "start" + ], + "console": "integratedTerminal", + }, + { + "name": "NPM Start LIB", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}/admin", + "runtimeExecutable": "ng", + "runtimeArgs": [ + "build", + "@rschneider/ng-daisyui", + "--watch" + ], + "console": "integratedTerminal" + }, + { + "name": "NPM Start REST", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}/server", + "runtimeExecutable": "npm", + "runtimeArgs": [ + "run", + "start:dev" + ], + "preLaunchTask": "Docker Up (Environment)", + "console": "integratedTerminal" + } + ], + "compounds": [ + { + "name": "Full Stack: Docker + App + GUI", + "configurations": [ + "NPM Start LIB", + "NPM Start Admin", + "NPM Start REST" + ], + "stopAll": true + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..28cde63 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.fontFamily": "'FiraCode Nerd Font Mono',Menlo, Monaco, 'Courier New', monospace", + "terminal.integrated.fontFamily": "'FiraCode Nerd Font Mono'", + "markdown.preview.fontFamily": "'FiraCode Nerd Font Mono',-apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', system-ui, 'Ubuntu', 'Droid Sans', sans-serif" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..d9ccd4c --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,18 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Docker Up (Environment)", + "type": "shell", + "command": "docker compose up -d", + "options": { + "cwd": "${workspaceFolder}/environment/dev" + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/admin/openapi/api.json b/admin/openapi/api.json index 0e83ce3..c37b41e 100644 --- a/admin/openapi/api.json +++ b/admin/openapi/api.json @@ -1 +1 @@ -{"openapi":"3.0.0","paths":{"/api":{"get":{"operationId":"AppController_getHello","parameters":[],"responses":{"200":{"description":""}},"tags":["App"]}},"/api/user":{"post":{"operationId":"UserController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserDto"}}}},"responses":{"201":{"description":""}},"tags":["User"]},"get":{"operationId":"UserController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["User"]}},"/api/user/search":{"get":{"operationId":"UserController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["User"]}},"/api/user/{id}":{"get":{"operationId":"UserController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["User"]},"patch":{"operationId":"UserController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserDto"}}}},"responses":{"200":{"description":""}},"tags":["User"]},"delete":{"operationId":"UserController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["User"]}},"/api/auth/login":{"post":{"operationId":"AuthController_login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["Auth"]}},"/api/auth/logout":{"post":{"operationId":"AuthController_logout","parameters":[],"responses":{"201":{"description":""}},"tags":["Auth"]}},"/api/auth/refresh":{"post":{"operationId":"AuthController_refresh","parameters":[],"responses":{"201":{"description":""}},"tags":["Auth"]}},"/api/event-type":{"post":{"operationId":"EventTypesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventTypeDto"}}}},"responses":{"201":{"description":""}},"tags":["EventTypes"]},"get":{"operationId":"EventTypesController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["EventTypes"]}},"/api/event-type/search":{"get":{"operationId":"EventTypesController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventTypes"]}},"/api/event-type/{id}":{"get":{"operationId":"EventTypesController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventTypes"]},"patch":{"operationId":"EventTypesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEventTypeDto"}}}},"responses":{"200":{"description":""}},"tags":["EventTypes"]},"delete":{"operationId":"EventTypesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventTypes"]}},"/api/products":{"post":{"operationId":"ProductsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProductDto"}}}},"responses":{"201":{"description":""}},"tags":["Products"]},"get":{"operationId":"ProductsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["Products"]}},"/api/products/search":{"get":{"operationId":"ProductsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Products"]}},"/api/products/{id}":{"get":{"operationId":"ProductsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Products"]},"patch":{"operationId":"ProductsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProductDto"}}}},"responses":{"200":{"description":""}},"tags":["Products"]},"delete":{"operationId":"ProductsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Products"]}},"/api/events":{"post":{"operationId":"EventsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventDto"}}}},"responses":{"201":{"description":""}},"tags":["Events"]},"get":{"operationId":"EventsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["Events"]}},"/api/events/search":{"get":{"operationId":"EventsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Events"]}},"/api/events/{id}":{"get":{"operationId":"EventsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Events"]},"patch":{"operationId":"EventsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEventDto"}}}},"responses":{"200":{"description":""}},"tags":["Events"]},"delete":{"operationId":"EventsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Events"]}},"/api/user-group":{"post":{"operationId":"UserGroupsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserGroupDto"}}}},"responses":{"201":{"description":""}},"tags":["UserGroups"]},"get":{"operationId":"UserGroupsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["UserGroups"]}},"/api/user-group/search":{"get":{"operationId":"UserGroupsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserGroups"]}},"/api/user-group/{id}":{"get":{"operationId":"UserGroupsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserGroups"]},"patch":{"operationId":"UserGroupsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserGroupDto"}}}},"responses":{"200":{"description":""}},"tags":["UserGroups"]},"delete":{"operationId":"UserGroupsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserGroups"]}},"/api/user-role":{"post":{"operationId":"UserRolesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRoleDto"}}}},"responses":{"201":{"description":""}},"tags":["UserRoles"]},"get":{"operationId":"UserRolesController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["UserRoles"]}},"/api/user-role/search":{"get":{"operationId":"UserRolesController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserRoles"]}},"/api/user-role/{id}":{"get":{"operationId":"UserRolesController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserRoles"]},"patch":{"operationId":"UserRolesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRoleDto"}}}},"responses":{"200":{"description":""}},"tags":["UserRoles"]},"delete":{"operationId":"UserRolesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserRoles"]}},"/api/recurrence-rules":{"post":{"operationId":"RecurrenceRulesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRecurrenceRuleDto"}}}},"responses":{"201":{"description":""}},"tags":["RecurrenceRules"]},"get":{"operationId":"RecurrenceRulesController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]}},"/api/recurrence-rules/search":{"get":{"operationId":"RecurrenceRulesController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]}},"/api/recurrence-rules/{id}":{"get":{"operationId":"RecurrenceRulesController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]},"patch":{"operationId":"RecurrenceRulesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRecurrenceRuleDto"}}}},"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]},"delete":{"operationId":"RecurrenceRulesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]}},"/api/event-exceptions":{"post":{"operationId":"EventExceptionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventExceptionDto"}}}},"responses":{"201":{"description":""}},"tags":["EventExceptions"]},"get":{"operationId":"EventExceptionsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["EventExceptions"]}},"/api/event-exceptions/search":{"get":{"operationId":"EventExceptionsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventExceptions"]}},"/api/event-exceptions/{id}":{"get":{"operationId":"EventExceptionsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventExceptions"]},"patch":{"operationId":"EventExceptionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEventExceptionDto"}}}},"responses":{"200":{"description":""}},"tags":["EventExceptions"]},"delete":{"operationId":"EventExceptionsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventExceptions"]}},"/api/calendar":{"get":{"operationId":"CalendarController_getCalendarEvents","parameters":[],"responses":{"200":{"description":""}},"tags":["Calendar"]}},"/api/calendar/events":{"post":{"operationId":"CalendarController_createEvent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventDto"}}}},"responses":{"201":{"description":""}},"tags":["Calendar"]}},"/api/calendar/events/{id}":{"get":{"operationId":"CalendarController_getEventById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Calendar"]},"patch":{"operationId":"CalendarController_updateEvent","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventDto"}}}},"responses":{"200":{"description":""}},"tags":["Calendar"]},"delete":{"operationId":"CalendarController_deleteEvent","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Calendar"]}},"/api/calendar/events/{id}/exceptions":{"post":{"operationId":"CalendarController_createException","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExceptionDto"}}}},"responses":{"201":{"description":""}},"tags":["Calendar"]}},"/api/calendar/events/{id}/bookings":{"post":{"operationId":"CalendarController_createBooking","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarCreateBookingDto"}}}},"responses":{"201":{"description":""}},"tags":["Calendar"]}},"/api/calendar/bookings/{bookingId}/cancel":{"patch":{"operationId":"CalendarController_cancelBooking","parameters":[{"name":"bookingId","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBookingDto"}}}},"responses":{"200":{"description":""}},"tags":["Calendar"]}},"/api/calendar/bookings/{eventId}":{"get":{"operationId":"CalendarController_getBookings","parameters":[{"name":"eventId","required":true,"in":"path","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"default":"startTime","type":"string"}},{"name":"order","required":false,"in":"query","description":"Sort order","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"startTime","required":true,"in":"query","description":"The start time for the event occurrence (ISO 8601 string)","schema":{"example":"2023-10-27T10:00:00.000Z","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalenderControllerGetBookingResponse"}}}}},"tags":["Calendar"]}},"/api/bookings":{"post":{"operationId":"BookingsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBookingDto"}}}},"responses":{"201":{"description":""}},"tags":["Bookings"]},"get":{"operationId":"BookingsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["Bookings"]}},"/api/bookings/search":{"get":{"operationId":"BookingsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Bookings"]}},"/api/bookings/{id}":{"get":{"operationId":"BookingsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Bookings"]},"patch":{"operationId":"BookingsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBookingDto"}}}},"responses":{"200":{"description":""}},"tags":["Bookings"]},"delete":{"operationId":"BookingsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Bookings"]}},"/api/ping":{"get":{"operationId":"PingController_ping","parameters":[],"responses":{"200":{"description":""}},"tags":["Ping"]}},"/api/ping/auth":{"get":{"operationId":"PingController_pingAuth","parameters":[],"responses":{"200":{"description":""}},"tags":["Ping"]}}},"info":{"title":"DV Booking API","description":"The DV Booking API description","version":"1.0","contact":{}},"tags":[{"name":"dvbooking","description":""}],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http","name":"JWT","description":"Enter JWT token","in":"header"}},"schemas":{"CreateUserDto":{"type":"object","properties":{"username":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"}},"required":["username","email","password"]},"UpdateUserDto":{"type":"object","properties":{"username":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"}},"required":["username","email","password"]},"LoginRequestDto":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}},"required":["username","password"]},"CreateEventTypeDto":{"type":"object","properties":{}},"UpdateEventTypeDto":{"type":"object","properties":{}},"CreateProductDto":{"type":"object","properties":{}},"UpdateProductDto":{"type":"object","properties":{}},"CreateEventDto":{"type":"object","properties":{}},"UpdateEventDto":{"type":"object","properties":{}},"CreateUserGroupDto":{"type":"object","properties":{}},"UpdateUserGroupDto":{"type":"object","properties":{}},"CreateUserRoleDto":{"type":"object","properties":{}},"UpdateUserRoleDto":{"type":"object","properties":{}},"CreateRecurrenceRuleDto":{"type":"object","properties":{}},"UpdateRecurrenceRuleDto":{"type":"object","properties":{}},"CreateEventExceptionDto":{"type":"object","properties":{}},"UpdateEventExceptionDto":{"type":"object","properties":{}},"CreateExceptionDto":{"type":"object","properties":{}},"CalendarCreateBookingDto":{"type":"object","properties":{"occurrenceStartTime":{"format":"date-time","type":"string"},"userId":{"type":"number"},"reservedSeatsCount":{"type":"number"},"notes":{"type":"string"}},"required":["occurrenceStartTime","userId","reservedSeatsCount","notes"]},"CancelBookingDto":{"type":"object","properties":{}},"UserResponseDto":{"type":"object","properties":{"id":{"type":"number"},"username":{"type":"string"}},"required":["id","username"]},"BookingResponseDto":{"type":"object","properties":{"id":{"type":"number"},"eventId":{"type":"number"},"occurrenceStartTime":{"format":"date-time","type":"string"},"notes":{"type":"string"},"reservedSeatsCount":{"type":"number"},"canceledAt":{"type":"string","nullable":true},"createdAt":{"type":"string","nullable":true},"user":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UserResponseDto"}]}},"required":["id","eventId","occurrenceStartTime","reservedSeatsCount","canceledAt","createdAt","user"]},"PaginationResponseMetaDto":{"type":"object","properties":{"totalItems":{"type":"number"},"itemCount":{"type":"number"},"itemsPerPage":{"type":"number"},"totalPages":{"type":"number"},"currentPage":{"type":"number"}},"required":["totalItems","itemCount","itemsPerPage","totalPages","currentPage"]},"CalenderControllerGetBookingResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BookingResponseDto"}},"meta":{"$ref":"#/components/schemas/PaginationResponseMetaDto"}},"required":["data","meta"]},"CreateBookingDto":{"type":"object","properties":{}},"UpdateBookingDto":{"type":"object","properties":{}}}}} \ No newline at end of file +{"openapi":"3.0.0","paths":{"/api":{"get":{"operationId":"AppController_getHello","parameters":[],"responses":{"200":{"description":""}},"tags":["App"]}},"/api/user":{"post":{"operationId":"UserController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserDto"}}}},"responses":{"201":{"description":""}},"tags":["User"]},"get":{"operationId":"UserController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["User"]}},"/api/user/search":{"get":{"operationId":"UserController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["User"]}},"/api/user/{id}":{"get":{"operationId":"UserController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["User"]},"patch":{"operationId":"UserController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserDto"}}}},"responses":{"200":{"description":""}},"tags":["User"]},"delete":{"operationId":"UserController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["User"]}},"/api/auth/login":{"post":{"operationId":"AuthController_login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequestDto"}}}},"responses":{"201":{"description":""}},"tags":["Auth"]}},"/api/auth/logout":{"post":{"operationId":"AuthController_logout","parameters":[],"responses":{"201":{"description":""}},"tags":["Auth"]}},"/api/auth/refresh":{"post":{"operationId":"AuthController_refresh","parameters":[],"responses":{"201":{"description":""}},"tags":["Auth"]}},"/api/event-type":{"post":{"operationId":"EventTypesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventTypeDto"}}}},"responses":{"201":{"description":""}},"tags":["EventTypes"]},"get":{"operationId":"EventTypesController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["EventTypes"]}},"/api/event-type/search":{"get":{"operationId":"EventTypesController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventTypes"]}},"/api/event-type/{id}":{"get":{"operationId":"EventTypesController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventTypes"]},"patch":{"operationId":"EventTypesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEventTypeDto"}}}},"responses":{"200":{"description":""}},"tags":["EventTypes"]},"delete":{"operationId":"EventTypesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventTypes"]}},"/api/products":{"post":{"operationId":"ProductsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProductDto"}}}},"responses":{"201":{"description":""}},"tags":["Products"]},"get":{"operationId":"ProductsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["Products"]}},"/api/products/search":{"get":{"operationId":"ProductsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Products"]}},"/api/products/{id}":{"get":{"operationId":"ProductsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Products"]},"patch":{"operationId":"ProductsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProductDto"}}}},"responses":{"200":{"description":""}},"tags":["Products"]},"delete":{"operationId":"ProductsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Products"]}},"/api/events":{"post":{"operationId":"EventsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventDto"}}}},"responses":{"201":{"description":""}},"tags":["Events"]},"get":{"operationId":"EventsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["Events"]}},"/api/events/search":{"get":{"operationId":"EventsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Events"]}},"/api/events/{id}":{"get":{"operationId":"EventsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Events"]},"patch":{"operationId":"EventsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEventDto"}}}},"responses":{"200":{"description":""}},"tags":["Events"]},"delete":{"operationId":"EventsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Events"]}},"/api/user-group":{"post":{"operationId":"UserGroupsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserGroupDto"}}}},"responses":{"201":{"description":""}},"tags":["UserGroups"]},"get":{"operationId":"UserGroupsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["UserGroups"]}},"/api/user-group/search":{"get":{"operationId":"UserGroupsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserGroups"]}},"/api/user-group/{id}":{"get":{"operationId":"UserGroupsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserGroups"]},"patch":{"operationId":"UserGroupsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserGroupDto"}}}},"responses":{"200":{"description":""}},"tags":["UserGroups"]},"delete":{"operationId":"UserGroupsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserGroups"]}},"/api/user-role":{"post":{"operationId":"UserRolesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserRoleDto"}}}},"responses":{"201":{"description":""}},"tags":["UserRoles"]},"get":{"operationId":"UserRolesController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["UserRoles"]}},"/api/user-role/search":{"get":{"operationId":"UserRolesController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserRoles"]}},"/api/user-role/{id}":{"get":{"operationId":"UserRolesController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserRoles"]},"patch":{"operationId":"UserRolesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRoleDto"}}}},"responses":{"200":{"description":""}},"tags":["UserRoles"]},"delete":{"operationId":"UserRolesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["UserRoles"]}},"/api/recurrence-rules":{"post":{"operationId":"RecurrenceRulesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRecurrenceRuleDto"}}}},"responses":{"201":{"description":""}},"tags":["RecurrenceRules"]},"get":{"operationId":"RecurrenceRulesController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]}},"/api/recurrence-rules/search":{"get":{"operationId":"RecurrenceRulesController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]}},"/api/recurrence-rules/{id}":{"get":{"operationId":"RecurrenceRulesController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]},"patch":{"operationId":"RecurrenceRulesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRecurrenceRuleDto"}}}},"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]},"delete":{"operationId":"RecurrenceRulesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["RecurrenceRules"]}},"/api/event-exceptions":{"post":{"operationId":"EventExceptionsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventExceptionDto"}}}},"responses":{"201":{"description":""}},"tags":["EventExceptions"]},"get":{"operationId":"EventExceptionsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["EventExceptions"]}},"/api/event-exceptions/search":{"get":{"operationId":"EventExceptionsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventExceptions"]}},"/api/event-exceptions/{id}":{"get":{"operationId":"EventExceptionsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventExceptions"]},"patch":{"operationId":"EventExceptionsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEventExceptionDto"}}}},"responses":{"200":{"description":""}},"tags":["EventExceptions"]},"delete":{"operationId":"EventExceptionsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["EventExceptions"]}},"/api/calendar":{"get":{"operationId":"CalendarController_getCalendarEvents","parameters":[],"responses":{"200":{"description":""}},"tags":["Calendar"]}},"/api/calendar/events":{"post":{"operationId":"CalendarController_createEvent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventDto"}}}},"responses":{"201":{"description":""}},"tags":["Calendar"]}},"/api/calendar/events/{id}":{"get":{"operationId":"CalendarController_getEventById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Calendar"]},"patch":{"operationId":"CalendarController_updateEvent","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventDto"}}}},"responses":{"200":{"description":""}},"tags":["Calendar"]},"delete":{"operationId":"CalendarController_deleteEvent","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Calendar"]}},"/api/calendar/events/{id}/exceptions":{"post":{"operationId":"CalendarController_createException","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExceptionDto"}}}},"responses":{"201":{"description":""}},"tags":["Calendar"]}},"/api/calendar/events/{id}/bookings":{"post":{"operationId":"CalendarController_createBooking","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarCreateBookingDto"}}}},"responses":{"201":{"description":""}},"tags":["Calendar"]}},"/api/calendar/bookings/{bookingId}/cancel":{"patch":{"operationId":"CalendarController_cancelBooking","parameters":[{"name":"bookingId","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBookingDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalenderControllerGetBookingResponse"}}}}},"tags":["Calendar"]}},"/api/calendar/bookings/{eventId}":{"get":{"operationId":"CalendarController_getBookings","parameters":[{"name":"eventId","required":true,"in":"path","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"default":10,"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Field to sort by","schema":{"default":"startTime","type":"string"}},{"name":"order","required":false,"in":"query","description":"Sort order","schema":{"default":"ASC","type":"string","enum":["ASC","DESC"]}},{"name":"startTime","required":true,"in":"query","description":"The start time for the event occurrence (ISO 8601 string)","schema":{"example":"2023-10-27T10:00:00.000Z","type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalenderControllerGetBookingResponse"}}}}},"tags":["Calendar"]}},"/api/bookings":{"post":{"operationId":"BookingsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBookingDto"}}}},"responses":{"201":{"description":""}},"tags":["Bookings"]},"get":{"operationId":"BookingsController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["Bookings"]}},"/api/bookings/search":{"get":{"operationId":"BookingsController_search","parameters":[{"name":"q","required":true,"in":"query","schema":{"type":"string"}},{"name":"page","required":true,"in":"query","schema":{"type":"number"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Bookings"]}},"/api/bookings/{id}":{"get":{"operationId":"BookingsController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Bookings"]},"patch":{"operationId":"BookingsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateBookingDto"}}}},"responses":{"200":{"description":""}},"tags":["Bookings"]},"delete":{"operationId":"BookingsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Bookings"]}},"/api/ping":{"get":{"operationId":"PingController_ping","parameters":[],"responses":{"200":{"description":""}},"tags":["Ping"]}},"/api/ping/auth":{"get":{"operationId":"PingController_pingAuth","parameters":[],"responses":{"200":{"description":""}},"tags":["Ping"]}}},"info":{"title":"DV Booking API","description":"The DV Booking API description","version":"1.0","contact":{}},"tags":[{"name":"dvbooking","description":""}],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http","name":"JWT","description":"Enter JWT token","in":"header"}},"schemas":{"CreateUserDto":{"type":"object","properties":{"username":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"}},"required":["username","email","password"]},"UpdateUserDto":{"type":"object","properties":{"username":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"}},"required":["username","email","password"]},"LoginRequestDto":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}},"required":["username","password"]},"CreateEventTypeDto":{"type":"object","properties":{}},"UpdateEventTypeDto":{"type":"object","properties":{}},"CreateProductDto":{"type":"object","properties":{}},"UpdateProductDto":{"type":"object","properties":{}},"CreateEventDto":{"type":"object","properties":{}},"UpdateEventDto":{"type":"object","properties":{}},"CreateUserGroupDto":{"type":"object","properties":{}},"UpdateUserGroupDto":{"type":"object","properties":{}},"CreateUserRoleDto":{"type":"object","properties":{}},"UpdateUserRoleDto":{"type":"object","properties":{}},"CreateRecurrenceRuleDto":{"type":"object","properties":{}},"UpdateRecurrenceRuleDto":{"type":"object","properties":{}},"CreateEventExceptionDto":{"type":"object","properties":{}},"UpdateEventExceptionDto":{"type":"object","properties":{}},"CreateExceptionDto":{"type":"object","properties":{}},"CalendarCreateBookingDto":{"type":"object","properties":{"occurrenceStartTime":{"format":"date-time","type":"string"},"userId":{"type":"number"},"reservedSeatsCount":{"type":"number"},"notes":{"type":"string"}},"required":["occurrenceStartTime","userId","reservedSeatsCount","notes"]},"CancelBookingDto":{"type":"object","properties":{"canceledReason":{"type":"string"}},"required":["canceledReason"]},"UserResponseDto":{"type":"object","properties":{"id":{"type":"number"},"username":{"type":"string"}},"required":["id","username"]},"BookingResponseDto":{"type":"object","properties":{"id":{"type":"number"},"eventId":{"type":"number"},"occurrenceStartTime":{"format":"date-time","type":"string"},"notes":{"type":"string"},"reservedSeatsCount":{"type":"number"},"canceledAt":{"type":"string","nullable":true},"createdAt":{"type":"string","nullable":true},"user":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UserResponseDto"}]},"status":{"type":"string"}},"required":["id","eventId","occurrenceStartTime","reservedSeatsCount","canceledAt","createdAt","user"]},"PaginationResponseMetaDto":{"type":"object","properties":{"totalItems":{"type":"number"},"itemCount":{"type":"number"},"itemsPerPage":{"type":"number"},"totalPages":{"type":"number"},"currentPage":{"type":"number"}},"required":["totalItems","itemCount","itemsPerPage","totalPages","currentPage"]},"CalenderControllerGetBookingResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BookingResponseDto"}},"meta":{"$ref":"#/components/schemas/PaginationResponseMetaDto"}},"required":["data","meta"]},"CreateBookingDto":{"type":"object","properties":{}},"UpdateBookingDto":{"type":"object","properties":{}}}}} \ No newline at end of file diff --git a/admin/src/api/models/index.ts b/admin/src/api/models/index.ts index f7e47f6..1ff152e 100644 --- a/admin/src/api/models/index.ts +++ b/admin/src/api/models/index.ts @@ -78,6 +78,7 @@ export interface CalendarCreateBookingDto { } export interface CancelBookingDto { + canceledReason: string; } export interface UserResponseDto { @@ -94,6 +95,7 @@ export interface BookingResponseDto { canceledAt: string | null; createdAt: string | null; user: UserResponseDto; + status?: string; } export interface PaginationResponseMetaDto { diff --git a/admin/src/api/services/calendar.service.ts b/admin/src/api/services/calendar.service.ts index 7baf582..243614c 100644 --- a/admin/src/api/services/calendar.service.ts +++ b/admin/src/api/services/calendar.service.ts @@ -137,9 +137,9 @@ export class CalendarService { return this.httpClient.post(url, calendarCreateBookingDto, requestOptions); } - calendarControllerCancelBooking(bookingId: number, cancelBookingDto: CancelBookingDto, observe?: 'body', options?: RequestOptions<'json'>): Observable; - calendarControllerCancelBooking(bookingId: number, cancelBookingDto: CancelBookingDto, observe?: 'response', options?: RequestOptions<'json'>): Observable>; - calendarControllerCancelBooking(bookingId: number, cancelBookingDto: CancelBookingDto, observe?: 'events', options?: RequestOptions<'json'>): Observable>; + calendarControllerCancelBooking(bookingId: number, cancelBookingDto: CancelBookingDto, observe?: 'body', options?: RequestOptions<'json'>): Observable; + calendarControllerCancelBooking(bookingId: number, cancelBookingDto: CancelBookingDto, observe?: 'response', options?: RequestOptions<'json'>): Observable>; + calendarControllerCancelBooking(bookingId: number, cancelBookingDto: CancelBookingDto, observe?: 'events', options?: RequestOptions<'json'>): Observable>; calendarControllerCancelBooking(bookingId: number, cancelBookingDto: CancelBookingDto, observe?: 'body' | 'events' | 'response', options?: RequestOptions<'arraybuffer' | 'blob' | 'json' | 'text'>): Observable { const url = `${this.basePath}/api/calendar/bookings/${bookingId}/cancel`; diff --git a/admin/src/app/features/calendar/components/calendar-view/calendar-view.html b/admin/src/app/features/calendar/components/calendar-view/calendar-view.html index 5c1a323..f5cfd32 100644 --- a/admin/src/app/features/calendar/components/calendar-view/calendar-view.html +++ b/admin/src/app/features/calendar/components/calendar-view/calendar-view.html @@ -5,26 +5,22 @@ @if (workflow() == 'event_create') { - + } @if (workflow() == 'event_dashboard' && selectedEvent()) { - - - + + + } -@for (dialogDefinition of dialogs; track dialogDefinition) { +@for (dialogDefinition of dialogs; track dialogDefinition) { - @if (dialogDefinition.isRendered()) { - - - - } +@if (dialogDefinition.isRendered()) { + + + } +} \ No newline at end of file diff --git a/admin/src/app/features/calendar/components/calendar-view/calendar-view.ts b/admin/src/app/features/calendar/components/calendar-view/calendar-view.ts index a9c0b68..d27cd6b 100644 --- a/admin/src/app/features/calendar/components/calendar-view/calendar-view.ts +++ b/admin/src/app/features/calendar/components/calendar-view/calendar-view.ts @@ -79,14 +79,24 @@ export class CalendarView { } }); - this.eventBus.on(EventType.CALENDAR_VIEW_DIALOG_CLOSED) + this.eventBus.on(EventType.CALENDAR_VIEW_CLOSE_DIALOG_AND_RELOAD) .pipe(takeUntilDestroyed()) .subscribe({ next: (_) => { this.closeDialog(); + this.calendarComponent?.getApi().refetchEvents(); } }) + this.eventBus.on(EventType.CALENDAR_VIEW_EVENT_DASHBOARD) + .pipe(takeUntilDestroyed()) + .subscribe({ + next: (_) => { + this.openDashboard(); + } + }) + + this.calendarOptions = { plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin], @@ -237,16 +247,16 @@ export class CalendarView { }), ) .subscribe({ - next: (events) => { - console.info('calendar events', events); - successCallback(events); - } - , - error: (error) => { - console.error('Error fetching events', error); - failureCallback(error); - }, + next: (events) => { + console.info('calendar events', events); + successCallback(events); + } + , + error: (error) => { + console.error('Error fetching events', error); + failureCallback(error); }, + }, ); } @@ -254,7 +264,9 @@ export class CalendarView { closeDialog() { this.workflow.set('NO_DIALOG'); } - + openDashboard() { + this.workflow.set('event_dashboard'); + } /** * Set dashboard workflow * @param workflowType diff --git a/admin/src/app/features/calendar/components/calendar-view/single-event-booking-list/single-event-booking-list.html b/admin/src/app/features/calendar/components/calendar-view/single-event-booking-list/single-event-booking-list.html index 35dced0..61df649 100644 --- a/admin/src/app/features/calendar/components/calendar-view/single-event-booking-list/single-event-booking-list.html +++ b/admin/src/app/features/calendar/components/calendar-view/single-event-booking-list/single-event-booking-list.html @@ -2,37 +2,52 @@ Foglalások @if (bookings.isLoading()) { -
loading...
+
loading...
} @else { - @if (bookings.value()?.data?.length) { -
- - - - - - - - - - - @for (booking of bookings.value()?.data; track booking) { - - - - - +@if (bookings.value()?.data?.length) { +
+
Foglalás dátumaFoglalt helyek száma
{{formatDateTime(booking.createdAt)}}{{booking.reservedSeatsCount}} - Lemondás -
+ + + + + + + + + + + @for (booking of bookings.value()?.data; track booking) { + + + + -
Foglalás dátumaFoglalt helyek számaStátusz
{{formatDateTime(booking.createdAt)}}{{booking.reservedSeatsCount}} + @switch (booking.status){ + @case ('active'){ + } -
-
- @if(bookings.value()?.meta?.totalPages! > 1){ - - } - } @else { - Nem találtunk foglalást erre az eseményre - } + @case ('customer_cancelled'){ + + } + } + + + @if (booking.status == 'active') { + + Lemondás + + } + + + } + + + +@if(bookings.value()?.meta?.totalPages! > 1){ + } +} @else { +Nem találtunk foglalást erre az eseményre +} +} \ No newline at end of file diff --git a/admin/src/app/features/calendar/components/calendar-view/single-event-booking-list/single-event-booking-list.ts b/admin/src/app/features/calendar/components/calendar-view/single-event-booking-list/single-event-booking-list.ts index 81f8c92..9042033 100644 --- a/admin/src/app/features/calendar/components/calendar-view/single-event-booking-list/single-event-booking-list.ts +++ b/admin/src/app/features/calendar/components/calendar-view/single-event-booking-list/single-event-booking-list.ts @@ -7,6 +7,9 @@ import { delay, of, throwError } from 'rxjs'; import { Button, Pagination } from '@rschneider/ng-daisyui'; import { Heading } from '../../../../../components/heading/heading'; import { format } from 'date-fns'; +import { EventType } from '../../../../../../types'; +import { SvgIcons } from '../../../../../svg-icons'; +import { SafeHtmlPipe } from "../../../../../pipes/safe-html-pipe"; @Component({ selector: 'app-single-event-booking-list', @@ -14,6 +17,7 @@ import { format } from 'date-fns'; Pagination, Heading, Button, + SafeHtmlPipe ], templateUrl: './single-event-booking-list.html', styleUrl: './single-event-booking-list.css', @@ -30,57 +34,64 @@ export class SingleEventBookingList { pageCount = computed(() => { // return this.bookings.value()?.pageCount || 1; return 1; - }) + }); bookings = rxResource( { params: () => ({ - page: this.activePage() + page: this.activePage(), }), - stream: ({params}) => { + stream: ({ params }) => { - // console.info("loading resource", params); - // - // const allData = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"] - // - // let pageCount = Math.floor( allData.length / this.pageSize()); - // if ( (allData.length % this.pageSize()) > 0){ - // pageCount += 1; - // } - // pageCount = Math.max(pageCount ,1); - // - // const pageData = allData.slice( ((this.activePage()-1) * this.pageSize()),this.activePage()*this.pageSize()); - // console.info("booking page data",pageData); - // return of({ - // items: pageData, - // pageCount - // }).pipe( delay(1000)) - if ( !this.event()){ - return throwError( () => new Error("no event")) + if (!this.event()) { + return throwError(() => new Error('no event')); } const event = this.event()!; return this.calendarService.calendarControllerGetBookings( event.id, - new Date(event.startTime).toISOString() - ) + new Date(event.startTime).toISOString(), + params.page, + this.pageSize(), + ); }, - } - ) + }, + ); protected paginate($event: number) { - console.info("paginated to ", $event) + console.info('paginated to ', $event); this.activePage.set($event); + } - formatDateTime( dateStr?: string|Date|null){ - if ( !dateStr ){ - return ""; + public cancelBooking(booking: BookingResponseDto) { + this.calendarService.calendarControllerCancelBooking( + booking.id, + { + canceledReason: 'customer_cancelled', + }, + ).subscribe({ + next: () => { + // this.eventBus.emit(EventType.CALENDAR_VIEW_BOOKING_CANCELLED, ''); + this.bookings.reload(); + }, + error: () => { + // todo: handle error + } + }); + } + + + formatDateTime(dateStr?: string | Date | null) { + if (!dateStr) { + return ''; } - return format(new Date(dateStr),'yyyy-MM-dd HH:mm'); + return format(new Date(dateStr), 'yyyy-MM-dd HH:mm'); } protected readonly format = format; + + protected readonly SvgIcons = SvgIcons; } diff --git a/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard-event-activation/single-event-dashboard-event-activation.component.ts b/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard-event-activation/single-event-dashboard-event-activation.component.ts index 87ff169..f8fbc1c 100644 --- a/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard-event-activation/single-event-dashboard-event-activation.component.ts +++ b/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard-event-activation/single-event-dashboard-event-activation.component.ts @@ -43,9 +43,9 @@ export class SingleEventDashboardEventActivation { if (eventException) { payload = { ...eventException, - originalStartTime: new Date(eventException.originalStartTime), + originalStartTime: new Date(eventException.originalStartTime), newStartTime: eventException.newStartTime ? new Date(eventException.newStartTime) : undefined, - newEndTime: eventException.newEndTime ? new Date(eventException.newEndTime) :undefined, + newEndTime: eventException.newEndTime ? new Date(eventException.newEndTime) : undefined, isCancelled: !activated, }; } else { @@ -55,7 +55,7 @@ export class SingleEventDashboardEventActivation { }; } - this.calendarService.applyException(eventId, payload ).subscribe( + this.calendarService.applyException(eventId, payload).subscribe( { next: () => { this.eventBus.emit(EventType.CALENDAR_VIEW_EVENT_SAVED, 'Event saved') @@ -77,7 +77,7 @@ export class SingleEventDashboardEventActivation { } protected closeDialog() { - this.eventBus.emit(EventType.CALENDAR_VIEW_DIALOG_CLOSED, 'Event saved') + this.eventBus.emit(EventType.CALENDAR_VIEW_EVENT_DASHBOARD, 'Event saved') } } diff --git a/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard-event-edit/single-event-dashboard-event-edit.ts b/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard-event-edit/single-event-dashboard-event-edit.ts index ff461ba..4686131 100644 --- a/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard-event-edit/single-event-dashboard-event-edit.ts +++ b/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard-event-edit/single-event-dashboard-event-edit.ts @@ -22,12 +22,12 @@ export class SingleEventDashboardEventEdit { * proxy to ready event from form to parent */ protected triggerAction(action: ReadyType) { - if ( action == 'save-event-success'){ - this.eventBus.emit(EventType.CALENDAR_VIEW_EVENT_SAVED,''); - }else if ( action == 'save-event-failed'){ - this.eventBus.emit(EventType.CALENDAR_VIEW_DIALOG_CLOSED,''); - }else{ - this.eventBus.emit(EventType.CALENDAR_VIEW_DIALOG_CLOSED,''); + if (action == 'save-event-success') { + this.eventBus.emit(EventType.CALENDAR_VIEW_EVENT_SAVED, ''); + } else if (action == 'save-event-failed') { + this.eventBus.emit(EventType.CALENDAR_VIEW_DIALOG_CLOSED, ''); + } else { + this.eventBus.emit(EventType.CALENDAR_VIEW_EVENT_DASHBOARD, ''); } } } diff --git a/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard/single-event-dashboard.ts b/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard/single-event-dashboard.ts index 9546bc7..4404f5a 100644 --- a/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard/single-event-dashboard.ts +++ b/admin/src/app/features/calendar/components/calendar-view/single-event-dashboard/single-event-dashboard.ts @@ -28,65 +28,65 @@ export class SingleEventDashboard { constructor() { effect(() => { - this.cards.set( [ - { - buttonTitle: 'Szerkesztés', - title: 'Szerkesztés', - svgIcon: SvgIcons.heorPencilSquare, - description: 'Az esemény módosítása', - workflow: 'event_edit', - }, - - this.event()?.isCancelled ? - + this.cards.set([ { - buttonTitle: 'Aktiválás', - title: 'Előfordulás aktiválása', - svgIcon: SvgIcons.heroPlay, - description: 'Az esemény ezen előfordulásának aktiválása', - workflow: 'event_activate', - } : - { - buttonTitle: 'Lemondás', - title: 'Előfordulás lemondása', - svgIcon: SvgIcons.heroXcircle, - description: 'Az esemény ezen előfordulásának lemondása', - workflow: 'event_cancel', - }, - { - buttonTitle: 'Törlés', - title: 'Esemény törlése', - svgIcon: SvgIcons.heroTrash, - description: 'Az esemény törlése', - workflow: 'event_delete', - }, - { - buttonTitle: 'Megnézem', - title: 'Foglalások', - svgIcon: SvgIcons.heroUserGroup, - description: 'Foglalások megtekintése', - workflow: 'booking_list', - }, - { - buttonTitle: 'Bejelentkezés', - title: 'Időpont foglalás', - svgIcon: SvgIcons.heroUserPlus, - description: 'Időpont foglalása eseményre', - workflow: 'booking_create', - }, - { - buttonTitle: 'Lemondás', - title: 'Lemondás', - svgIcon: SvgIcons.heroUserMinus, - description: 'Az időpont lemondása', - workflow: 'booking_cancel', - }, - ]); + buttonTitle: 'Szerkesztés', + title: 'Szerkesztés', + svgIcon: SvgIcons.heorPencilSquare, + description: 'Az esemény módosítása', + workflow: 'event_edit', + }, + + this.event()?.isCancelled ? + + { + buttonTitle: 'Aktiválás', + title: 'Előfordulás aktiválása', + svgIcon: SvgIcons.heroPlay, + description: 'Az esemény ezen előfordulásának aktiválása', + workflow: 'event_activate', + } : + { + buttonTitle: 'Lemondás', + title: 'Előfordulás lemondása', + svgIcon: SvgIcons.heroXcircle, + description: 'Az esemény ezen előfordulásának lemondása', + workflow: 'event_cancel', + }, + { + buttonTitle: 'Törlés', + title: 'Esemény törlése', + svgIcon: SvgIcons.heroTrash, + description: 'Az esemény törlése', + workflow: 'event_delete', + }, + { + buttonTitle: 'Megnézem', + title: 'Foglalások', + svgIcon: SvgIcons.heroUserGroup, + description: 'Foglalások megtekintése', + workflow: 'booking_list', + }, + { + buttonTitle: 'Bejelentkezés', + title: 'Időpont foglalás', + svgIcon: SvgIcons.heroUserPlus, + description: 'Időpont foglalása eseményre', + workflow: 'booking_create', + }, + { + buttonTitle: 'Lemondás', + title: 'Lemondás', + svgIcon: SvgIcons.heroUserMinus, + description: 'Az időpont lemondása', + workflow: 'booking_cancel', + }, + ]); }); } - onCardAction (action: WORKFLOW_TYPE) { - if ( action ){ + onCardAction(action: WORKFLOW_TYPE) { + if (action) { this.action.emit(action); } console.info("card action", action); diff --git a/admin/src/app/features/calendar/components/create-event-form/create-event-form.html b/admin/src/app/features/calendar/components/create-event-form/create-event-form.html index 32bc59f..5e990f6 100644 --- a/admin/src/app/features/calendar/components/create-event-form/create-event-form.html +++ b/admin/src/app/features/calendar/components/create-event-form/create-event-form.html @@ -1,115 +1,108 @@
-

- Esemény {{ isEditMode ? 'szerkesztése' : 'létrehozása' }} -

+

+ Esemény {{ isEditMode ? 'szerkesztése' : 'létrehozása' }} +

-
+ -
- -
+
+ +
-
- -
- -
-
- -
-
- -
-
- -
- - @if (isRecurring?.value === true) { -
-

Ismétlődés

- -
- - -
- -
- - -
- -
- -
- @for (day of weekDayOptions; track day.value) { - - } -
-
- -
- - -
- Vesszővel elválasztott lista (pl. 1,15,31) -
-
- -
- - -
- Vesszővel elválasztott lista (pl. 1,2,3) -
-
- -
- - -
-
+
+ +
-
- Mégse - +
+ +
+ +
+ +
+ +
+ +
+ +
+ + @if (isRecurring?.value === true) { +
+

Ismétlődés

+ +
+ + +
+ +
+ + +
+ +
+ +
+ @for (day of weekDayOptions; track day.value) { + + }
- -
+
+ +
+ + +
+ Vesszővel elválasztott lista (pl. 1,15,31) +
+
+ +
+ + +
+ Vesszővel elválasztott lista (pl. 1,2,3) +
+
+ +
+ + +
+
+ } + +
+ + Mégse +
+ +
\ No newline at end of file diff --git a/admin/src/app/svg-icons.ts b/admin/src/app/svg-icons.ts index 334c2c0..0fe0429 100644 --- a/admin/src/app/svg-icons.ts +++ b/admin/src/app/svg-icons.ts @@ -39,9 +39,24 @@ export class SvgIcons { ` - public static heroPlay = ` + public static heroPlay = ` `; + public static heroMinusCircle = ` + + +`; + + public static heroBadgeCircle = ` + + +`; + + public static heroCheckCircle = ` + + + +`; } diff --git a/admin/src/types.ts b/admin/src/types.ts index 304ab75..a427f18 100644 --- a/admin/src/types.ts +++ b/admin/src/types.ts @@ -1,5 +1,5 @@ -export interface AppConfig{ +export interface AppConfig { apiUrl: string; apiBaseUrl: string; } @@ -19,8 +19,11 @@ export enum EventType { USER_LOGGED_IN = 'USER_LOGGED_IN', ORDER_CREATED = 'ORDER_CREATED', THEME_CHANGED = 'THEME_CHANGED', + CALENDAR_VIEW_EVENT_DASHBOARD = 'CALENDAR_VIEW_EVENT_DASHBOARD', CALENDAR_VIEW_EVENT_SAVED = 'CALENDAR_VIEW_EVENT_SAVED', - CALENDAR_VIEW_DIALOG_CLOSED = 'CALENDAR_VIEW_DIALOG_CLOSED' + CALENDAR_VIEW_DIALOG_CLOSED = 'CALENDAR_VIEW_DIALOG_CLOSED', + CALENDAR_VIEW_BOOKING_CANCELLED = 'CALENDAR_VIEW_BOOKING_CANCELLED', + CALENDAR_VIEW_CLOSE_DIALOG_AND_RELOAD = 'CALENDAR_VIEW_CLOSE_DIALOG_AND_RELOAD' } @@ -30,6 +33,10 @@ export interface EventMap { [EventType.ORDER_CREATED]: { orderId: number }; [EventType.CALENDAR_VIEW_EVENT_SAVED]: string; [EventType.CALENDAR_VIEW_DIALOG_CLOSED]: string; + [EventType.CALENDAR_VIEW_DIALOG_CLOSED]: string; + [EventType.CALENDAR_VIEW_BOOKING_CANCELLED]: string; + [EventType.CALENDAR_VIEW_CLOSE_DIALOG_AND_RELOAD]: string; + [EventType.CALENDAR_VIEW_EVENT_DASHBOARD]: string; } export interface AppEvent { diff --git a/dius.txt b/dius.txt new file mode 100644 index 0000000..2a58a22 --- /dev/null +++ b/dius.txt @@ -0,0 +1,8 @@ + +NAiP +file:///Users/rschneider/Library/Fonts/FiraCodeNerdFontMono-Light.ttf#postscript-name=FiraCodeNFM-Light +file:///Users/rschneider/Library/Fonts/FiraCodeNerdFontMono-Regular.ttf#postscript-name=FiraCodeNFM-Reg +file:///Users/rschneider/Library/Fonts/FiraCodeNerdFontMono-Retina.ttf#postscript-name=FiraCodeNFM-Ret +file:///Users/rschneider/Library/Fonts/FiraCodeNerdFontMono-Medium.ttf#postscript-name=FiraCodeNFM-Med +file:///Users/rschneider/Library/Fonts/FiraCodeNerdFontMono-SemiBold.ttf#postscript-name=FiraCodeNFM-SemBd +file:///Users/rschneider/Library/Fonts/FiraCodeNerdFontMono-Bold.ttf#postscript-name=FiraCodeNFM-Bold \ No newline at end of file diff --git a/server/src/calendar/calendar.controller.ts b/server/src/calendar/calendar.controller.ts index ec84105..0f1cde5 100644 --- a/server/src/calendar/calendar.controller.ts +++ b/server/src/calendar/calendar.controller.ts @@ -31,7 +31,7 @@ import { CalenderControllerGetBookingResponse } from './dto/booking.response.dto @UseGuards(JwtAuthGuard, RolesGuard) @Roles(Role.Admin) export class CalendarController { - constructor(private readonly calendarService: CalendarService) {} + constructor(private readonly calendarService: CalendarService) { } @Get() getCalendarEvents(@Query() getCalendarDto: GetCalendarDto) { @@ -110,6 +110,7 @@ export class CalendarController { @ApiCreatedResponse({ type: CalenderControllerGetBookingResponse }) // Removed generic for cleaner syntax unless defined elsewhere // Ensure ValidationPipe is enabled with transform: true (Global or Method scoped) // @UsePipes(new ValidationPipe({ transform: true })) + @Roles(Role.Admin, Role.User) async getBookings( @User() user: types.AppUser, @Param('eventId', ParseIntPipe) eventId: number, @@ -117,7 +118,7 @@ export class CalendarController { @Query() calendarGetBookingDto: CalendarGetBookingDto, ) { return this.calendarService.getBookings( - user.user!.userId, + user, eventId, calendarGetBookingDto, ); diff --git a/server/src/calendar/calendar.service.ts b/server/src/calendar/calendar.service.ts index fbce5fb..e4e956f 100644 --- a/server/src/calendar/calendar.service.ts +++ b/server/src/calendar/calendar.service.ts @@ -28,6 +28,8 @@ import { BookingResponseDto, CalenderControllerGetBookingResponse, } from './dto/booking.response.dto'; +import { AppUser } from 'src/types'; +import { Role } from '../auth/role.enum'; // --- Type-Safe Maps --- const frequencyMap: Record = { @@ -82,7 +84,7 @@ export class CalendarService { private readonly eventExceptionRepository: Repository, @InjectRepository(Booking) private readonly bookingRepository: Repository, - ) {} + ) { } async getEventsInRange( startDate: Date, @@ -606,7 +608,7 @@ export class CalendarService { } async getBookings( - userId: number, + user: AppUser, eventId: number, queryParams: CalendarGetBookingDto, ): Promise { @@ -621,6 +623,13 @@ export class CalendarService { ['createdAt']: order!, }, }; + + if (!user.user?.roles.includes(Role.Admin)) { + findOptions.where = { + ...findOptions.where, + userId: user.user!.userId, + }; + } const paginated = limit > 0; const [data, totalItems] = await this.bookingRepository.findAndCount(findOptions); diff --git a/server/src/calendar/dto/booking.response.dto.ts b/server/src/calendar/dto/booking.response.dto.ts index 1f3374a..8cfb8a1 100644 --- a/server/src/calendar/dto/booking.response.dto.ts +++ b/server/src/calendar/dto/booking.response.dto.ts @@ -32,6 +32,9 @@ export class BookingResponseDto { }) user?: UserResponseDto; + @ApiProperty({ required: false }) + status?: string; + constructor(booking: Booking) { this.id = Number(booking.id); // Handle BigInt conversion this.eventId = Number(booking.eventId); @@ -46,6 +49,14 @@ export class BookingResponseDto { // Assuming User entity has firstName/lastName this.user = new UserResponseDto(booking.user); } + this.status = 'active'; + if (booking.canceledAt) { + if (booking.canceledReason == 'customer_cancelled') { + this.status = 'customer_cancelled'; + } else { + this.status = 'cancelled'; + } + } } } diff --git a/server/src/calendar/dto/cancel-booking.dto.ts b/server/src/calendar/dto/cancel-booking.dto.ts index 62d24b8..370fbb6 100644 --- a/server/src/calendar/dto/cancel-booking.dto.ts +++ b/server/src/calendar/dto/cancel-booking.dto.ts @@ -1,14 +1,12 @@ import { - IsInt, - IsNotEmpty, IsOptional, IsString, MaxLength, } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; export class CancelBookingDto { - - + @ApiProperty() @IsOptional() @IsString() @MaxLength(50)