Skip to content

Staff fix bug#41

Merged
nnh53 merged 2 commits into
mainfrom
staff-fix-bug
Nov 14, 2025
Merged

Staff fix bug#41
nnh53 merged 2 commits into
mainfrom
staff-fix-bug

Conversation

@nnh53

@nnh53 nnh53 commented Nov 14, 2025

Copy link
Copy Markdown
Member

No description provided.

Copilot AI review requested due to automatic review settings November 14, 2025 12:12
@naming-conventions-bot

Copy link
Copy Markdown

Thank you for following naming conventions! 😻

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying ev-rental with  Cloudflare Pages  Cloudflare Pages

Latest commit: cc836a8
Status: ✅  Deploy successful!
Preview URL: https://f9c9562a.ev-rental.pages.dev
Branch Preview URL: https://staff-fix-bug.ev-rental.pages.dev

View logs

@nnh53 nnh53 merged commit 1779e5c into main Nov 14, 2025
9 checks passed
@nnh53 nnh53 deleted the staff-fix-bug branch November 14, 2025 12:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the staff booking workflow by extracting presentation logic into dedicated presenter classes, fixing the fulfillment route structure, and adding KYC document support for renter management. The changes improve code organization and maintainability while addressing routing bugs.

  • Refactored staff-dashboard and fulfillment-page components to use presenter pattern for separation of concerns
  • Fixed booking fulfillment route from /staff/bookings/:bookingId/fulfillment to /staff/fulfillment/:bookingId
  • Added comprehensive KYC document extraction and display for renter profiles

Reviewed Changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/contract/model/bookingDetailsDto.ts Added optional depositAmount and totalAmount fields to BookingDetailsDto
src/app/features/staff/staff.routes.ts Fixed fulfillment route path and reorganized imports
src/app/features/staff/staff-dashboard/staff-dashboard.ts Extracted presentation logic to StaffDashboardPresenter, delegated formatting and view model building
src/app/features/staff/staff-dashboard/staff-dashboard.presenter.ts New presenter containing all view model building, formatting, and business logic
src/app/features/staff/staff-dashboard/staff-dashboard.models.ts New models file containing interfaces and constants previously in component
src/app/features/staff/renter-management/renter-management.ts Added KYC document extraction, prioritization, and display logic
src/app/features/staff/renter-management/renter-management.scss Added styles for KYC document list display
src/app/features/staff/renter-management/renter-management.html Updated template to display KYC documents and use dynamic primary KYC fields
src/app/features/staff/booking-fulfillment/pages/fulfillment-page/fulfillment-page.ts Extracted presentation logic to FulfillmentPagePresenter
src/app/features/staff/booking-fulfillment/pages/fulfillment-page/fulfillment-page.presenter.ts New presenter for fulfillment page logic
src/app/features/staff/booking-fulfillment/pages/fulfillment-page/fulfillment-page.models.ts New models file for fulfillment page interfaces and constants
src/app/core-logic/renters/renters.service.ts Added extensive KYC document extraction logic with type normalization and status classification
src/app/core-logic/bookings/bookings.service.ts Added userId extraction and resolution for booking records
src/app/core-logic/auth/auth.interceptor.ts Refactored to use proper token refresh with shareReplay to prevent duplicate requests
specs/001-staff-booking-flow/spec.md Updated route path in documentation
specs/001-staff-booking-flow/quickstart.md Updated route path in quickstart guide
openapi-spec.json Added depositAmount and totalAmount fields to BookingDetailsDto schema
angular.json Added 'qrcode' to allowedCommonJsDependencies

Comment on lines +182 to +188
record.rental?.rentalId ?? undefined,
record.rental?.vehicleId ?? undefined,
record.vehicleDetails?.make ?? undefined,
record.vehicleDetails?.model ?? undefined,
record.renterProfile?.userName ?? undefined,
record.renterProfile?.address ?? undefined,
record.renterProfile?.driverLicenseNo ?? undefined,

Copilot AI Nov 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ?? undefined pattern is redundant. The nullish coalescing operator already returns undefined when the left operand is null or undefined, so explicitly specifying ?? undefined has no effect and reduces readability.

Suggested change
record.rental?.rentalId ?? undefined,
record.rental?.vehicleId ?? undefined,
record.vehicleDetails?.make ?? undefined,
record.vehicleDetails?.model ?? undefined,
record.renterProfile?.userName ?? undefined,
record.renterProfile?.address ?? undefined,
record.renterProfile?.driverLicenseNo ?? undefined,
record.rental?.rentalId,
record.rental?.vehicleId,
record.vehicleDetails?.make,
record.vehicleDetails?.model,
record.renterProfile?.userName,
record.renterProfile?.address,
record.renterProfile?.driverLicenseNo,

