Skip to content

Commit

Permalink
Feat file empty or invalid messages (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
chavda-bhavik authored Dec 21, 2022
2 parents 89ee7c8 + 1ef5d51 commit faf201c
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 19 deletions.
1 change: 1 addition & 0 deletions apps/api/src/app/shared/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const APIMessages = {
FILE_TYPE_NOT_VALID: 'File type is not supported.',
FILE_IS_EMPTY: 'File is empty',
FILE_CONTENT_INVALID: 'File content is invalid. Please check the file or upload new file.',
EMPTY_HEADING_PREFIX: 'Empty Heading',
INVALID_TEMPLATE_ID_CODE_SUFFIX: 'is not valid TemplateId or CODE.',
FILE_MAPPING_REMAINING: 'File mapping is not yet done, please finalize mapping before.',
Expand Down
8 changes: 8 additions & 0 deletions apps/api/src/app/shared/exceptions/invalid-file.exception.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { BadRequestException } from '@nestjs/common';
import { APIMessages } from '../constants';

export class InvalidFileException extends BadRequestException {
constructor() {
super(APIMessages.FILE_CONTENT_INVALID);
}
}
29 changes: 14 additions & 15 deletions apps/api/src/app/shared/file/file.service.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
import * as XLSX from 'xlsx';
import { Defaults, FileEncodingsEnum, IFileInformation } from '@impler/shared';
import { ParserOptionsArgs, parseString } from 'fast-csv';
import { StorageService } from '@impler/shared';
import { EmptyFileException } from '../exceptions/empty-file.exception';
import { APIMessages } from '../constants';
import { InvalidFileException } from '@shared/exceptions/invalid-file.exception';

export abstract class FileService {
abstract getFileInformation(storageService: StorageService, storageKey: string): Promise<IFileInformation>;
abstract getFileInformation(file: Express.Multer.File, options?: ParserOptionsArgs): Promise<IFileInformation>;
}

export class CSVFileService extends FileService {
async getFileInformation(storageService: StorageService, storageKey: string): Promise<IFileInformation> {
const fileContent = await storageService.getFileContent(storageKey, FileEncodingsEnum.CSV);

return await this.getCSVInformation(fileContent, { headers: true });
}
private async getCSVInformation(fileContent: string, options?: ParserOptionsArgs): Promise<IFileInformation> {
async getFileInformation(file: Express.Multer.File, options?: ParserOptionsArgs): Promise<IFileInformation> {
return new Promise((resolve, reject) => {
const information: IFileInformation = {
data: [],
headings: [],
totalRecords: 0,
};
const fileContent = file.buffer.toString(FileEncodingsEnum.CSV);

parseString(fileContent, options)
.on('error', reject)
.on('error', (error) => {
if (error.message.includes('Parse Error')) {
reject(new InvalidFileException());
} else {
reject(error);
}
})
.on('headers', (headers) => information.headings.push(...headers))
.on('data', (row) => information.data.push(row))
.on('end', () => {
if (!information.data.length) return reject(new EmptyFileException());
information.totalRecords = information.data.length;
resolve(information);
});
});
}
}
export class ExcelFileService extends FileService {
async getFileInformation(storageService: StorageService, storageKey: string): Promise<IFileInformation> {
const fileContent = await storageService.getFileContent(storageKey, FileEncodingsEnum.EXCEL);

return this.getExcelInformation(fileContent);
}
async getExcelInformation(fileContent: string): Promise<IFileInformation> {
async getFileInformation(file: Express.Multer.File): Promise<IFileInformation> {
const fileContent = file.buffer.toString(FileEncodingsEnum.EXCEL);
const workbookHeaders = XLSX.read(fileContent);
// Throw empty error if file do not have any sheets
if (workbookHeaders.SheetNames.length < Defaults.DATA_LENGTH) throw new EmptyFileException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ export class MakeUploadEntry {
) {}

async execute({ file, templateId, extra, authHeaderValue }: MakeUploadEntryCommand) {
const fileService: FileService = getFileService(file.mimetype);
const fileInformation = await fileService.getFileInformation(file, { headers: true });
const uploadId = this.commonRepository.generateMongoId();
const fileEntity = await this.makeFileEntry(uploadId, file);
const fileService: FileService = getFileService(file.mimetype);
const fileInformation = await fileService.getFileInformation(this.storageService, fileEntity.path);
const allDataFile = await this.addAllDataEntry(uploadId, fileInformation.data);

return this.addUploadEntry(
Expand Down
3 changes: 3 additions & 0 deletions apps/widget/src/hooks/Phase1/usePhase1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export function usePhase1({ goNext }: IUsePhase1Props) {
setUploadInfo(uploadData);
goNext();
},
onError(error: IErrorObject) {
notifier.showError({ title: error.error, message: error.message });
},
}
);
const {
Expand Down
1 change: 1 addition & 0 deletions apps/widget/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './store.types';
export * from './icon.types';
export * from './component.types';
export * from './utility.types';
1 change: 1 addition & 0 deletions apps/widget/src/types/utility.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type NotificationContent = { title: string; message: string };
10 changes: 8 additions & 2 deletions apps/widget/src/util/notifier/Notifier.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { colors, TEXTS } from '@config';
import { NotificationContent } from '@types';
import { showNotification } from '@mantine/notifications';

const autoCloseDuration = 5000;
export function showError(type: keyof typeof TEXTS.NOTIFICATIONS) {
const notificationData = TEXTS.NOTIFICATIONS[type];
export function showError(data: NotificationContent | keyof typeof TEXTS.NOTIFICATIONS) {
let notificationData: NotificationContent;
if (typeof data === 'string') {
notificationData = TEXTS.NOTIFICATIONS[data];
} else {
notificationData = data;
}
showNotification({
color: '#FFFFFF',
autoClose: autoCloseDuration,
Expand Down

0 comments on commit faf201c

Please sign in to comment.