Update reservations logic to handle non-nullable fields and type adjustments

- Adjust `userId` handling in update DTO logic to allow undefined instead of null.
- Cast certain fields to `any` to handle edge cases in type compatibility.
- Extend Prisma imports to include `Role` for future role-based logic enhancements.
main
Pau Costa Ferrer 2026-03-28 18:40:02 +01:00
parent 604d4c7244
commit 9e2476049d
3 changed files with 33 additions and 20 deletions

View File

@ -4,16 +4,10 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="6c8b3c54-eabb-40e5-967f-c7b594c750bc" name="Changes" comment="Prevent past bookings and updates across web and API&#10;&#10;- Add validation logic to block creating or updating reservations in the past.&#10;- Update date pickers to enforce minimum selectable date as today.&#10;- Extend i18n files (`en.json`, `es-ES.json`) with new error messages.&#10;- Refine UI to disable interaction with past time slots and display appropriate messages."> <list default="true" id="6c8b3c54-eabb-40e5-967f-c7b594c750bc" name="Changes" comment="Allow admins and supervisors to book or update reservations for other users&#10;&#10;- Add role-based restrictions for booking or updating reservations on behalf of others (Admins/Supervisors only).&#10;- Extend reservation DTOs (`CreateReservationDto`, `UpdateReservationDto`) to include `userId` and `note` fields.&#10;- Update Prisma schema to allow nullable `userId` and add support for reservation notes.&#10;- Enhance API logic to validate permissions and handle ownership changes for reservations.&#10;- Improve UI for booking flow; introduce &quot;Book for&quot; options, user search, and reservation notes.&#10;- Localize new strings in `en.json` and `es-ES.json`.">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/api/prisma/schema.prisma" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/prisma/schema.prisma" afterDir="false" /> <change beforePath="$PROJECT_DIR$/apps/api/src/reports/reports.service.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/src/reports/reports.service.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/api/src/reservations/dto/create-reservation.dto.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/src/reservations/dto/create-reservation.dto.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/api/src/reservations/dto/update-reservation.dto.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/src/reservations/dto/update-reservation.dto.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/api/src/reservations/reservations.controller.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/src/reservations/reservations.controller.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/api/src/reservations/reservations.service.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/src/reservations/reservations.service.ts" afterDir="false" /> <change beforePath="$PROJECT_DIR$/apps/api/src/reservations/reservations.service.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/src/reservations/reservations.service.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/lib/components/BookingModal.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/lib/components/BookingModal.svelte" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/lib/i18n/locales/en.json" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/lib/i18n/locales/en.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/lib/i18n/locales/es-ES.json" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/lib/i18n/locales/es-ES.json" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -113,8 +107,8 @@
</configuration> </configuration>
<recent_temporary> <recent_temporary>
<list> <list>
<item itemvalue="npm.web &gt; dev" />
<item itemvalue="npm.api &gt; start:dev" /> <item itemvalue="npm.api &gt; start:dev" />
<item itemvalue="npm.web &gt; dev" />
<item itemvalue="Docker.docker-compose.yml: Compose Deployment" /> <item itemvalue="Docker.docker-compose.yml: Compose Deployment" />
</list> </list>
</recent_temporary> </recent_temporary>
@ -135,7 +129,7 @@
<updated>1774643312599</updated> <updated>1774643312599</updated>
<workItem from="1774643313611" duration="74000" /> <workItem from="1774643313611" duration="74000" />
<workItem from="1774643422240" duration="5278000" /> <workItem from="1774643422240" duration="5278000" />
<workItem from="1774706361502" duration="12417000" /> <workItem from="1774706361502" duration="13226000" />
</task> </task>
<task id="LOCAL-00001" summary="Initialize Hot Desking app with web and API services &#10;&#10;- Set up SvelteKit for the web interface with Tailwind CSS. &#10;- Build the API using NestJS with Prisma ORM for database interaction. &#10;- Add environment variable management and docker-compose for PostgreSQL and PgAdmin instances. &#10;- Create shared data models for consistent typing across services. &#10;- Establish basic routing and layouts for web and API services."> <task id="LOCAL-00001" summary="Initialize Hot Desking app with web and API services &#10;&#10;- Set up SvelteKit for the web interface with Tailwind CSS. &#10;- Build the API using NestJS with Prisma ORM for database interaction. &#10;- Add environment variable management and docker-compose for PostgreSQL and PgAdmin instances. &#10;- Create shared data models for consistent typing across services. &#10;- Establish basic routing and layouts for web and API services.">
<option name="closed" value="true" /> <option name="closed" value="true" />
@ -345,14 +339,32 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1774718397058</updated> <updated>1774718397058</updated>
</task> </task>
<option name="localTasksCounter" value="27" /> <task id="LOCAL-00027" summary="Allow admins and supervisors to book or update reservations for other users&#10;&#10;- Add role-based restrictions for booking or updating reservations on behalf of others (Admins/Supervisors only).&#10;- Extend reservation DTOs (`CreateReservationDto`, `UpdateReservationDto`) to include `userId` and `note` fields.&#10;- Update Prisma schema to allow nullable `userId` and add support for reservation notes.&#10;- Enhance API logic to validate permissions and handle ownership changes for reservations.&#10;- Improve UI for booking flow; introduce &quot;Book for&quot; options, user search, and reservation notes.&#10;- Localize new strings in `en.json` and `es-ES.json`.">
<option name="closed" value="true" />
<created>1774718807082</created>
<option name="number" value="00027" />
<option name="presentableId" value="LOCAL-00027" />
<option name="project" value="LOCAL" />
<updated>1774718807082</updated>
</task>
<option name="localTasksCounter" value="28" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" /> <option name="version" value="3" />
</component> </component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<MESSAGE value="Add building-level dashboard and interactive floorplan viewer&#10;&#10;- Create `+page.svelte` for building-level dashboard with floor selection and layout preview.&#10;- Add `FloorplanViewer.svelte` component with WebSocket integration for real-time space status updates.&#10;- Extend `SpacesService` and API endpoints for building floors and floor details retrieval.&#10;- Update dashboard UI with cleaner building and floor presentation.&#10;- Improve loading states and error handling across dashboard and floor pages." />
<MESSAGE value="Add booking modal and enhance reservation handling&#10;&#10;- Create `BookingModal.svelte` for booking spaces with custom time slots or full-day durations.&#10;- Add API endpoint to fetch reservations by space ID and date.&#10;- Update `SpacesService` with enhanced validation rules and conflict checks for reservations.&#10;- Extend WebSocket updates to include reservation data for real-time synchronization.&#10;- Enable date-based filtering and status handling in UI components (`SpaceCard.svelte`, `FloorplanViewer.svelte`)." /> <MESSAGE value="Add booking modal and enhance reservation handling&#10;&#10;- Create `BookingModal.svelte` for booking spaces with custom time slots or full-day durations.&#10;- Add API endpoint to fetch reservations by space ID and date.&#10;- Update `SpacesService` with enhanced validation rules and conflict checks for reservations.&#10;- Extend WebSocket updates to include reservation data for real-time synchronization.&#10;- Enable date-based filtering and status handling in UI components (`SpaceCard.svelte`, `FloorplanViewer.svelte`)." />
<MESSAGE value="Add support for space resizing and enhanced layout management&#10;&#10;- Update `SpacesService` to handle width and height properties for spaces.&#10;- Introduce `UpdateSpaceDto` for improved validation in batch update operations.&#10;- Extend `FloorplanEditor.svelte` and `FloorplanViewer.svelte` to support dynamic container scaling and space resizing.&#10;- Modify Prisma schema to include `width` and `height` fields for spaces.&#10;- Enhance floorplan rendering to maintain proportional layout during editing and viewing." /> <MESSAGE value="Add support for space resizing and enhanced layout management&#10;&#10;- Update `SpacesService` to handle width and height properties for spaces.&#10;- Introduce `UpdateSpaceDto` for improved validation in batch update operations.&#10;- Extend `FloorplanEditor.svelte` and `FloorplanViewer.svelte` to support dynamic container scaling and space resizing.&#10;- Modify Prisma schema to include `width` and `height` fields for spaces.&#10;- Enhance floorplan rendering to maintain proportional layout during editing and viewing." />
<MESSAGE value="Add admin reporting dashboard with utilization statistics and downloadable reports&#10;&#10;- Implement `+page.svelte` for admin reporting dashboard showing utilization and employee stats.&#10;- Add API endpoints for utilization stats, employee stats, and Excel report export (NestJS).&#10;- Create `ReportsService` and `ReportsModule` for backend logic.&#10;- Introduce `xlsx` package for generating Excel reports.&#10;- Update layout to include &quot;Reports&quot; link for admin users.&#10;- Extend Prisma querying for detailed building, space type, and employee role data." /> <MESSAGE value="Add admin reporting dashboard with utilization statistics and downloadable reports&#10;&#10;- Implement `+page.svelte` for admin reporting dashboard showing utilization and employee stats.&#10;- Add API endpoints for utilization stats, employee stats, and Excel report export (NestJS).&#10;- Create `ReportsService` and `ReportsModule` for backend logic.&#10;- Introduce `xlsx` package for generating Excel reports.&#10;- Update layout to include &quot;Reports&quot; link for admin users.&#10;- Extend Prisma querying for detailed building, space type, and employee role data." />
@ -377,6 +389,7 @@
<MESSAGE value="Add filtering for past and upcoming bookings in &quot;My Bookings&quot; page&#10;&#10;- Enhance UI to separate upcoming and past bookings with collapsible sections.&#10;- Add new i18n keys for handling booking filters (`en.json`, `es-ES.json`).&#10;- Update booking component logic to filter reservations based on time.&#10;- Introduce &quot;Show/Hide Past Bookings&quot; toggle for improved user experience." /> <MESSAGE value="Add filtering for past and upcoming bookings in &quot;My Bookings&quot; page&#10;&#10;- Enhance UI to separate upcoming and past bookings with collapsible sections.&#10;- Add new i18n keys for handling booking filters (`en.json`, `es-ES.json`).&#10;- Update booking component logic to filter reservations based on time.&#10;- Introduce &quot;Show/Hide Past Bookings&quot; toggle for improved user experience." />
<MESSAGE value="Refactor date picker components for improved accessibility and usability&#10;&#10;- Add `showPicker` event to trigger native date picker overlays.&#10;- Adjust z-index and positioning for hidden `input` elements to improve interaction.&#10;- Reorganize markup for consistent focus and selection behavior across components." /> <MESSAGE value="Refactor date picker components for improved accessibility and usability&#10;&#10;- Add `showPicker` event to trigger native date picker overlays.&#10;- Adjust z-index and positioning for hidden `input` elements to improve interaction.&#10;- Reorganize markup for consistent focus and selection behavior across components." />
<MESSAGE value="Prevent past bookings and updates across web and API&#10;&#10;- Add validation logic to block creating or updating reservations in the past.&#10;- Update date pickers to enforce minimum selectable date as today.&#10;- Extend i18n files (`en.json`, `es-ES.json`) with new error messages.&#10;- Refine UI to disable interaction with past time slots and display appropriate messages." /> <MESSAGE value="Prevent past bookings and updates across web and API&#10;&#10;- Add validation logic to block creating or updating reservations in the past.&#10;- Update date pickers to enforce minimum selectable date as today.&#10;- Extend i18n files (`en.json`, `es-ES.json`) with new error messages.&#10;- Refine UI to disable interaction with past time slots and display appropriate messages." />
<option name="LAST_COMMIT_MESSAGE" value="Prevent past bookings and updates across web and API&#10;&#10;- Add validation logic to block creating or updating reservations in the past.&#10;- Update date pickers to enforce minimum selectable date as today.&#10;- Extend i18n files (`en.json`, `es-ES.json`) with new error messages.&#10;- Refine UI to disable interaction with past time slots and display appropriate messages." /> <MESSAGE value="Allow admins and supervisors to book or update reservations for other users&#10;&#10;- Add role-based restrictions for booking or updating reservations on behalf of others (Admins/Supervisors only).&#10;- Extend reservation DTOs (`CreateReservationDto`, `UpdateReservationDto`) to include `userId` and `note` fields.&#10;- Update Prisma schema to allow nullable `userId` and add support for reservation notes.&#10;- Enhance API logic to validate permissions and handle ownership changes for reservations.&#10;- Improve UI for booking flow; introduce &quot;Book for&quot; options, user search, and reservation notes.&#10;- Localize new strings in `en.json` and `es-ES.json`." />
<option name="LAST_COMMIT_MESSAGE" value="Allow admins and supervisors to book or update reservations for other users&#10;&#10;- Add role-based restrictions for booking or updating reservations on behalf of others (Admins/Supervisors only).&#10;- Extend reservation DTOs (`CreateReservationDto`, `UpdateReservationDto`) to include `userId` and `note` fields.&#10;- Update Prisma schema to allow nullable `userId` and add support for reservation notes.&#10;- Enhance API logic to validate permissions and handle ownership changes for reservations.&#10;- Improve UI for booking flow; introduce &quot;Book for&quot; options, user search, and reservation notes.&#10;- Localize new strings in `en.json` and `es-ES.json`." />
</component> </component>
</project> </project>

