Skip to content

Commit 32cc118

Browse files
committed
resolved comments
1 parent 7956eab commit 32cc118

2 files changed

Lines changed: 106 additions & 22 deletions

File tree

src/main/webapp/app/shared/components/atoms/upload-button/upload-button.component.ts

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export class UploadButtonComponent {
5959
disabled = computed(() => (this.documentIds()?.length ?? 0) > 0);
6060
allowMultiple = input<boolean>(true);
6161
deferUpload = input<boolean>(false);
62-
queuedFiles = signal<File[]>([]);
62+
queuedFilesById = signal<Map<string, File>>(new Map());
63+
queuedFiles = computed(() => Array.from(this.queuedFilesById().values()));
6364

6465
// Duplicate dialog state
6566
pendingDuplicateFile = signal<File | null>(null);
@@ -127,7 +128,7 @@ export class UploadButtonComponent {
127128
if (this.deferUpload()) {
128129
const updatedList = this.documentIds()?.filter(doc => doc.id !== existingDoc.id) ?? [];
129130
this.documentIds.set(updatedList);
130-
this.removeQueuedFileFor(existingDoc);
131+
this.removeQueuedFileFor(existingDoc.id);
131132
} else {
132133
try {
133134
await firstValueFrom(this.applicationService.deleteDocumentFromApplication(existingDoc.id));
@@ -161,8 +162,8 @@ export class UploadButtonComponent {
161162
const existingDocs = this.documentIds() ?? [];
162163
if (this.deferUpload()) {
163164
this.documentIds.set([]);
164-
this.queuedFiles.set([]);
165-
this.queuedFilesChange.emit([]);
165+
this.queuedFilesById.set(new Map());
166+
this.emitQueuedFilesChange();
166167
} else {
167168
for (const doc of existingDocs) {
168169
try {
@@ -211,7 +212,7 @@ export class UploadButtonComponent {
211212
if (this.deferUpload()) {
212213
const updatedList = this.documentIds()?.filter(doc => doc.id !== documentId) ?? [];
213214
this.documentIds.set(updatedList);
214-
this.removeQueuedFileFor(documentInfo);
215+
this.removeQueuedFileFor(documentId);
215216
return;
216217
}
217218

@@ -253,6 +254,7 @@ export class UploadButtonComponent {
253254
: doc,
254255
) ?? [];
255256
this.documentIds.set(updatedDocs);
257+
this.renameQueuedFile(documentId, newName);
256258
return;
257259
}
258260

@@ -339,15 +341,20 @@ export class UploadButtonComponent {
339341
}
340342

341343
if (this.deferUpload()) {
342-
const tempDocumentEntries: DocumentInformationHolderDTO[] = files.map(file => ({
343-
id: `temp-${Date.now()}-${Math.random().toString(36).slice(2)}`,
344-
name: file.name,
345-
size: file.size,
346-
}));
344+
const updatedQueuedFiles = new Map(this.queuedFilesById());
345+
const tempDocumentEntries: DocumentInformationHolderDTO[] = files.map(file => {
346+
const id = `temp-${Date.now()}-${Math.random().toString(36).slice(2)}`;
347+
updatedQueuedFiles.set(id, file);
348+
return {
349+
id,
350+
name: file.name,
351+
size: file.size,
352+
};
353+
});
347354
const updatedList = [...(this.documentIds() ?? []), ...tempDocumentEntries];
348355
this.documentIds.set(updatedList);
349-
this.queuedFiles.set(combinedFiles);
350-
this.queuedFilesChange.emit(combinedFiles);
356+
this.queuedFilesById.set(updatedQueuedFiles);
357+
this.emitQueuedFilesChange();
351358
this.fileUploadComponent()?.clear();
352359
this.resetNativeFileInput();
353360
return;
@@ -374,18 +381,34 @@ export class UploadButtonComponent {
374381
/**
375382
* Keeps the deferred upload queue in sync with the placeholder row removed from `documentIds`.
376383
*/
377-
private removeQueuedFileFor(documentInfo: DocumentInformationHolderDTO): void {
378-
const files = this.queuedFiles();
379-
if (files.length === 0) {
384+
private removeQueuedFileFor(documentId: string): void {
385+
const filesById = this.queuedFilesById();
386+
if (!filesById.has(documentId)) {
380387
return;
381388
}
382-
const index = files.findIndex(file => file.name === documentInfo.name && file.size === documentInfo.size);
383-
if (index < 0) {
389+
const updated = new Map(filesById);
390+
updated.delete(documentId);
391+
this.queuedFilesById.set(updated);
392+
this.emitQueuedFilesChange();
393+
}
394+
395+
private renameQueuedFile(documentId: string, newName: string): void {
396+
const queuedFile = this.queuedFilesById().get(documentId);
397+
if (!queuedFile || queuedFile.name === newName) {
384398
return;
385399
}
386-
const updated = [...files];
387-
updated.splice(index, 1);
388-
this.queuedFiles.set(updated);
389-
this.queuedFilesChange.emit(updated);
400+
401+
const renamedFile = new File([queuedFile], newName, {
402+
type: queuedFile.type,
403+
lastModified: queuedFile.lastModified,
404+
});
405+
const updated = new Map(this.queuedFilesById());
406+
updated.set(documentId, renamedFile);
407+
this.queuedFilesById.set(updated);
408+
this.emitQueuedFilesChange();
409+
}
410+
411+
private emitQueuedFilesChange(): void {
412+
this.queuedFilesChange.emit(this.queuedFiles());
390413
}
391414
}

src/test/webapp/app/shared/components/atoms/upload-button/upload-button.component.spec.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ describe('UploadButtonComponent', () => {
2121
let applicationService: ApplicationResourceApiServiceMock;
2222
let toastService: ToastServiceMock;
2323

24-
function createUploadButtonFixture(inputs: { documentType: DocumentType; applicationId: string; markAsRequired?: boolean }) {
24+
function createUploadButtonFixture(inputs: {
25+
documentType: DocumentType;
26+
applicationId: string;
27+
markAsRequired?: boolean;
28+
deferUpload?: boolean;
29+
allowMultiple?: boolean;
30+
}) {
2531
const fixture = TestBed.createComponent(UploadButtonComponent);
2632
Object.entries(inputs).forEach(([key, value]) => {
2733
fixture.componentRef.setInput(key, value);
@@ -300,6 +306,61 @@ describe('UploadButtonComponent', () => {
300306
expect(updatedDocs?.length).toBe(0);
301307
});
302308

309+
it('should remove a deferred queued file by placeholder id after renaming and deleting it', async () => {
310+
const fixture = createUploadButtonFixture({ applicationId: '1234', documentType: 'CV', deferUpload: true });
311+
const component = fixture.componentInstance;
312+
313+
component.fileUploadComponent = signal({
314+
clear: vi.fn(),
315+
} as unknown as FileUpload);
316+
317+
await component.onFileSelected({
318+
currentFiles: [new File(['old-content'], 'original.pdf', { type: 'application/pdf' })],
319+
} as FileSelectEvent);
320+
321+
const queuedDocument = component.documentIds()?.[0];
322+
expect(queuedDocument).toBeDefined();
323+
324+
await component.renameDocument({ ...queuedDocument!, name: 'renamed.pdf' });
325+
326+
expect(component.documentIds()?.[0]?.name).toBe('renamed.pdf');
327+
expect(component.queuedFiles()).toHaveLength(1);
328+
expect(component.queuedFiles()[0].name).toBe('renamed.pdf');
329+
330+
await component.deleteDictionary(component.documentIds()![0]);
331+
332+
expect(component.documentIds()).toEqual([]);
333+
expect(component.queuedFiles()).toEqual([]);
334+
expect(applicationService.deleteDocumentFromApplication).not.toHaveBeenCalled();
335+
});
336+
337+
it('should replace a deferred renamed placeholder by id without leaving the old queued file behind', async () => {
338+
const fixture = createUploadButtonFixture({ applicationId: '1234', documentType: 'CV', deferUpload: true });
339+
const component = fixture.componentInstance;
340+
341+
component.fileUploadComponent = signal({
342+
clear: vi.fn(),
343+
} as unknown as FileUpload);
344+
345+
await component.onFileSelected({ currentFiles: [new File(['old'], 'original.pdf', { type: 'application/pdf' })] } as FileSelectEvent);
346+
347+
const queuedDocument = component.documentIds()?.[0];
348+
expect(queuedDocument).toBeDefined();
349+
350+
await component.renameDocument({ ...queuedDocument!, name: 'renamed.pdf' });
351+
352+
const replacementFile = new File(['replacement-content'], 'renamed.pdf', { type: 'application/pdf' });
353+
component.pendingDuplicateFile.set(replacementFile);
354+
355+
await component.onConfirmDuplicate();
356+
357+
expect(component.documentIds()).toHaveLength(1);
358+
expect(component.documentIds()?.[0]?.name).toBe('renamed.pdf');
359+
expect(component.queuedFiles()).toHaveLength(1);
360+
expect(component.queuedFiles()[0].name).toBe('renamed.pdf');
361+
expect(component.queuedFiles()[0].size).toBe(replacementFile.size);
362+
});
363+
303364
describe('Duplicate Handling', () => {
304365
it('should detect duplicate filename and show dialog instead of uploading', async () => {
305366
vi.useFakeTimers();

0 commit comments

Comments
 (0)