@paro.io/expert-shared-components 1.12.33 → 1.12.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,6 +16,7 @@ interface ClientDocumentTableProps {
16
16
  documentUploadUrl?: string;
17
17
  downloadDocumentUrl?: string;
18
18
  clientId?: number;
19
+ stage?: string;
19
20
  }
20
- export declare const ClientDocumentsTable: ({ legacyFreelancerId, expertFiles, setExpertClientFiles, clientAndProjectsList, uploadExpertClientFiles, paroDocuments, freelancerName, freelancerEmail, updateFileLastViewed, deleteExpertClientFile, getFileLazyQuery, expertClientFilesLazyQuery, isClientPortal, documentUploadUrl, downloadDocumentUrl, clientId }: ClientDocumentTableProps) => JSX.Element;
21
+ export declare const ClientDocumentsTable: ({ legacyFreelancerId, expertFiles, setExpertClientFiles, clientAndProjectsList, uploadExpertClientFiles, paroDocuments, freelancerName, freelancerEmail, updateFileLastViewed, deleteExpertClientFile, getFileLazyQuery, expertClientFilesLazyQuery, isClientPortal, documentUploadUrl, downloadDocumentUrl, clientId, stage }: ClientDocumentTableProps) => JSX.Element;
21
22
  export {};
@@ -135,7 +135,7 @@ const getKeyByValue = (object, value) => {
135
135
  }
136
136
  return Object.keys(object).find(key => object[key] === value);
137
137
  };
