Skip to content

Commit

Permalink
[Bug] : #18
Browse files Browse the repository at this point in the history
  • Loading branch information
Basi-mohd committed Nov 25, 2024
1 parent 5af957c commit 0e96522
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 52 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
server/src/common/exchangeRate.json
server/src/common/exchangeRate.json
4 changes: 4 additions & 0 deletions client/src/app/core/services/quotation/quotation.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export class QuotationService {
return this.http.post(`${this.api}/quotation/markAsQuotationSeened`, { quoteId, userId })
}

removeLpo(fileName: string, quoteId: string): Observable<any> {
return this.http.delete(`${this.api}/quotation/lpo/${quoteId}/${fileName}`)
}


getBase64ImageFromURL(url: string) {
return new Promise((resolve, reject) => {
Expand Down
8 changes: 6 additions & 2 deletions client/src/app/lib/icons/icons.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ import {
heroInformationCircle,
heroArrowTrendingUp,
heroArrowUturnLeft,
heroChartBar
heroChartBar,
heroArrowUpTray,
heroDocument
} from '@ng-icons/heroicons/outline';

import { heroBellSolid } from '@ng-icons/heroicons/solid'
Expand Down Expand Up @@ -122,7 +124,9 @@ import { heroBellSolid } from '@ng-icons/heroicons/solid'
heroInformationCircle,
heroArrowTrendingUp,
heroArrowUturnLeft,
heroChartBar
heroChartBar,
heroArrowUpTray,
heroDocument
}),
],
exports: [NgIconsModule]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ <h3 class="font-semibold">Quotations</h3>
class="cursor-pointer text-center flex justify-center items-center gap-2 px-2 py-2 bg-violet-700 hover:bg-violet-600 text-white text-sm rounded-full font-medium">
<ng-icon name="heroDocumentArrowUp"></ng-icon>
</div>
<div (click)="onViewLpo(element,$event)"
<div (click)="onViewLpo(element,$event,i)"
*ngIf="element.status == 'Won' && element.lpoFiles.length " matTooltip="View Lpo"
matTooltipPosition="above" matTooltipClass="mat-tooltip"
class="cursor-pointer w-8 h-8 rounded-full border border-gray-300 hover:border-gray-500 flex justify-center items-center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,6 @@ export class QuotationListComponent {


onPreviewDeal(approval: boolean, quoteData: Quotatation, event: Event, index: number) {
console.log(quoteData);

event.stopPropagation()
let priceDetails = {
totalSellingPrice: 0,
Expand Down Expand Up @@ -330,11 +328,16 @@ export class QuotationListComponent {
})
}

