mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 09:35:44 +00:00
feat: implemented the changes request to the company profile
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import {
|
||||
ChangeRequestStatus,
|
||||
CompanyChangeRequest,
|
||||
} from "../entities/company-change-request.entity";
|
||||
|
||||
/**
|
||||
* A staged profile change request. Used both by the portal (to lock the settings
|
||||
* page, show the reviewer note, and prefill the proposed values) and by the
|
||||
* backoffice review screen (to render the proposed-vs-current diff).
|
||||
*/
|
||||
export class ChangeRequestResponseDto {
|
||||
id: string;
|
||||
companyId: string;
|
||||
status: ChangeRequestStatus;
|
||||
/** Proposed field values (Partial<UpdateProfileDto>) — the diff payload. */
|
||||
snapshot: Record<string, any>;
|
||||
documentFileIds: string[];
|
||||
note: string | null;
|
||||
submittedBy: string | null;
|
||||
submittedAt: Date | null;
|
||||
reviewedBy: string | null;
|
||||
reviewedAt: Date | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
constructor(req: CompanyChangeRequest) {
|
||||
this.id = req.id;
|
||||
this.companyId = req.companyId;
|
||||
this.status = req.status;
|
||||
this.snapshot = req.snapshot ?? {};
|
||||
this.documentFileIds = req.documents?.documentFileIds ?? [];
|
||||
this.note = req.note ?? null;
|
||||
this.submittedBy = req.submittedBy ?? null;
|
||||
this.submittedAt = req.submittedAt ?? null;
|
||||
this.reviewedBy = req.reviewedBy ?? null;
|
||||
this.reviewedAt = req.reviewedAt ?? null;
|
||||
this.createdAt = req.createdAt;
|
||||
this.updatedAt = req.updatedAt;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,43 @@
|
||||
import { Company } from '../entities/company.entity';
|
||||
import { ExternalProfile } from '../entities/external-profile.entity';
|
||||
import {
|
||||
ChangeRequestStatus,
|
||||
CompanyChangeRequest,
|
||||
} from '../entities/company-change-request.entity';
|
||||
import { ResponseCompanyDto } from './response-company.dto';
|
||||
import { ResponseExternalProfileDto } from './response-external-profile.dto';
|
||||
|
||||
export class CompanyInfoResponseDto {
|
||||
profile: ResponseExternalProfileDto;
|
||||
company: ResponseCompanyDto;
|
||||
/**
|
||||
* Open profile-edit review, if any. Drives the portal-wide lock (pending →
|
||||
* settings + new-contract/booking creation disabled) and the reapply banner.
|
||||
*/
|
||||
review: {
|
||||
status: 'pending' | 'rejected';
|
||||
note: string | null;
|
||||
} | null;
|
||||
|
||||
constructor(profile: ExternalProfile, company: Company) {
|
||||
constructor(
|
||||
profile: ExternalProfile,
|
||||
company: Company,
|
||||
changeRequest?: CompanyChangeRequest | null,
|
||||
) {
|
||||
this.profile = new ResponseExternalProfileDto(profile, company);
|
||||
this.company = new ResponseCompanyDto(company);
|
||||
|
||||
const open =
|
||||
changeRequest &&
|
||||
(changeRequest.status === ChangeRequestStatus.Pending ||
|
||||
changeRequest.status === ChangeRequestStatus.Rejected)
|
||||
? changeRequest
|
||||
: null;
|
||||
this.review = open
|
||||
? {
|
||||
status: open.status as 'pending' | 'rejected',
|
||||
note: open.note ?? null,
|
||||
}
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Company } from '../entities/company.entity';
|
||||
import { ExternalProfile } from '../entities/external-profile.entity';
|
||||
import {
|
||||
ChangeRequestStatus,
|
||||
CompanyChangeRequest,
|
||||
} from '../entities/company-change-request.entity';
|
||||
import { ResponseCompanyProfileDto } from './response-company.dto';
|
||||
|
||||
export class ProfileResponseDto {
|
||||
@@ -48,7 +52,20 @@ export class ProfileResponseDto {
|
||||
|
||||
profileId: string;
|
||||
|
||||
constructor(profile: ExternalProfile, company: Company) {
|
||||
/**
|
||||
* Open profile-edit review, if any. `reviewStatus === "pending"` locks the
|
||||
* settings page; `"rejected"` surfaces the note and prefills the (declined)
|
||||
* proposed values from `pendingChanges` so the customer can amend & resubmit.
|
||||
*/
|
||||
reviewStatus: "pending" | "rejected" | null;
|
||||
reviewNote: string | null;
|
||||
pendingChanges: Record<string, any> | null;
|
||||
|
||||
constructor(
|
||||
profile: ExternalProfile,
|
||||
company: Company,
|
||||
changeRequest?: CompanyChangeRequest | null,
|
||||
) {
|
||||
this.companyId = company.id;
|
||||
this.companyName = company.name;
|
||||
this.companyType = company.type;
|
||||
@@ -92,5 +109,20 @@ export class ProfileResponseDto {
|
||||
this.poaEmail = attrs.poaEmail ?? null;
|
||||
this.poaLocation = attrs.poaLocation ?? null;
|
||||
this.poaAddress = attrs.poaAddress ?? null;
|
||||
|
||||
const openReview =
|
||||
changeRequest &&
|
||||
(changeRequest.status === ChangeRequestStatus.Pending ||
|
||||
changeRequest.status === ChangeRequestStatus.Rejected)
|
||||
? changeRequest
|
||||
: null;
|
||||
this.reviewStatus =
|
||||
openReview?.status === ChangeRequestStatus.Pending
|
||||
? "pending"
|
||||
: openReview?.status === ChangeRequestStatus.Rejected
|
||||
? "rejected"
|
||||
: null;
|
||||
this.reviewNote = openReview?.note ?? null;
|
||||
this.pendingChanges = openReview?.snapshot ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsString, MaxLength, MinLength } from "class-validator";
|
||||
|
||||
export class RejectChangeRequestDto {
|
||||
/** Why the proposed changes were declined — shown to the customer so they can fix and resubmit. */
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(2000)
|
||||
note!: string;
|
||||
}
|
||||
@@ -21,6 +21,8 @@ export class ResponseCompanyProfileDto {
|
||||
/** Business-license documents stored on the profile (multi-file). */
|
||||
licenseFiles: BusinessLicenseFile[];
|
||||
attributes?: Record<string, any> | null;
|
||||
/** Reviewer note when the role is rejected (drives the reapply prompt). */
|
||||
reviewNote?: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
@@ -33,6 +35,7 @@ export class ResponseCompanyProfileDto {
|
||||
this.businessLicense = profile.businessLicense;
|
||||
this.licenseFiles = profile.businessLicenseFiles ?? [];
|
||||
this.attributes = profile.attributes;
|
||||
this.reviewNote = profile.reviewNote ?? null;
|
||||
this.createdAt = profile.createdAt;
|
||||
this.updatedAt = profile.updatedAt;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsIn } from "class-validator";
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { IsIn, IsOptional, IsString, MaxLength } from "class-validator";
|
||||
import { ProfileStatus } from "../entities/company-profile.entity";
|
||||
|
||||
export class UpdateCompanyProfileStatusDto {
|
||||
@ApiProperty({ enum: ProfileStatus })
|
||||
@IsIn(Object.values(ProfileStatus))
|
||||
status!: ProfileStatus;
|
||||
|
||||
/** Reviewer note — required in practice when rejecting so the customer knows why. */
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(2000)
|
||||
note?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user