138
- const ClientDocumentsTable = ({ legacyFreelancerId, expertFiles, setExpertClientFiles, clientAndProjectsList, uploadExpertClientFiles, paroDocuments, freelancerName, freelancerEmail, updateFileLastViewed, deleteExpertClientFile, getFileLazyQuery, expertClientFilesLazyQuery, isClientPortal, documentUploadUrl, downloadDocumentUrl, clientId }) => {
138
+ const ClientDocumentsTable = ({ legacyFreelancerId, expertFiles, setExpertClientFiles, clientAndProjectsList, uploadExpertClientFiles, paroDocuments, freelancerName, freelancerEmail, updateFileLastViewed, deleteExpertClientFile, getFileLazyQuery, expertClientFilesLazyQuery, isClientPortal, documentUploadUrl, downloadDocumentUrl, clientId, stage }) => {
139
139
  const classes = (0, exports.useStyles)();
140
140
  const [order, setOrder] = react_1.default.useState('desc');
141
141
  const [orderBy, setOrderBy] = react_1.default.useState('lastViewed');
@@ -304,12 +304,13 @@ const ClientDocumentsTable = ({ legacyFreelancerId, expertFiles, setExpertClient
304
304
  setFileId(null);
305
305
  });
306
306
  };
307
- const handleDownloadFile = (fileName, fileId, projectId, docSize) => __awaiter(void 0, void 0, void 0, function* () {
307
+ const handleDownloadFile = (fileName, fileId, projectId, docSize, docType) => __awaiter(void 0, void 0, void 0, function* () {
308
308
  (0, utils_1.showToast)('success', 'Starting File Download...');
309
309
  fileId && setFileId(fileId);
310
+ const bucketName = docType === 'Dispute Documents' ? `expert-client-dispute-files${!stage || stage === 'dev' ? '' : `-${stage}`}` : `expert-client-files-${stage}`;
310
311
  if (docSize >= 5) {
311
312
  const downloadFileName = `project-${projectId}/${fileName}`;
312
- const downloadClient = new DownloadClient_1.default({ downloadDocumentUrl: downloadDocumentUrl, fileKey: downloadFileName });
313
+ const downloadClient = new DownloadClient_1.default({ downloadDocumentUrl: downloadDocumentUrl, fileKey: downloadFileName, bucketName: bucketName });
313
314
  const downloadData = yield downloadClient.downloadDocument();
314
315
  (0, utils_1.handleDownloadPdf)({ fileData: downloadData, downloadFilename: fileName, streamData: true });
315
316
  updateLastViewed();
@@ -355,7 +356,7 @@ const ClientDocumentsTable = ({ legacyFreelancerId, expertFiles, setExpertClient
355
356
  return (react_1.default.createElement(core_1.TableRow, { key: fileId },
356
357
  react_1.default.createElement(core_1.TableCell, { className: classes.tableCell, align: "center" }, index + 1),
357
358
  react_1.default.createElement(core_1.TableCell, { className: classes.tableCell, align: "center" },
358
- react_1.default.createElement("a", { onClick: () => handleDownloadFile(fileName, fileId, projectId, docSize), style: {
359
+ react_1.default.createElement("a", { onClick: () => handleDownloadFile(fileName, fileId, projectId, docSize, docType), style: {
359
360
  color: 'blue',
360
361
  textDecoration: 'underline',
361
362
  cursor: 'pointer',
@@ -373,7 +374,7 @@ const ClientDocumentsTable = ({ legacyFreelancerId, expertFiles, setExpertClient
373
374
  react_1.default.createElement(core_1.TableCell, { className: classes.tableCell },
374
375
  react_1.default.createElement(core_1.Grid, { item: true, container: true, direction: "row", justify: "space-evenly", alignItems: "center" },
375
376
  react_1.default.createElement(core_1.Tooltip, { arrow: true, placement: "top", interactive: true, className: "whitespace-nowrap", title: "Download Document" },
376
- react_1.default.createElement(core_1.IconButton, { onClick: () => __awaiter(void 0, void 0, void 0, function* () { return handleDownloadFile(fileName, fileId, projectId, docSize); }) },
377
+ react_1.default.createElement(core_1.IconButton, { onClick: () => __awaiter(void 0, void 0, void 0, function* () { return handleDownloadFile(fileName, fileId, projectId, docSize, docType); }) },
377
378
  " ",
378
379
  react_1.default.createElement(base_icons_1.IconDocumentDownload, { size: "sm" }),
379
380
  " ")),
@@ -23,6 +23,7 @@ interface DocumentCenterProps {
23
23
  downloadDocumentUrl?: string;
24
24
  loading?: boolean;
25
25
  clientId?: number;
26
+ stage?: string;
26
27
  }
27
- export declare const DocumentCenter: ({ legacyFreelancerId, openModal, setOpenModal, expertClientFilesLazyQuery, getClientAndProjectsLazyQuery, clientFilesData, uploadExpertClientFiles, uploadFileData, deleteFileMutation, updateFreelancerExpiryMutation, foldername, getFilesLazyQuery, getFileLazyQuery, freelancerName, freelancerEmail, updateFileLastViewed, deleteExpertClientFile, isClientPortal, expertProjectsList, getFreelancerLazyQuery, documentUploadUrl, downloadDocumentUrl, clientId, loading, }: DocumentCenterProps) => JSX.Element;
28
+ export declare const DocumentCenter: ({ legacyFreelancerId, openModal, setOpenModal, expertClientFilesLazyQuery, getClientAndProjectsLazyQuery, clientFilesData, uploadExpertClientFiles, uploadFileData, deleteFileMutation, updateFreelancerExpiryMutation, foldername, getFilesLazyQuery, getFileLazyQuery, freelancerName, freelancerEmail, updateFileLastViewed, deleteExpertClientFile, isClientPortal, expertProjectsList, getFreelancerLazyQuery, documentUploadUrl, downloadDocumentUrl, clientId, loading, stage, }: DocumentCenterProps) => JSX.Element;
28
29
  export {};
@@ -80,7 +80,7 @@ const CustomDialogContent = (0, core_1.styled)(core_1.DialogContent)(({ theme })
80
80
  background: '#707070',
81
81
  },
82
82
  }));
83
- const DocumentCenter = ({ legacyFreelancerId, openModal, setOpenModal, expertClientFilesLazyQuery, getClientAndProjectsLazyQuery, clientFilesData, uploadExpertClientFiles, uploadFileData, deleteFileMutation, updateFreelancerExpiryMutation, foldername, getFilesLazyQuery, getFileLazyQuery, freelancerName, freelancerEmail, updateFileLastViewed, deleteExpertClientFile, isClientPortal = false, expertProjectsList, getFreelancerLazyQuery, documentUploadUrl, downloadDocumentUrl, clientId, loading = false, }) => {
83
+ const DocumentCenter = ({ legacyFreelancerId, openModal, setOpenModal, expertClientFilesLazyQuery, getClientAndProjectsLazyQuery, clientFilesData, uploadExpertClientFiles, uploadFileData, deleteFileMutation, updateFreelancerExpiryMutation, foldername, getFilesLazyQuery, getFileLazyQuery, freelancerName, freelancerEmail, updateFileLastViewed, deleteExpertClientFile, isClientPortal = false, expertProjectsList, getFreelancerLazyQuery, documentUploadUrl, downloadDocumentUrl, clientId, loading = false, stage = 'dev', }) => {
84
84
  var _a;
85
85
  const [value, setValue] = (0, react_1.useState)(0);
86
86
  const [expertClientFiles, setExpertClientFiles] = (0, react_1.useState)(clientFilesData !== null && clientFilesData !== void 0 ? clientFilesData : []);
@@ -175,7 +175,7 @@ const DocumentCenter = ({ legacyFreelancerId, openModal, setOpenModal, expertCli
175
175
  react_1.default.createElement("b", null, value === 0 ? ((expertClientFiles === null || expertClientFiles === void 0 ? void 0 : expertClientFiles.length) ? (_a = expertClientFiles === null || expertClientFiles === void 0 ? void 0 : expertClientFiles.filter((file) => !(file === null || file === void 0 ? void 0 : file.lastViewed))) === null || _a === void 0 ? void 0 : _a.length : 0) : expertFiles === null || expertFiles === void 0 ? void 0 : expertFiles.length),
176
176
  " Documents Unread")))),
177
177
  react_1.default.createElement(lab_1.TabPanel, { value: '0', style: { paddingTop: '0px' } },
178
- react_1.default.createElement(ClientDocumentsTable_1.ClientDocumentsTable, { legacyFreelancerId: legacyFreelancerId, expertFiles: expertClientFiles, setExpertClientFiles: setExpertClientFiles, clientAndProjectsList: clientAndProjects, uploadExpertClientFiles: uploadExpertClientFiles, updateFileLastViewed: updateFileLastViewed, deleteExpertClientFile: deleteExpertClientFile, paroDocuments: false, freelancerName: freelancerName !== null && freelancerName !== void 0 ? freelancerName : '', freelancerEmail: freelancerEmail !== null && freelancerEmail !== void 0 ? freelancerEmail : '', getFileLazyQuery: getFileLazyQuery, expertClientFilesLazyQuery: expertClientFilesLazyQuery, isClientPortal: isClientPortal, documentUploadUrl: documentUploadUrl, downloadDocumentUrl: downloadDocumentUrl, clientId: clientId })),
178
+ react_1.default.createElement(ClientDocumentsTable_1.ClientDocumentsTable, { legacyFreelancerId: legacyFreelancerId, expertFiles: expertClientFiles, setExpertClientFiles: setExpertClientFiles, clientAndProjectsList: clientAndProjects, uploadExpertClientFiles: uploadExpertClientFiles, updateFileLastViewed: updateFileLastViewed, deleteExpertClientFile: deleteExpertClientFile, paroDocuments: false, freelancerName: freelancerName !== null && freelancerName !== void 0 ? freelancerName : '', freelancerEmail: freelancerEmail !== null && freelancerEmail !== void 0 ? freelancerEmail : '', getFileLazyQuery: getFileLazyQuery, expertClientFilesLazyQuery: expertClientFilesLazyQuery, isClientPortal: isClientPortal, documentUploadUrl: documentUploadUrl, downloadDocumentUrl: downloadDocumentUrl, clientId: clientId, stage: stage })),
179
179
  react_1.default.createElement(lab_1.TabPanel, { value: '1' },
180
180
  react_1.default.createElement(ParoDocumentsTable_1.ParoDocumentsTable, { legacyFreelancerId: legacyFreelancerId, expiryDate: insuranceExpiryDate !== null && insuranceExpiryDate !== void 0 ? insuranceExpiryDate : '', setExpiryDate: setInsuranceExpiryDate, expertFiles: expertFiles, setExpertFiles: setExpertFiles, uploadExpertClientFiles: uploadExpertClientFiles, uploadFileData: uploadFileData, deleteFileMutation: deleteFileMutation, updateFreelancerExpiryMutation: updateFreelancerExpiryMutation, foldername: foldername !== null && foldername !== void 0 ? foldername : '', paroDocuments: true, getFileLazyQuery: getFileLazyQuery, getFilesLazyQuery: getFilesLazyQuery }))))),
181
181
  react_1.default.createElement(react_hot_toast_1.Toaster, { position: "top-center", toastOptions: {
@@ -6,8 +6,17 @@ interface UploadFileParams {
6
6
  documentUploadUrl: string;
7
7
  bucketName: string;
8
8
  updateClientInvoiceDisputeMutation: any;
9
+ uploadExpertClientFiles?: any;
9
10
  previousFiles: string | string[];
10
11
  isExpert: boolean;
12
+ disputeData?: {
13
+ clientId: number;
14
+ clientName: string;
15
+ email: string;
16
+ freelancerId: number;
17
+ freelancerName: string;
18
+ projectName: string;
19
+ };
11
20
  }
12
- export declare const fileUploader: ({ file, projectId, documentUploadUrl, updateClientInvoiceDisputeMutation, bucketName, disputeId, previousFiles, isExpert, }: UploadFileParams) => Promise<any>;
21
+ export declare const fileUploader: ({ file, projectId, documentUploadUrl, updateClientInvoiceDisputeMutation, uploadExpertClientFiles, bucketName, disputeId, previousFiles, isExpert, disputeData, }: UploadFileParams) => Promise<any>;
13
22
  export {};
@@ -15,7 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.fileUploader = void 0;
16
16
  const UploadClient_1 = __importDefault(require("../shared/UploadClient"));
17
17
  const utils_1 = require("../shared/utils");
18
- const fileUploader = (_a) => __awaiter(void 0, [_a], void 0, function* ({ file, projectId, documentUploadUrl, updateClientInvoiceDisputeMutation, bucketName, disputeId, previousFiles, isExpert, }) {
18
+ const fileUploader = (_a) => __awaiter(void 0, [_a], void 0, function* ({ file, projectId, documentUploadUrl, updateClientInvoiceDisputeMutation, uploadExpertClientFiles, bucketName, disputeId, previousFiles, isExpert, disputeData, }) {
19
19
  const documentLinks = previousFiles ? (typeof previousFiles === 'string' ? previousFiles.split(',') : [...previousFiles]) : [];
20
20
  try {
21
21
  (0, utils_1.showToast)('success', 'Starting Document Upload');
@@ -30,20 +30,48 @@ const fileUploader = (_a) => __awaiter(void 0, [_a], void 0, function* ({ file,
30
30
  const resParsed = JSON.parse(res);
31
31
  const documentLink = resParsed === null || resParsed === void 0 ? void 0 : resParsed.Location;
32
32
  documentLinks.push(documentLink); // Add the new file to the documentLinks array
33
- disputeId && (yield updateClientInvoiceDisputeMutation({
34
- variables: {
35
- input: {
36
- disputeId: disputeId,
37
- projectDisputes: [
38
- Object.assign({ projectId: projectId }, (isExpert ? {
39
- expertDocumentLinks: documentLinks.join(',')
40
- } : {
41
- clientDocumentLinks: documentLinks.join(',')
42
- }))
43
- ]
33
+ const promises = [];
34
+ if (disputeId) {
35
+ promises.push(updateClientInvoiceDisputeMutation({
36
+ variables: {
37
+ input: {
38
+ disputeId: disputeId,
39
+ projectDisputes: [
40
+ Object.assign({ projectId: projectId }, (isExpert ? {
41
+ expertDocumentLinks: documentLinks.join(',')
42
+ } : {
43
+ clientDocumentLinks: documentLinks.join(',')
44
+ }))
45
+ ]
46
+ },
44
47
  },
45
- },
46
- }));
48
+ }));
49
+ }
50
+ if (uploadExpertClientFiles && disputeData) {
51
+ promises.push(uploadExpertClientFiles({
52
+ variables: {
53
+ input: {
54
+ clientId: disputeData.clientId,
55
+ clientName: disputeData.clientName,
56
+ email: disputeData.email,
57
+ fileName: file.name,
58
+ fileSize: file.size,
59
+ fileType: 'DISPUTE_DOCUMENTS',
60
+ freelancerId: disputeData.freelancerId,
61
+ freelancerName: disputeData.freelancerName,
62
+ projectId: projectId,
63
+ projectName: disputeData.projectName,
64
+ uploadedBy: isExpert ? 'FREELANCER' : 'CLIENT',
65
+ data: "",
66
+ },
67
+ }
68
+ }));
69
+ }
70
+ // Execute all promises in parallel
71
+ if (promises.length > 0) {
72
+ yield Promise.all(promises);
73
+ console.log('Document uploaded successfully to S3 and to Document Center');
74
+ }
47
75
  console.log(`Multipart File uploaded successfully with ${res}`);
48
76
  (0, utils_1.showToast)('success', 'Document Upload Successful');
49
77
  }));
@@ -4,7 +4,8 @@ interface ClientDisputeProjectCardProps {
4
4
  documentUploadUrl: string;
5
5
  downloadDocumentUrl: string;
6
6
  bucketName?: string;
7
+ uploadExpertClientFiles?: any;
7
8
  }
8
9
  export declare const handleDownloadDocument: (projectId: number, fileName: string, downloadDocumentUrl: string, bucketName: string | undefined) => Promise<void>;
9
- export declare const ClientDisputeProjectCard: ({ clientInvoice, updateClientInvoiceDisputeMutation, documentUploadUrl, downloadDocumentUrl, bucketName }: ClientDisputeProjectCardProps) => JSX.Element;
10
+ export declare const ClientDisputeProjectCard: ({ clientInvoice, updateClientInvoiceDisputeMutation, documentUploadUrl, downloadDocumentUrl, bucketName, uploadExpertClientFiles }: ClientDisputeProjectCardProps) => JSX.Element;
10
11
  export {};
@@ -145,7 +145,7 @@ const handleDownloadDocument = (projectId, fileName, downloadDocumentUrl, bucket
145
145
  });
146
146
  });
147
147
  exports.handleDownloadDocument = handleDownloadDocument;
148
- const ClientDisputeProjectCard = ({ clientInvoice, updateClientInvoiceDisputeMutation, documentUploadUrl, downloadDocumentUrl, bucketName }) => {
148
+ const ClientDisputeProjectCard = ({ clientInvoice, updateClientInvoiceDisputeMutation, documentUploadUrl, downloadDocumentUrl, bucketName, uploadExpertClientFiles }) => {
149
149
  const [expandRow, setExpandRow] = (0, react_1.useState)(null);
150
150
  const classes = useStyles();
151
151
  const [projects, setProjects] = (0, react_1.useState)(clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.disputeProjects);
@@ -192,7 +192,7 @@ const ClientDisputeProjectCard = ({ clientInvoice, updateClientInvoiceDisputeMut
192
192
  return new Promise((resolve, reject) => {
193
193
  const reader = new FileReader();
194
194
  reader.onloadend = () => __awaiter(void 0, void 0, void 0, function* () {
195
- var _a, _b, _c, _d, _e;
195
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
196
196
  try {
197
197
  const res = yield (0, FileUploader_1.fileUploader)({
198
198
  file: selectedFile,
@@ -204,6 +204,15 @@ const ClientDisputeProjectCard = ({ clientInvoice, updateClientInvoiceDisputeMut
204
204
  updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation,
205
205
  previousFiles: (_e = (_d = (_c = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.disputeProjects) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.clientDocumentLinks) !== null && _e !== void 0 ? _e : [],
206
206
  isExpert: false,
207
+ uploadExpertClientFiles: uploadExpertClientFiles,
208
+ disputeData: {
209
+ clientId: (_f = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.invoice) === null || _f === void 0 ? void 0 : _f.clientId,
210
+ clientName: (_g = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.client) === null || _g === void 0 ? void 0 : _g.name,
211
+ email: (_h = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.freelancer) === null || _h === void 0 ? void 0 : _h.email,
212
+ freelancerId: clientInvoice.freelancerId,
213
+ freelancerName: ((_j = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.freelancer) === null || _j === void 0 ? void 0 : _j.firstName) + ' ' + ((_k = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.freelancer) === null || _k === void 0 ? void 0 : _k.lastName),
214
+ projectName: (_o = (_m = (_l = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.disputeProjects) === null || _l === void 0 ? void 0 : _l[0]) === null || _m === void 0 ? void 0 : _m.project) === null || _o === void 0 ? void 0 : _o.name
215
+ }
207
216
  });
208
217
  if (res) {
209
218
  setProjects((prevProjects) => prevProjects.map((p) => {
@@ -6,6 +6,7 @@ interface DecisionSectionProps {
6
6
  getClientInvoiceSummaryByMonth: any;
7
7
  invoiceSummary: any;
8
8
  updateClientInvoiceDisputeMutation: any;
9
+ addClientCredit: any;
9
10
  }
10
- export declare const DecisionSection: ({ dispute, onUpdateDispute, updateInvoiceMutation, updateClientInvoiceDisputeMutation, invoiceSummary, user, getClientInvoiceSummaryByMonth, }: DecisionSectionProps) => JSX.Element;
11
+ export declare const DecisionSection: ({ dispute, onUpdateDispute, updateInvoiceMutation, updateClientInvoiceDisputeMutation, invoiceSummary, user, getClientInvoiceSummaryByMonth, addClientCredit }: DecisionSectionProps) => JSX.Element;
11
12
  export {};
@@ -42,14 +42,15 @@ const RESOLUTION_OPTIONS = [
42
42
  { value: 'DECLINED', label: 'Decline Dispute' },
43
43
  { value: 'PARTIAL', label: 'Partial Approval' },
44
44
  ];
45
- const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, updateClientInvoiceDisputeMutation, invoiceSummary, user, getClientInvoiceSummaryByMonth, }) => {
46
- var _a, _b;
45
+ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, updateClientInvoiceDisputeMutation, invoiceSummary, user, getClientInvoiceSummaryByMonth, addClientCredit }) => {
46
+ var _a, _b, _c, _d;
47
47
  const totalDisputeHours = (_a = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _a === void 0 ? void 0 : _a.reduce((acc, project) => acc + (project === null || project === void 0 ? void 0 : project.disputeHours), 0);
48
48
  const [resolution, setResolution] = (0, react_1.useState)('');
49
49
  const [approvedHours, setApprovedHours] = (0, react_1.useState)(totalDisputeHours);
50
50
  const [projectApprovedHours, setProjectApprovedHours] = (0, react_1.useState)({});
51
51
  const [isSubmitting, setIsSubmitting] = (0, react_1.useState)(false);
52
52
  const [showHoursModal, setShowHoursModal] = (0, react_1.useState)(false);
53
+ const isDisputePaid = ((_b = dispute === null || dispute === void 0 ? void 0 : dispute.invoice) === null || _b === void 0 ? void 0 : _b.clientInvoiceStatusId) === 4 || ((_c = dispute === null || dispute === void 0 ? void 0 : dispute.invoice) === null || _c === void 0 ? void 0 : _c.clientInvoiceStatusId) === 8;
53
54
  // Initialize project approved hours when resolution changes to PARTIAL
54
55
  const handleResolutionChange = (newResolution) => {
55
56
  var _a;
@@ -84,7 +85,6 @@ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, upda
84
85
  const handleApproveClick = () => {
85
86
  if (!resolution)
86
87
  return;
87
- // Show modal for PARTIAL or APPROVED resolutions regardless of dispute type
88
88
  if (resolution === 'PARTIAL' || resolution === 'APPROVED') {
89
89
  setShowHoursModal(true);
90
90
  }
@@ -100,19 +100,13 @@ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, upda
100
100
  var _a, _b, _c;
101
101
  setIsSubmitting(true);
102
102
  try {
103
- const resolutionType = resolution === 'APPROVED' ? 'Upheld' : 'Reduced';
104
- const disputeProjectUpdates = ((_a = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _a === void 0 ? void 0 : _a.map((project) => ({
105
- projectId: project.projectId,
106
- resolutionMode: 'Direct',
107
- resolutionType: resolution === 'DECLINED' ? 'Canceled' : resolutionType
108
- }))) || [];
109
103
  let calculatedApprovedAmount = 0;
110
- const fullDisputeAmount = (_b = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _b === void 0 ? void 0 : _b.reduce((acc, project) => acc + project.disputeAmount, 0);
104
+ const fullDisputeAmount = (_a = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _a === void 0 ? void 0 : _a.reduce((acc, project) => acc + project.disputeAmount, 0);
111
105
  if (resolution === 'APPROVED') {
112
106
  calculatedApprovedAmount = fullDisputeAmount;
113
107
  }
114
108
  else {
115
- (_c = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _c === void 0 ? void 0 : _c.forEach((project) => {
109
+ (_b = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _b === void 0 ? void 0 : _b.forEach((project) => {
116
110
  var _a, _b;
117
111
  const approvedForProject = projectApprovedHours[project.projectId] || 0;
118
112
  if (project.disputeType === 'Hourly') {
@@ -124,6 +118,50 @@ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, upda
124
118
  }
125
119
  });
126
120
  }
121
+ if (submissionData) {
122
+ if (isDisputePaid) {
123
+ yield addClientCredit({
124
+ variables: {
125
+ input: {
126
+ clientId: submissionData.clientId,
127
+ amount: calculatedApprovedAmount,
128
+ description: `Credit from Dispute #${dispute.disputeId} - Invoice #${dispute.invoice.id}`,
129
+ updatedDate: new Date().toISOString()
130
+ }
131
+ }
132
+ });
133
+ }
134
+ else {
135
+ yield updateInvoiceMutation({
136
+ variables: {
137
+ input: submissionData.input,
138
+ clientId: submissionData.clientId,
139
+ invoiceId: submissionData.invoiceId,
140
+ dateGenerated: submissionData.dateGenerated,
141
+ updateDescription: submissionData.updateDescription,
142
+ freelancerIds: submissionData.freelancerIds
143
+ }
144
+ });
145
+ }
146
+ }
147
+ let resolutionType;
148
+ if (isDisputePaid) {
149
+ resolutionType = 'FutureCredit';
150
+ }
151
+ else if (resolution === 'APPROVED') {
152
+ resolutionType = 'Upheld';
153
+ }
154
+ else if (resolution === 'PARTIAL') {
155
+ resolutionType = 'Reduced';
156
+ }
157
+ else {
158
+ resolutionType = 'Canceled';
159
+ }
160
+ const disputeProjectUpdates = ((_c = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _c === void 0 ? void 0 : _c.map((project) => ({
161
+ projectId: project.projectId,
162
+ resolutionMode: 'Direct',
163
+ resolutionType: resolutionType
164
+ }))) || [];
127
165
  const updateData = {
128
166
  disputeId: dispute.disputeId,
129
167
  status: "Resolved",
@@ -131,24 +169,17 @@ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, upda
131
169
  finalDecisionOwnerId: (user === null || user === void 0 ? void 0 : user.userId) || null,
132
170
  projectDisputes: disputeProjectUpdates
133
171
  };
134
- if (submissionData) {
135
- yield updateInvoiceMutation({
136
- variables: {
137
- input: submissionData.input,
138
- clientId: submissionData.clientId,
139
- invoiceId: submissionData.invoiceId,
140
- dateGenerated: submissionData.dateGenerated,
141
- updateDescription: submissionData.updateDescription,
142
- freelancerIds: submissionData.freelancerIds
143
- }
144
- });
145
- }
146
172
  yield onUpdateDispute({
147
173
  variables: {
148
174
  input: updateData,
149
175
  },
150
176
  });
151
- (0, utils_1.showToast)('success', 'Thank you for resolving the dispute. The invoice has been updated with the new hours.');
177
+ if (isDisputePaid) {
178
+ (0, utils_1.showToast)('success', `Future credit applied: $${calculatedApprovedAmount} to Client ${dispute.client.name}'s balance`);
179
+ }
180
+ else {
181
+ (0, utils_1.showToast)('success', 'Thank you for resolving the dispute. The invoice has been updated with the new hours.');
182
+ }
152
183
  }
153
184
  catch (error) {
154
185
  console.error('Failed to update dispute:', error);
@@ -158,7 +189,7 @@ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, upda
158
189
  setIsSubmitting(false);
159
190
  }
160
191
  });
161
- const isPartialWithMultipleProjects = resolution === 'PARTIAL' && ((_b = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _b === void 0 ? void 0 : _b.length) > 0;
192
+ const isPartialWithMultipleProjects = resolution === 'PARTIAL' && ((_d = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _d === void 0 ? void 0 : _d.length) > 0;
162
193
  const isValidPartialApproval = () => {
163
194
  if (resolution !== 'PARTIAL')
164
195
  return true;
@@ -3,7 +3,10 @@ interface DisputeSectionProps {
3
3
  documentUploadUrl: string;
4
4
  downloadDocumentUrl: string;
5
5
  bucketName: string;
6
+ isInternal: boolean;
6
7
  updateClientInvoiceDisputeMutation: (variables: any) => Promise<any>;
8
+ uploadExpertClientFiles: (variables: any) => Promise<any>;
9
+ hasDisputeAdminRole?: boolean;
7
10
  }
8
- export declare const DisputeSection: ({ dispute, documentUploadUrl, downloadDocumentUrl, bucketName, updateClientInvoiceDisputeMutation, }: DisputeSectionProps) => JSX.Element;
11
+ export declare const DisputeSection: ({ dispute, documentUploadUrl, downloadDocumentUrl, bucketName, isInternal, updateClientInvoiceDisputeMutation, uploadExpertClientFiles, hasDisputeAdminRole }: DisputeSectionProps) => JSX.Element;
9
12
  export {};
@@ -47,7 +47,7 @@ const ACCEPTED_FILE_TYPES = [
47
47
  'image/png',
48
48
  'text/csv',
49
49
  ];
50
- const DisputeSection = ({ dispute, documentUploadUrl, downloadDocumentUrl, bucketName, updateClientInvoiceDisputeMutation, }) => {
50
+ const DisputeSection = ({ dispute, documentUploadUrl, downloadDocumentUrl, bucketName, isInternal, updateClientInvoiceDisputeMutation, uploadExpertClientFiles, hasDisputeAdminRole }) => {
51
51
  var _a, _b, _c;
52
52
  const expertFileInputRef = (0, react_1.useRef)(null);
53
53
  const clientFileInputRef = (0, react_1.useRef)(null);
@@ -74,7 +74,7 @@ const DisputeSection = ({ dispute, documentUploadUrl, downloadDocumentUrl, bucke
74
74
  Array.from(selectedFiles).forEach((selectedFile) => {
75
75
  const reader = new FileReader();
76
76
  reader.onloadend = () => __awaiter(void 0, void 0, void 0, function* () {
77
- var _a, _b;
77
+ var _a, _b, _c, _d, _e, _f, _g, _h;
78
78
  yield (0, FileUploader_1.fileUploader)({
79
79
  file: selectedFile,
80
80
  documentName: selectedFile.name,
@@ -82,9 +82,18 @@ const DisputeSection = ({ dispute, documentUploadUrl, downloadDocumentUrl, bucke
82
82
  documentUploadUrl: documentUploadUrl,
83
83
  bucketName: bucketName,
84
84
  updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation,
85
+ uploadExpertClientFiles: uploadExpertClientFiles,
85
86
  disputeId: dispute === null || dispute === void 0 ? void 0 : dispute.disputeId,
86
87
  previousFiles: isExpert ? expertDocumentLinks : clientDocumentLinks,
87
88
  isExpert: isExpert,
89
+ disputeData: {
90
+ clientId: (_c = dispute === null || dispute === void 0 ? void 0 : dispute.invoice) === null || _c === void 0 ? void 0 : _c.clientId,
91
+ clientName: (_d = dispute === null || dispute === void 0 ? void 0 : dispute.client) === null || _d === void 0 ? void 0 : _d.name,
92
+ email: (_e = dispute === null || dispute === void 0 ? void 0 : dispute.freelancer) === null || _e === void 0 ? void 0 : _e.email,
93
+ freelancerId: dispute === null || dispute === void 0 ? void 0 : dispute.freelancerId,
94
+ freelancerName: `${(_f = dispute === null || dispute === void 0 ? void 0 : dispute.freelancer) === null || _f === void 0 ? void 0 : _f.firstName} ${(_g = dispute === null || dispute === void 0 ? void 0 : dispute.freelancer) === null || _g === void 0 ? void 0 : _g.lastName}`,
95
+ projectName: (_h = disputeProject === null || disputeProject === void 0 ? void 0 : disputeProject.project) === null || _h === void 0 ? void 0 : _h.name,
96
+ },
88
97
  });
89
98
  });
90
99
  reader.readAsDataURL(selectedFile);
@@ -123,7 +132,7 @@ const DisputeSection = ({ dispute, documentUploadUrl, downloadDocumentUrl, bucke
123
132
  }
124
133
  } })))),
125
134
  react_1.default.createElement("div", { className: "w-full mt-2" },
126
- react_1.default.createElement(base_ui_1.Button, { label: "Add File", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: "sm" }), onClick: () => { var _a; return (_a = clientFileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, size: "sm", color: "info", className: "bg-white border border-[#248384] text-[#248384]" })))))),
135
+ react_1.default.createElement(base_ui_1.Button, { label: "Add File", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: "sm" }), onClick: () => { var _a; return (_a = clientFileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, size: "sm", color: "info", className: "bg-white border border-[#248384] text-[#248384]", disabled: isInternal && !hasDisputeAdminRole })))))),
127
136
  react_1.default.createElement("div", { className: "space-y-4" },
128
137
  react_1.default.createElement("div", { className: "flex items-center justify-between" },
129
138
  react_1.default.createElement("div", { className: "text-lg font-bold text-[#333333]" }, "Expert Rebuttal")),
@@ -146,6 +155,6 @@ const DisputeSection = ({ dispute, documentUploadUrl, downloadDocumentUrl, bucke
146
155
  }
147
156
  } })))),
148
157
  react_1.default.createElement("div", { className: "w-full mt-2" },
149
- react_1.default.createElement(base_ui_1.Button, { label: "Add File", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: "sm" }), onClick: () => { var _a; return (_a = expertFileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, size: "sm", color: "info", className: "bg-white border border-[#248384] text-[#248384]" }))))))));
158
+ react_1.default.createElement(base_ui_1.Button, { label: "Add File", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: "sm" }), onClick: () => { var _a; return (_a = expertFileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, size: "sm", color: "info", className: "bg-white border border-[#248384] text-[#248384]", disabled: isInternal && !hasDisputeAdminRole }))))))));
150
159
  };
151
160
  exports.DisputeSection = DisputeSection;
@@ -13,7 +13,9 @@ interface InvoiceCardProps {
13
13
  isClient?: boolean;
14
14
  bucketName?: string;
15
15
  reactAppUrl?: string;
16
+ addClientCredit?: any;
16
17
  isLateDisputeAllowed?: boolean;
18
+ uploadExpertClientFiles?: any;
17
19
  }
18
- export declare const InvoiceCard: ({ clientInvoice, createDisputeChatMessage, user, chatMessages, updateClientInvoiceDisputeMutation, updateInvoiceMutation, getClientInvoiceSummaryByMonth, invoiceSummary, documentUploadUrl, downloadDocumentUrl, isInternal, isClient, bucketName, reactAppUrl, isLateDisputeAllowed, }: InvoiceCardProps) => JSX.Element;
20
+ export declare const InvoiceCard: ({ clientInvoice, createDisputeChatMessage, user, chatMessages, updateClientInvoiceDisputeMutation, uploadExpertClientFiles, updateInvoiceMutation, getClientInvoiceSummaryByMonth, invoiceSummary, documentUploadUrl, downloadDocumentUrl, isInternal, isClient, bucketName, reactAppUrl, addClientCredit, isLateDisputeAllowed }: InvoiceCardProps) => JSX.Element;
19
21
  export {};
@@ -34,12 +34,16 @@ const DisputeSection_1 = require("./DisputeSection");
34
34
  const DiscussionSection_1 = require("./DiscussionSection");
35
35
  const DecisionSection_1 = require("./DecisionSection");
36
36
  const ClientDisputeProjectCard_1 = require("./ClientDisputeProjectCard");
37
- const InvoiceCard = ({ clientInvoice, createDisputeChatMessage, user, chatMessages, updateClientInvoiceDisputeMutation, updateInvoiceMutation, getClientInvoiceSummaryByMonth, invoiceSummary, documentUploadUrl, downloadDocumentUrl, isInternal = false, isClient = false, bucketName, reactAppUrl, isLateDisputeAllowed = false, }) => {
37
+ const InvoiceCard = ({ clientInvoice, createDisputeChatMessage, user, chatMessages, updateClientInvoiceDisputeMutation, uploadExpertClientFiles, updateInvoiceMutation, getClientInvoiceSummaryByMonth, invoiceSummary, documentUploadUrl, downloadDocumentUrl, isInternal = false, isClient = false, bucketName, reactAppUrl, addClientCredit, isLateDisputeAllowed = false }) => {
38
+ var _a;
39
+ const envUrl = reactAppUrl === null || reactAppUrl === void 0 ? void 0 : reactAppUrl.split('.')[1];
40
+ const rolesUrl = `https://app.${envUrl}.io/roles`;
38
41
  const [currentInvoice, setCurrentInvoice] = (0, react_1.useState)(clientInvoice);
39
42
  (0, react_1.useEffect)(() => {
40
43
  setCurrentInvoice(clientInvoice);
41
44
  }, [clientInvoice]);
42
45
  const disputeId = currentInvoice === null || currentInvoice === void 0 ? void 0 : currentInvoice.disputeId;
46
+ const hasDisputeAdminRole = (_a = user === null || user === void 0 ? void 0 : user[rolesUrl]) === null || _a === void 0 ? void 0 : _a.includes('disputes_admin');
43
47
  return (react_1.default.createElement(base_ui_1.Card, { className: "w-full bg-white rounded-lg shadow-sm overflow-hidden mb-4" },
44
48
  react_1.default.createElement(core_1.Accordion, null,
45
49
  react_1.default.createElement(core_1.AccordionSummary, { expandIcon: react_1.default.createElement(base_icons_1.IconChevronDown, null), "aria-controls": "invoice-content", id: "invoice-header" },
@@ -48,11 +52,11 @@ const InvoiceCard = ({ clientInvoice, createDisputeChatMessage, user, chatMessag
48
52
  react_1.default.createElement("div", { className: "p-6 space-y-6 w-full" },
49
53
  react_1.default.createElement(InvoiceDetails_1.InvoiceDetails, { invoice: currentInvoice, isInternal: isInternal, isClient: isClient, reactAppUrl: reactAppUrl, isLateDisputeAllowed: isLateDisputeAllowed }),
50
54
  isInternal ?
51
- react_1.default.createElement(DisputeSection_1.DisputeSection, { dispute: currentInvoice, documentUploadUrl: documentUploadUrl, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, downloadDocumentUrl: downloadDocumentUrl, bucketName: bucketName })
55
+ react_1.default.createElement(DisputeSection_1.DisputeSection, { dispute: currentInvoice, documentUploadUrl: documentUploadUrl, uploadExpertClientFiles: uploadExpertClientFiles, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, downloadDocumentUrl: downloadDocumentUrl, bucketName: bucketName, isInternal: isInternal, hasDisputeAdminRole: hasDisputeAdminRole })
52
56
  :
53
- react_1.default.createElement(ClientDisputeProjectCard_1.ClientDisputeProjectCard, { clientInvoice: currentInvoice, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, documentUploadUrl: documentUploadUrl, downloadDocumentUrl: downloadDocumentUrl, bucketName: bucketName }),
57
+ react_1.default.createElement(ClientDisputeProjectCard_1.ClientDisputeProjectCard, { clientInvoice: currentInvoice, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, documentUploadUrl: documentUploadUrl, downloadDocumentUrl: downloadDocumentUrl, bucketName: bucketName, uploadExpertClientFiles: uploadExpertClientFiles }),
54
58
  (currentInvoice === null || currentInvoice === void 0 ? void 0 : currentInvoice.chatEnabled) && disputeId && (react_1.default.createElement(DiscussionSection_1.DiscussionSection, { disputeId: disputeId, currentUser: user, messages: chatMessages, onCreateMessage: createDisputeChatMessage, isInternal: isInternal })),
55
- isInternal &&
56
- react_1.default.createElement(DecisionSection_1.DecisionSection, { dispute: currentInvoice, onUpdateDispute: updateClientInvoiceDisputeMutation, updateInvoiceMutation: updateInvoiceMutation, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, invoiceSummary: invoiceSummary, user: user, getClientInvoiceSummaryByMonth: getClientInvoiceSummaryByMonth }))))));
59
+ isInternal && hasDisputeAdminRole &&
60
+ react_1.default.createElement(DecisionSection_1.DecisionSection, { dispute: currentInvoice, onUpdateDispute: updateClientInvoiceDisputeMutation, updateInvoiceMutation: updateInvoiceMutation, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, invoiceSummary: invoiceSummary, user: user, getClientInvoiceSummaryByMonth: getClientInvoiceSummaryByMonth, addClientCredit: addClientCredit }))))));
57
61
  };
58
62
  exports.InvoiceCard = InvoiceCard;
@@ -40,9 +40,9 @@ const InvoiceDetails = ({ invoice, isInternal = false, isClient = false, reactAp
40
40
  const internalInvoiceUrl = `${reactAppUrl}/client/${(_d = invoice === null || invoice === void 0 ? void 0 : invoice.invoice) === null || _d === void 0 ? void 0 : _d.clientId}/invoices/${(_e = invoice === null || invoice === void 0 ? void 0 : invoice.invoice) === null || _e === void 0 ? void 0 : _e.id}?month=${(_f = invoice === null || invoice === void 0 ? void 0 : invoice.invoice) === null || _f === void 0 ? void 0 : _f.month}`;
41
41
  const today = (0, dayjs_1.default)();
42
42
  const firstDayOfMonth = (0, dayjs_1.default)().startOf('month');
43
- const disputeDaysLeft = isLateDisputeAllowed ? 14 - today.diff(firstDayOfMonth, 'day') : 7 - today.diff(firstDayOfMonth, 'day');
43
+ const disputeDaysLeft = 14 - today.diff(firstDayOfMonth, 'day');
44
44
  const daysLeft = disputeDaysLeft > 0;
45
- const editableDate = (0, dayjs_1.default)().date(isLateDisputeAllowed ? 14 : 7).format("MMM DD");
45
+ const editableDate = (0, dayjs_1.default)().date(14).format("MMM DD");
46
46
  return (react_1.default.createElement("div", { className: "space-y-6" },
47
47
  react_1.default.createElement("div", { className: "flex items-center space-x-4" },
48
48
  react_1.default.createElement(base_ui_1.Tag, { color: (0, exports.getStatusColor)(invoice === null || invoice === void 0 ? void 0 : invoice.status), label: (0, exports.getStatusText)(invoice === null || invoice === void 0 ? void 0 : invoice.status), borderRadius: "full", variant: "subtle" }),
@@ -33,6 +33,7 @@ export declare const DOCUMENT_TYPE_CONSTANTS: {
33
33
  "Operational and Management Documents": string;
34
34
  "Tax and Compliance Documents": string;
35
35
  "Project Specific Documents": string;
36
+ "Dispute Documents": string;
36
37
  };
37
38
  export declare const titleMappings: Record<string, string>;
38
39
  export declare const features: string[];
@@ -270,7 +270,8 @@ exports.DOCUMENT_TYPE_CONSTANTS = {
270
270
  "Contractual and Legal Documents": "CONTRACTUAL_AND_LEGAL_DOCUMENTS",
271
271
  "Operational and Management Documents": "OPERATIONAL_AND_MANAGEMENT_DOCUMENTS",
272
272
  "Tax and Compliance Documents": "TAX_AND_COMPLIANCE_DOCUMENTS",
273
- "Project Specific Documents": "PROJECT_SPECIFIC_DOCUMENTS"
273
+ "Project Specific Documents": "PROJECT_SPECIFIC_DOCUMENTS",
274
+ "Dispute Documents": "DISPUTE_DOCUMENTS"
274
275
  };
275
276
  exports.titleMappings = {
276
277
  "CFO": "Chief Financial Officer (CFO)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paro.io/expert-shared-components",
3
- "version": "1.12.33",
3
+ "version": "1.12.35",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {