@paro.io/expert-shared-components 1.12.32 → 1.12.33
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.
- package/lib/components/ExpertProfileHeader/ProfileSection.js +9 -0
- package/lib/components/Invoices/DecisionSection.d.ts +1 -2
- package/lib/components/Invoices/DecisionSection.js +25 -56
- package/lib/components/Invoices/InvoiceCard.d.ts +2 -2
- package/lib/components/Invoices/InvoiceCard.js +4 -8
- package/lib/components/Invoices/InvoiceDetails.d.ts +2 -1
- package/lib/components/Invoices/InvoiceDetails.js +3 -3
- package/package.json +1 -1
|
@@ -121,6 +121,15 @@ const ProfileSection = ({ legacyFreelancerId, imageUrl, shouldAllowEditProfile,
|
|
|
121
121
|
" Reviews")))),
|
|
122
122
|
react_1.default.createElement(core_1.Box, { mt: 1, mb: 1 },
|
|
123
123
|
react_1.default.createElement(core_1.Divider, null))),
|
|
124
|
+
react_1.default.createElement(core_1.Box, { ml: 1, display: "flex", justifyContent: "space-between", alignItems: "center", "data-testid": "Matching-Id", style: { marginRight: '10px' } },
|
|
125
|
+
react_1.default.createElement(core_1.Typography, { variant: "body2" }, "Paro Tenure"),
|
|
126
|
+
react_1.default.createElement("b", null, paroTenure.length > 0 ? paroTenure : "N/A")),
|
|
127
|
+
react_1.default.createElement(core_1.Box, { ml: 1, mt: 1, display: "flex", justifyContent: "space-between", alignItems: "center", "data-testid": "Matching-Id", style: { marginRight: '10px' } },
|
|
128
|
+
react_1.default.createElement(core_1.Typography, { variant: "body2" }, isInternal ? 'Hourly Expert Rate' : 'Hourly Rate'),
|
|
129
|
+
react_1.default.createElement("b", null, hourlyRate > 0 ? `$ ${hourlyRate.toLocaleString()}` : "N/A")),
|
|
130
|
+
isInternal && react_1.default.createElement(core_1.Box, { ml: 1, mt: 1, display: "flex", justifyContent: "space-between", alignItems: "center", "data-testid": "Matching-Id", style: { marginRight: '10px' } },
|
|
131
|
+
react_1.default.createElement(core_1.Typography, { variant: "body2" }, "Hourly Client Rate"),
|
|
132
|
+
react_1.default.createElement("b", null, hourlyRate > 0 ? `$ ${(hourlyRate * 2).toLocaleString()}` : "N/A")),
|
|
124
133
|
react_1.default.createElement(core_1.Box, { mt: 2, mb: 1 }),
|
|
125
134
|
(rates === null || rates === void 0 ? void 0 : rates.length) > 0 && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
126
135
|
react_1.default.createElement(core_1.Grid, { item: true, container: true, direction: 'row', justifyContent: 'space-evenly' },
|
|
@@ -6,7 +6,6 @@ interface DecisionSectionProps {
|
|
|
6
6
|
getClientInvoiceSummaryByMonth: any;
|
|
7
7
|
invoiceSummary: any;
|
|
8
8
|
updateClientInvoiceDisputeMutation: any;
|
|
9
|
-
addClientCredit: any;
|
|
10
9
|
}
|
|
11
|
-
export declare const DecisionSection: ({ dispute, onUpdateDispute, updateInvoiceMutation, updateClientInvoiceDisputeMutation, invoiceSummary, user, getClientInvoiceSummaryByMonth,
|
|
10
|
+
export declare const DecisionSection: ({ dispute, onUpdateDispute, updateInvoiceMutation, updateClientInvoiceDisputeMutation, invoiceSummary, user, getClientInvoiceSummaryByMonth, }: DecisionSectionProps) => JSX.Element;
|
|
12
11
|
export {};
|
|
@@ -42,15 +42,14 @@ 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, }) => {
|
|
46
|
+
var _a, _b;
|
|
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;
|
|
54
53
|
// Initialize project approved hours when resolution changes to PARTIAL
|
|
55
54
|
const handleResolutionChange = (newResolution) => {
|
|
56
55
|
var _a;
|
|
@@ -85,6 +84,7 @@ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, upda
|
|
|
85
84
|
const handleApproveClick = () => {
|
|
86
85
|
if (!resolution)
|
|
87
86
|
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,13 +100,19 @@ 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
|
+
}))) || [];
|
|
103
109
|
let calculatedApprovedAmount = 0;
|
|
104
|
-
const fullDisputeAmount = (
|
|
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);
|
|
105
111
|
if (resolution === 'APPROVED') {
|
|
106
112
|
calculatedApprovedAmount = fullDisputeAmount;
|
|
107
113
|
}
|
|
108
114
|
else {
|
|
109
|
-
(
|
|
115
|
+
(_c = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _c === void 0 ? void 0 : _c.forEach((project) => {
|
|
110
116
|
var _a, _b;
|
|
111
117
|
const approvedForProject = projectApprovedHours[project.projectId] || 0;
|
|
112
118
|
if (project.disputeType === 'Hourly') {
|
|
@@ -118,50 +124,6 @@ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, upda
|
|
|
118
124
|
}
|
|
119
125
|
});
|
|
120
126
|
}
|
|
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
|
-
}))) || [];
|
|
165
127
|
const updateData = {
|
|
166
128
|
disputeId: dispute.disputeId,
|
|
167
129
|
status: "Resolved",
|
|
@@ -169,17 +131,24 @@ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, upda
|
|
|
169
131
|
finalDecisionOwnerId: (user === null || user === void 0 ? void 0 : user.userId) || null,
|
|
170
132
|
projectDisputes: disputeProjectUpdates
|
|
171
133
|
};
|
|
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
|
+
}
|
|
172
146
|
yield onUpdateDispute({
|
|
173
147
|
variables: {
|
|
174
148
|
input: updateData,
|
|
175
149
|
},
|
|
176
150
|
});
|
|
177
|
-
|
|
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
|
-
}
|
|
151
|
+
(0, utils_1.showToast)('success', 'Thank you for resolving the dispute. The invoice has been updated with the new hours.');
|
|
183
152
|
}
|
|
184
153
|
catch (error) {
|
|
185
154
|
console.error('Failed to update dispute:', error);
|
|
@@ -189,7 +158,7 @@ const DecisionSection = ({ dispute, onUpdateDispute, updateInvoiceMutation, upda
|
|
|
189
158
|
setIsSubmitting(false);
|
|
190
159
|
}
|
|
191
160
|
});
|
|
192
|
-
const isPartialWithMultipleProjects = resolution === 'PARTIAL' && ((
|
|
161
|
+
const isPartialWithMultipleProjects = resolution === 'PARTIAL' && ((_b = dispute === null || dispute === void 0 ? void 0 : dispute.disputeProjects) === null || _b === void 0 ? void 0 : _b.length) > 0;
|
|
193
162
|
const isValidPartialApproval = () => {
|
|
194
163
|
if (resolution !== 'PARTIAL')
|
|
195
164
|
return true;
|
|
@@ -13,7 +13,7 @@ interface InvoiceCardProps {
|
|
|
13
13
|
isClient?: boolean;
|
|
14
14
|
bucketName?: string;
|
|
15
15
|
reactAppUrl?: string;
|
|
16
|
-
|
|
16
|
+
isLateDisputeAllowed?: boolean;
|
|
17
17
|
}
|
|
18
|
-
export declare const InvoiceCard: ({ clientInvoice, createDisputeChatMessage, user, chatMessages, updateClientInvoiceDisputeMutation, updateInvoiceMutation, getClientInvoiceSummaryByMonth, invoiceSummary, documentUploadUrl, downloadDocumentUrl, isInternal, isClient, bucketName, reactAppUrl,
|
|
18
|
+
export declare const InvoiceCard: ({ clientInvoice, createDisputeChatMessage, user, chatMessages, updateClientInvoiceDisputeMutation, updateInvoiceMutation, getClientInvoiceSummaryByMonth, invoiceSummary, documentUploadUrl, downloadDocumentUrl, isInternal, isClient, bucketName, reactAppUrl, isLateDisputeAllowed, }: InvoiceCardProps) => JSX.Element;
|
|
19
19
|
export {};
|
|
@@ -34,29 +34,25 @@ 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,
|
|
38
|
-
var _a;
|
|
39
|
-
const envUrl = reactAppUrl === null || reactAppUrl === void 0 ? void 0 : reactAppUrl.split('.')[1];
|
|
40
|
-
const rolesUrl = `https://app.${envUrl}.io/roles`;
|
|
37
|
+
const InvoiceCard = ({ clientInvoice, createDisputeChatMessage, user, chatMessages, updateClientInvoiceDisputeMutation, updateInvoiceMutation, getClientInvoiceSummaryByMonth, invoiceSummary, documentUploadUrl, downloadDocumentUrl, isInternal = false, isClient = false, bucketName, reactAppUrl, isLateDisputeAllowed = false, }) => {
|
|
41
38
|
const [currentInvoice, setCurrentInvoice] = (0, react_1.useState)(clientInvoice);
|
|
42
39
|
(0, react_1.useEffect)(() => {
|
|
43
40
|
setCurrentInvoice(clientInvoice);
|
|
44
41
|
}, [clientInvoice]);
|
|
45
42
|
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');
|
|
47
43
|
return (react_1.default.createElement(base_ui_1.Card, { className: "w-full bg-white rounded-lg shadow-sm overflow-hidden mb-4" },
|
|
48
44
|
react_1.default.createElement(core_1.Accordion, null,
|
|
49
45
|
react_1.default.createElement(core_1.AccordionSummary, { expandIcon: react_1.default.createElement(base_icons_1.IconChevronDown, null), "aria-controls": "invoice-content", id: "invoice-header" },
|
|
50
46
|
react_1.default.createElement(InvoiceHeader_1.InvoiceHeader, { invoice: currentInvoice, isInternal: isInternal, isClient: isClient })),
|
|
51
47
|
react_1.default.createElement(core_1.AccordionDetails, null,
|
|
52
48
|
react_1.default.createElement("div", { className: "p-6 space-y-6 w-full" },
|
|
53
|
-
react_1.default.createElement(InvoiceDetails_1.InvoiceDetails, { invoice: currentInvoice, isInternal: isInternal, isClient: isClient, reactAppUrl: reactAppUrl }),
|
|
49
|
+
react_1.default.createElement(InvoiceDetails_1.InvoiceDetails, { invoice: currentInvoice, isInternal: isInternal, isClient: isClient, reactAppUrl: reactAppUrl, isLateDisputeAllowed: isLateDisputeAllowed }),
|
|
54
50
|
isInternal ?
|
|
55
51
|
react_1.default.createElement(DisputeSection_1.DisputeSection, { dispute: currentInvoice, documentUploadUrl: documentUploadUrl, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, downloadDocumentUrl: downloadDocumentUrl, bucketName: bucketName })
|
|
56
52
|
:
|
|
57
53
|
react_1.default.createElement(ClientDisputeProjectCard_1.ClientDisputeProjectCard, { clientInvoice: currentInvoice, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, documentUploadUrl: documentUploadUrl, downloadDocumentUrl: downloadDocumentUrl, bucketName: bucketName }),
|
|
58
54
|
(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 })),
|
|
59
|
-
isInternal &&
|
|
60
|
-
react_1.default.createElement(DecisionSection_1.DecisionSection, { dispute: currentInvoice, onUpdateDispute: updateClientInvoiceDisputeMutation, updateInvoiceMutation: updateInvoiceMutation, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, invoiceSummary: invoiceSummary, user: user, getClientInvoiceSummaryByMonth: getClientInvoiceSummaryByMonth
|
|
55
|
+
isInternal &&
|
|
56
|
+
react_1.default.createElement(DecisionSection_1.DecisionSection, { dispute: currentInvoice, onUpdateDispute: updateClientInvoiceDisputeMutation, updateInvoiceMutation: updateInvoiceMutation, updateClientInvoiceDisputeMutation: updateClientInvoiceDisputeMutation, invoiceSummary: invoiceSummary, user: user, getClientInvoiceSummaryByMonth: getClientInvoiceSummaryByMonth }))))));
|
|
61
57
|
};
|
|
62
58
|
exports.InvoiceCard = InvoiceCard;
|
|
@@ -3,8 +3,9 @@ interface InvoiceDetailsProps {
|
|
|
3
3
|
isInternal: boolean;
|
|
4
4
|
isClient: boolean;
|
|
5
5
|
reactAppUrl?: string;
|
|
6
|
+
isLateDisputeAllowed?: boolean;
|
|
6
7
|
}
|
|
7
8
|
export declare const getStatusColor: (status: string) => "success" | "primary" | "info" | "warning";
|
|
8
9
|
export declare const getStatusText: (status: string) => "" | "Resolved" | "In Progress" | "Under Review";
|
|
9
|
-
export declare const InvoiceDetails: ({ invoice, isInternal, isClient, reactAppUrl }: InvoiceDetailsProps) => JSX.Element;
|
|
10
|
+
export declare const InvoiceDetails: ({ invoice, isInternal, isClient, reactAppUrl, isLateDisputeAllowed }: InvoiceDetailsProps) => JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -34,15 +34,15 @@ const getStatusText = (status) => {
|
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
36
|
exports.getStatusText = getStatusText;
|
|
37
|
-
const InvoiceDetails = ({ invoice, isInternal = false, isClient = false, reactAppUrl = 'https://internal.parodev.io' }) => {
|
|
37
|
+
const InvoiceDetails = ({ invoice, isInternal = false, isClient = false, reactAppUrl = 'https://internal.parodev.io', isLateDisputeAllowed = false }) => {
|
|
38
38
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
39
39
|
const clientInvoiceUrl = `${reactAppUrl}/invoices/${(_a = invoice === null || invoice === void 0 ? void 0 : invoice.invoice) === null || _a === void 0 ? void 0 : _a.id}?month=${(_b = invoice === null || invoice === void 0 ? void 0 : invoice.invoice) === null || _b === void 0 ? void 0 : _b.month}&companyId=${(_c = invoice === null || invoice === void 0 ? void 0 : invoice.invoice) === null || _c === void 0 ? void 0 : _c.clientId}`;
|
|
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 = 14 - today.diff(firstDayOfMonth, 'day');
|
|
43
|
+
const disputeDaysLeft = isLateDisputeAllowed ? 14 - today.diff(firstDayOfMonth, 'day') : 7 - today.diff(firstDayOfMonth, 'day');
|
|
44
44
|
const daysLeft = disputeDaysLeft > 0;
|
|
45
|
-
const editableDate = (0, dayjs_1.default)().date(14).format("MMM DD");
|
|
45
|
+
const editableDate = (0, dayjs_1.default)().date(isLateDisputeAllowed ? 14 : 7).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" }),
|