onViewLpo(data: Quotatation, event: Event) {
onViewLpo(data: Quotatation, event: Event, index: number) {
event.stopPropagation()
this._dialog.open(ViewLpoComponent,
{
data: data
}).afterClosed().subscribe((quote: Quotatation) => {
if (quote) {
this.dataSource.data[index].lpoFiles = quote.lpoFiles
this.dataSource._updateChangeSubscription();
}
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,57 @@
<div class=" bg-black bg-opacity-50 flex items-center justify-center ">
<div class="bg-white rounded-lg shadow-lg max-w-lg w-full p-6">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold">LPO Files</h2>
<button class="bg-gray-200 rounded-lg p-1 text-center flex items-center justify-center" (click)="onClose()">
<ng-icon name="heroXMark" class="text-md p-0 m-0"></ng-icon>
<div class="bg-black bg-opacity-50 flex items-center justify-center min-w-90">
<div class="bg-white rounded-lg shadow-lg max-w-lg w-full ">
<!-- Header -->
<div class="flex justify-between items-center px-6 py-3">
<h2 class="text-xl font-bold text-gray-800">LPO Files</h2>
<button class="hover:bg-gray-100 rounded-full p-2 text-center flex items-center justify-center transition-colors" (click)="onClose()">
<ng-icon name="heroXMark" class="text-gray-500 text-md"></ng-icon>
</button>
</div>
<div class="space-y-4">
<div >
<div class="p-2 bg-gray-100 rounded " *ngFor="let file of data.lpoFiles;let i=index">
<p class="text-sm w-64 flex items-center"><span
(click)="onDownloadClicks(file)"
class="hover:underline hover:text-purple-600 hover:cursor-pointer max-w-[13rem] truncate"
[matTooltip]="'Download File'" matTooltipPosition="below"
matTooltipClass="mat-tooltip">{{file.originalname}}</span>
</p>
</div>

<!-- Divider -->
<div class="h-px bg-gray-200 "></div>

<!-- Files List -->
<div class="space-y-2 p-6">
<div *ngFor="let file of data.lpoFiles; let i=index"
class="p-3 hover:bg-gray-50 rounded-md flex justify-between items-center gap-4 border border-gray-100">
<p class="text-sm flex items-center">
<ng-icon name="heroDocument" class="text-gray-400 mr-2"></ng-icon>
<span (click)="onDownloadClicks(file)"
class="hover:underline hover:text-purple-600 hover:cursor-pointer max-w-[13rem] truncate"
[matTooltip]="'Download File'"
matTooltipPosition="below"
matTooltipClass="mat-tooltip">
{{file.originalname}}
</span>
</p>
<ng-container *ngIf="!data.dealData">
<ng-container *ngIf="removingFileIndex === i; else removeIcon">
<ng-icon name="heroArrowPath" class="text-orange-500 text-lg spin"></ng-icon>
</ng-container>
<ng-template #removeIcon>
<ng-icon name="heroXMark"
class="text-gray-400 hover:text-red-500 text-lg cursor-pointer transition-colors"
(click)="onFileRemoved(i)">
</ng-icon>
</ng-template>
</ng-container>
</div>
</div>

<!-- Divider -->
<div class="h-px bg-gray-200"></div>

<!-- Upload Button -->
<div class="flex justify-end px-6 py-3">
<label *ngIf="!data.dealData"
class="relative inline-flex items-center gap-1.5 bg-violet-700 hover:bg-violet-600 text-white font-medium py-1.5 px-3 rounded text-xs cursor-pointer transition-colors">
<input type="file" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
(change)="onUploadLpo($event)">
<ng-icon name="heroArrowUpTray" class="text-sm"></ng-icon>
<span>{{ isUploading ? 'Uploading...' : 'Add File' }}</span>
<ng-icon *ngIf="isUploading" class="spin text-sm" name="heroArrowPath"></ng-icon>
</label>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import saveAs from 'file-saver';
import { ToastrService } from 'ngx-toastr';
import { EnquiryService } from 'src/app/core/services/enquiry/enquiry.service';
import { QuotationService } from 'src/app/core/services/quotation/quotation.service';
import { ViewCommentComponent } from 'src/app/modules/assigned-jobs/pages/view-comment/view-comment.component';
import { Quotatation } from 'src/app/shared/interfaces/quotation.interface';

Expand All @@ -14,36 +15,80 @@ import { Quotatation } from 'src/app/shared/interfaces/quotation.interface';
})
export class ViewLpoComponent {

progress: number = 0
progress: number = 0;
isUploading: boolean = false;
removingFileIndex: number | null = null;

constructor(
private dialogRef: MatDialogRef<ViewCommentComponent>,
@Inject(MAT_DIALOG_DATA) public data:Quotatation,
private _enquiryService:EnquiryService,
@Inject(MAT_DIALOG_DATA) public data: Quotatation,
private _enquiryService: EnquiryService,
private toast: ToastrService,
) { }
private _quotationService: QuotationService
) {
this.dialogRef.backdropClick().subscribe(() => {
this.onClose();
});
}

onClose() {
this.dialogRef.close()
this.dialogRef.close(this.data)
}

onDownloadClicks(file: any) {
this._enquiryService.downloadFile(file.fileName)
.subscribe({
next: (event) => {
if (event.type === HttpEventType.DownloadProgress) {
this.progress = Math.round(100 * event.loaded / event.total);
} else if (event.type === HttpEventType.Response) {
const fileContent: Blob = new Blob([event['body']])
saveAs(fileContent, file.originalname)
this.clearProgress()
}
},
error: (error) => {
if (error.status == 404) {
this.toast.warning('Sorry, The requested file was not found on the server. Please ensure that the file exists and try again.')
this._enquiryService.downloadFile(file.fileName)
.subscribe({
next: (event) => {
if (event.type === HttpEventType.DownloadProgress) {
this.progress = Math.round(100 * event.loaded / event.total);
} else if (event.type === HttpEventType.Response) {
const fileContent: Blob = new Blob([event['body']])
saveAs(fileContent, file.originalname)
this.clearProgress()
}
},
error: (error) => {
if (error.status == 404) {
this.toast.warning('Sorry, The requested file was not found on the server. Please ensure that the file exists and try again.')
}
}
})
}

onFileRemoved(index: number) {
this.removingFileIndex = index;
this._quotationService.removeLpo(this.data.lpoFiles[index].fileName, this.data._id as string)
.subscribe({
next: (response) => {
if (response.success) {
this.data.lpoFiles.splice(index, 1)
if (this.data.lpoFiles.length == 0) {
this.onClose()
}
}
})
},
complete: () => {
this.removingFileIndex = null;
}
})
}

onUploadLpo(event: any) {
let files = event.target.files
if (files.length) {
this.isUploading = true
let formData = new FormData();
formData.append('quoteId', this.data._id as string)
for (let i = 0; i < files.length; i++) {
formData.append('files', files[i] as Blob)
}
this._quotationService.uploadLpo(formData).subscribe((quote: Quotatation) => {
if (quote) {
this.isUploading = false
this.data.lpoFiles = quote.lpoFiles
}
})
}
}

clearProgress() {
Expand Down
2 changes: 1 addition & 1 deletion server/src/common/exchangeRate.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"rate":3.64,"timestamp":1732195607270}
{"rate":3.64,"timestamp":1732518409534}
37 changes: 31 additions & 6 deletions server/src/controllers/quotation.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { calculateDiscountPrice, getAllReportedEmployees, getUSDRated } from "..
const { ObjectId } = require('mongodb');
import { removeFile } from '../common/util'
import quotationModel from "../models/quotation.model";
import { uploadFileToAws } from '../common/aws-connect';
import { deleteFileFromAws, uploadFileToAws } from '../common/aws-connect';

export const saveQuotation = async (req: Request, res: Response, next: NextFunction) => {
try {
Expand Down Expand Up @@ -732,10 +732,10 @@ export const rejectDeal = async (req: Request, res: Response, next: NextFunction
deal.dealData.status = 'rejected';
deal.dealData.seenedBySalsePerson = false
deal.dealData.comments.push(comment);
await deal.save();
const savedDeal = await deal.save();

const socket = req.app.get('io') as Server;
socket.emit("notifications", 'quotation')
socket.to(savedDeal.createdBy.toString()).emit("notifications", 'quotation')

return res.status(200).json({ success: true })

Expand Down Expand Up @@ -776,12 +776,21 @@ export const uploadLpo = async (req: any, res: Response, next: NextFunction) =>
if (!req.files) return res.status(204).json({ err: 'No data' });

const lpoFiles = req.files;
const files = await Promise.all(lpoFiles.map(async (file: any) => {
const newFiles = await Promise.all(lpoFiles.map(async (file: any) => {
await uploadFileToAws(file.filename, file.path);
return { fileName: file.filename, originalname: file.originalname };
}));

const quote = await Quotation.findByIdAndUpdate(req.body.quoteId, { lpoSubmitted: true, lpoFiles: files });
// Use $push to append new files to existing array
const quote = await Quotation.findByIdAndUpdate(
req.body.quoteId,
{
lpoSubmitted: true,
$push: { lpoFiles: { $each: newFiles } }
},
{ new: true } // Return updated document
);

if (quote) {
return res.status(200).json(quote);
}
Expand Down Expand Up @@ -1065,4 +1074,20 @@ export const markAsQuotationSeened = async (req: Request, res: Response, next: N
console.log(error)
next(error);
}
};
};

export const removeLpo = async (req: Request, res: Response, next: NextFunction) => {
try {
const { quoteId, fileName } = req.params;
const quote = await Quotation.findById(quoteId);
if (quote) {
quote.lpoFiles = quote.lpoFiles.filter((file: any) => file.fileName !== fileName) as [];
await deleteFileFromAws(fileName);
await quote.save();
}
return res.status(200).json({ success: true });
} catch (error) {
console.log(error)
next(error);
}
}
6 changes: 3 additions & 3 deletions server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: process.env.ORIGIN1 ?? 'http://localhost:4200',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
credentials: true
}
});
app.set('io', io);

app.use(morgan("combined"));
app.use(morgan("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

Expand All @@ -48,7 +48,7 @@ dotenv.config({ path: path.resolve(__dirname, '../.env') });

app.use(cors({
origin: process.env.ORIGIN1,
methods: ['GET', 'POST', 'PUT', 'PATCH' , 'DELETE'],
methods: ['GET', 'POST', 'PUT', 'PATCH' , 'DELETE', 'OPTIONS'],
credentials: true,
}));

Expand Down
2 changes: 2 additions & 0 deletions server/src/routes/quotation.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
markAsQuotationSeened,
markAsSeenDeal,
rejectDeal,
removeLpo,
revokeDeal,
saveDealSheet,
saveQuotation,
Expand Down Expand Up @@ -37,5 +38,6 @@ quoteRouter.get('/total', totalQuotation)
quoteRouter.post('/nextQuoteId', getNextQuoteId)
quoteRouter.post('/markAsSeenedDeal', markAsSeenDeal);
quoteRouter.post('/markAsQuotationSeened', markAsQuotationSeened);
quoteRouter.delete('/lpo/:quoteId/:fileName', removeLpo);

export default quoteRouter;

0 comments on commit 0e96522

Please sign in to comment.