View File

@ -132,8 +132,8 @@ export class ReportsService {
const data = reservations.map(r => ({ const data = reservations.map(r => ({
'Reservation ID': r.id, 'Reservation ID': r.id,
'User Email': r.user.email, 'User Email': r.user?.email || 'N/A',
'User Role': r.user.role, 'User Role': r.user?.role || 'N/A',
'Building': r.space.floor.building.name, 'Building': r.space.floor.building.name,
'Floor': r.space.floor.number, 'Floor': r.space.floor.number,
'Space Name': r.space.name, 'Space Name': r.space.name,

View File

@ -3,7 +3,7 @@ import { PrismaService } from '../prisma/prisma.service';
import { EventsGateway } from '../events/events.gateway'; import { EventsGateway } from '../events/events.gateway';
import { CreateReservationDto } from './dto/create-reservation.dto'; import { CreateReservationDto } from './dto/create-reservation.dto';
import { UpdateReservationDto } from './dto/update-reservation.dto'; import { UpdateReservationDto } from './dto/update-reservation.dto';
import { SpaceType } from '@prisma/client'; import { SpaceType, Role } from '@prisma/client';
@Injectable() @Injectable()
export class ReservationsService { export class ReservationsService {
@ -94,7 +94,7 @@ export class ReservationsService {
} }
} }
} }
}); }) as any;
// Notify clients on the floor // Notify clients on the floor
this.eventsGateway.emitSpaceStatusChanged(space.floorId, spaceId, true, { this.eventsGateway.emitSpaceStatusChanged(space.floorId, spaceId, true, {
@ -197,8 +197,8 @@ export class ReservationsService {
const spaceId = updateReservationDto.spaceId || reservation.spaceId; const spaceId = updateReservationDto.spaceId || reservation.spaceId;
const startTime = updateReservationDto.startTime || reservation.startTime; const startTime = updateReservationDto.startTime || reservation.startTime;
const endTime = updateReservationDto.endTime || reservation.endTime; const endTime = updateReservationDto.endTime || reservation.endTime;
const targetUserId = updateReservationDto.userId === null ? null : (updateReservationDto.userId || reservation.userId); const targetUserId = updateReservationDto.userId === null ? undefined : (updateReservationDto.userId || reservation.userId);
const note = updateReservationDto.note === undefined ? reservation.note : updateReservationDto.note; const note = updateReservationDto.note === undefined ? (reservation as any).note : updateReservationDto.note;
const space = await this.prisma.space.findUnique({ const space = await this.prisma.space.findUnique({
where: { id: spaceId }, where: { id: spaceId },
@ -279,7 +279,7 @@ export class ReservationsService {
}, },
space: true space: true
} }
}); }) as any;
// Notify clients on the floor if space or time changed // Notify clients on the floor if space or time changed
if (reservation.spaceId !== updated.spaceId) { if (reservation.spaceId !== updated.spaceId) {