Copilot uses AI. Check for mistakes.
import { AuthService } from './auth.service';
import { TokenService } from '../token/token.service';

let refreshInFlight$: Observable<unknown> | null = null;

Copilot AI Nov 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module-level mutable state (refreshInFlight$) creates a shared singleton that persists across multiple injector contexts and can cause race conditions or stale state. Consider moving this into a service with proper lifecycle management or using a BehaviorSubject to ensure proper cleanup and testability.

Copilot uses AI. Check for mistakes.
: undefined;

return {
id: 'kyc-' + document.type + '-' + index,

Copilot AI Nov 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using index as part of the tracking ID can cause incorrect rendering when documents are reordered or filtered. Since document.type is not unique, this can produce duplicate IDs if multiple documents of the same type exist. Consider using a combination of all unique fields: ${document.type}-${document.documentNumber ?? 'none'}-${document.status ?? 'none'}.

Suggested change
id: 'kyc-' + document.type + '-' + index,
id: `kyc-${document.type}-${document.documentNumber ?? 'none'}-${document.status ?? 'none'}`,

Copilot uses AI. Check for mistakes.
Comment on lines +602 to +609
return this._staffService.apiStaffRentersGet().pipe(
map((response: RenterProfileDtoListApiResponse) => response.data ?? []),
map((renters) =>
renters.find((renter) => this._normalizeString(renter?.renterId) === renterId),
),
map((match) => this._extractUserId(match)),
catchError(() => of(undefined)),
);

Copilot AI Nov 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _resolveRenterUserId$ method fetches the entire renter list on every call to find a single userId. This creates an N+1 query pattern when loading multiple bookings. Consider caching the renter list, using a dedicated API endpoint for userId lookup, or resolving all userIds in batch before processing individual bookings.

Copilot uses AI. Check for mistakes.
private readonly router = inject(Router);
private readonly cdr = inject(ChangeDetectorRef);
private readonly environmentInjector = inject(EnvironmentInjector);
private readonly presenter = new StaffDashboardPresenter();

Copilot AI Nov 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manually instantiating the presenter with new bypasses Angular's dependency injection. If the presenter later needs injected dependencies (e.g., for formatters or services), this will require refactoring. Consider making StaffDashboardPresenter an injectable service with @Injectable({ providedIn: 'root' }) or using inject() within the component constructor.

Suggested change
private readonly presenter = new StaffDashboardPresenter();
private readonly presenter = inject(StaffDashboardPresenter);

Copilot uses AI. Check for mistakes.
private readonly formBuilder = inject(NonNullableFormBuilder);
private readonly cdr = inject(ChangeDetectorRef);
private readonly environmentInjector = inject(EnvironmentInjector);
private readonly presenter = new FulfillmentPagePresenter();

Copilot AI Nov 14, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manually instantiating the presenter with new bypasses Angular's dependency injection. If the presenter later needs injected dependencies, this will require refactoring. Consider making FulfillmentPagePresenter an injectable service with @Injectable({ providedIn: 'root' }) or using inject() within the component constructor.

Suggested change
private readonly presenter = new FulfillmentPagePresenter();
private readonly presenter = inject(FulfillmentPagePresenter);

Copilot uses AI. Check for mistakes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +597 to +609
private _resolveRenterUserId$(renterId: string | undefined): Observable<string | undefined> {
if (!renterId) {
return of(undefined);
}

return this._staffService.apiStaffRentersGet().pipe(
map((response: RenterProfileDtoListApiResponse) => response.data ?? []),
map((renters) =>
renters.find((renter) => this._normalizeString(renter?.renterId) === renterId),
),
map((match) => this._extractUserId(match)),
catchError(() => of(undefined)),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid refetching renter list for every booking

When building staff booking records the new _resolveRenterUserId$ helper now calls apiStaffRentersGet() for each booking that lacks a userId. The staff dashboard can easily contain dozens of bookings, so this change issues dozens of identical requests that download the entire renter list repeatedly before any booking data resolves. This is a regression from the previous code path (which performed no additional calls) and significantly slows the dashboard and stresses the API. Consider caching the renter list or resolving all user IDs in a single request per refresh.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants