mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 13:05:44 +00:00
add file viewer functionality across various components
- Implemented a shared file viewer modal using `useFileViewer` hook to allow inline viewing of documents (images, PDFs, videos, etc.) across the application. - Updated `ContractClearanceReviewSection`, `ContractRequestDetailPage`, `ContractViewPage`, and booking-related components to utilize the new file viewer for document previews. - Added "Approve all" button in `ContractClearanceReviewSection` to bulk approve documents. - Enhanced document action buttons to include view and download options based on file type. - Introduced `isViewable` utility to determine if a file can be previewed inline. - Created `FileViewer` component to handle rendering of various file types and added appropriate fallback for unsupported formats.
This commit is contained in:
@@ -231,10 +231,14 @@ export class ContractTransitionService {
|
||||
|
||||
await this.contractsRepository.completeApprovalStep(step.id, actorId, 'APPROVED');
|
||||
|
||||
// Record who acted on this step, but DO NOT advance the contract status here —
|
||||
// approving one step (e.g. LINE_STAFF) must not finalize the chain while later
|
||||
// steps (e.g. DIRECTOR) are still pending. Status only moves to APPROVED once
|
||||
// every step in the chain is complete; until then the contract stays in
|
||||
// PENDING_APPROVAL so the next required role can act.
|
||||
const updates: Record<string, unknown> = {};
|
||||
const now = new Date();
|
||||
if (requiredRole === 'LINE_STAFF') {
|
||||
updates.status = 'APPROVED_PENDING_SIGNATURE';
|
||||
updates.approvedByStaffId = actorId;
|
||||
updates.approvedByStaffAt = now;
|
||||
} else if (requiredRole === 'DIRECTOR') {
|
||||
@@ -246,9 +250,7 @@ export class ContractTransitionService {
|
||||
}
|
||||
|
||||
const allDone = await this.contractsRepository.allApprovalStepsComplete(contractId);
|
||||
if (allDone) {
|
||||
updates.status = 'APPROVED';
|
||||
}
|
||||
updates.status = allDone ? 'APPROVED' : 'PENDING_APPROVAL';
|
||||
|
||||
if (Object.keys(updates).length > 0) {
|
||||
await this.contractsRepository.update(contractId, updates as never);
|
||||
@@ -368,9 +370,28 @@ export class ContractTransitionService {
|
||||
options: { signerUserId?: string },
|
||||
): Promise<void> {
|
||||
const role = dto.role as ContractSignerRole;
|
||||
const raw = dto.signatureImageBase64.includes(',')
|
||||
? dto.signatureImageBase64.split(',')[1]!
|
||||
: dto.signatureImageBase64;
|
||||
|
||||
// Resolve the signature image. The client may send a freshly-drawn image, or
|
||||
// omit it to reuse the signer's saved profile signature. Fall back to the
|
||||
// saved one whenever no image is supplied.
|
||||
let imageBase64 = dto.signatureImageBase64;
|
||||
let signerDisplayName = dto.signerDisplayName;
|
||||
if (!imageBase64 && options.signerUserId) {
|
||||
const saved = await this.signaturesService.getForUser(options.signerUserId);
|
||||
if (saved?.signatureImageUrl) {
|
||||
imageBase64 = saved.signatureImageUrl;
|
||||
signerDisplayName = signerDisplayName || saved.signerDisplayName;
|
||||
}
|
||||
}
|
||||
if (!imageBase64) {
|
||||
throw new BadRequestException(
|
||||
'No signature provided and no saved signature found on the profile.',
|
||||
);
|
||||
}
|
||||
|
||||
const raw = imageBase64.includes(',')
|
||||
? imageBase64.split(',')[1]!
|
||||
: imageBase64;
|
||||
const buffer = Buffer.from(raw, 'base64');
|
||||
const sigFile: Express.Multer.File = {
|
||||
fieldname: `signature_${role.toLowerCase()}`,
|
||||
@@ -395,17 +416,19 @@ export class ContractTransitionService {
|
||||
await this.contractsRepository.saveSignature({
|
||||
contractId: contract.id,
|
||||
role,
|
||||
signerDisplayName: dto.signerDisplayName,
|
||||
signerDisplayName,
|
||||
signedAt: new Date(),
|
||||
signatureFileId: fileRecord.id,
|
||||
consentText: dto.consentText ?? null,
|
||||
});
|
||||
|
||||
if (options.signerUserId) {
|
||||
// Only (re)save the reusable profile signature when the signer drew a NEW
|
||||
// image. Reusing the saved signature must not rewrite it with itself.
|
||||
if (options.signerUserId && dto.signatureImageBase64) {
|
||||
try {
|
||||
await this.signaturesService.upsertForUser({
|
||||
userId: options.signerUserId,
|
||||
signerDisplayName: dto.signerDisplayName,
|
||||
signerDisplayName,
|
||||
signatureImageBase64: dto.signatureImageBase64,
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user