@paro.io/expert-shared-components 1.13.1 → 1.13.3
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/Escalations/EscalationChat.d.ts +2 -2
- package/lib/components/Escalations/EscalationChat.js +7 -10
- package/lib/components/Escalations/EscalationIssueCard.js +44 -18
- package/lib/components/Escalations/EscalationRespondForm.js +5 -9
- package/lib/components/Escalations/EscalationSubmitForm.js +3 -3
- package/lib/components/Escalations/EscalationTabsContent.js +2 -1
- package/lib/components/Escalations/Escalations.js +10 -6
- package/lib/components/Escalations/MarkResolvedModal.js +2 -2
- package/lib/components/Escalations/ViewResponseModal.d.ts +2 -2
- package/lib/components/Escalations/ViewResponseModal.js +12 -2
- package/lib/components/Invoices/DiscussionSection.js +28 -22
- package/lib/components/shared/utils.d.ts +1 -0
- package/lib/components/shared/utils.js +10 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
declare const EscalationChat: ({ activeChatIssue, showEscalationChat,
|
|
1
|
+
declare const EscalationChat: ({ activeChatIssue, showEscalationChat, onClose, user, createEscalationChatMessage, documentUploadUrl, bucketName, uploadExpertClientFiles, updateProjectEscalation, isExpert, }: {
|
|
2
2
|
activeChatIssue: any;
|
|
3
3
|
showEscalationChat: boolean;
|
|
4
|
-
|
|
4
|
+
onClose: () => void;
|
|
5
5
|
user: any;
|
|
6
6
|
createEscalationChatMessage: any;
|
|
7
7
|
documentUploadUrl: string;
|
|
@@ -40,7 +40,8 @@ const DiscussionSection_1 = require("../Invoices/DiscussionSection");
|
|
|
40
40
|
const EscalationIssueCard_1 = require("./EscalationIssueCard");
|
|
41
41
|
const FileUploader_1 = require("../FileUploader");
|
|
42
42
|
const EscalationRespondForm_1 = require("./EscalationRespondForm");
|
|
43
|
-
const
|
|
43
|
+
const utils_1 = require("../shared/utils");
|
|
44
|
+
const EscalationChat = ({ activeChatIssue, showEscalationChat, onClose, user, createEscalationChatMessage, documentUploadUrl, bucketName, uploadExpertClientFiles, updateProjectEscalation, isExpert, }) => {
|
|
44
45
|
var _a, _b, _c, _d;
|
|
45
46
|
const [uploadFiles, setUploadFiles] = (0, react_1.useState)(isExpert
|
|
46
47
|
? (((_a = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.expertSupportingDocuments) === null || _a === void 0 ? void 0 : _a.split(",")) || [])
|
|
@@ -108,15 +109,11 @@ const EscalationChat = ({ activeChatIssue, showEscalationChat, setShowEscalation
|
|
|
108
109
|
}
|
|
109
110
|
});
|
|
110
111
|
const docs = [activeChatIssue.expertSupportingDocuments, activeChatIssue.clientSupportingDocuments, activeChatIssue.internalSupportingDocuments, ...uploadFiles];
|
|
111
|
-
const processedDocs = docs
|
|
112
|
-
.filter(doc => doc !== null && doc !== undefined && doc !== '' && doc !== "NULL")
|
|
113
|
-
.flatMap(doc => doc.split(','))
|
|
114
|
-
.map(doc => doc.trim())
|
|
115
|
-
.filter(doc => doc !== '' || doc !== "NULL");
|
|
112
|
+
const processedDocs = (0, utils_1.processDocs)(docs);
|
|
116
113
|
const project = activeChatIssue.projectDetails && Array.isArray(activeChatIssue.projectDetails) && activeChatIssue.projectDetails.length > 0
|
|
117
114
|
? `${(_c = activeChatIssue.projectDetails[0]) === null || _c === void 0 ? void 0 : _c.projectName}${activeChatIssue.projectDetails.length > 1 ? ` +${activeChatIssue.projectDetails.length - 1} more` : ''} `
|
|
118
115
|
: '';
|
|
119
|
-
return (react_1.default.createElement(core_1.Dialog, { open: showEscalationChat, onClose:
|
|
116
|
+
return (react_1.default.createElement(core_1.Dialog, { open: showEscalationChat, onClose: onClose, maxWidth: 'sm' },
|
|
120
117
|
react_1.default.createElement(core_1.DialogTitle, null,
|
|
121
118
|
react_1.default.createElement("div", { className: "text-black bg-white mb-1 p-2 pl-4 absolute top-0 left-0 w-full flex flex-row justify-between items-center z-50" },
|
|
122
119
|
react_1.default.createElement("div", { className: "flex flex-col items-start" },
|
|
@@ -130,14 +127,14 @@ const EscalationChat = ({ activeChatIssue, showEscalationChat, setShowEscalation
|
|
|
130
127
|
" \u2022 ",
|
|
131
128
|
project)),
|
|
132
129
|
react_1.default.createElement("div", { className: "flex items-center space-x-4" },
|
|
133
|
-
react_1.default.createElement(core_1.IconButton, { onClick:
|
|
130
|
+
react_1.default.createElement(core_1.IconButton, { onClick: onClose },
|
|
134
131
|
react_1.default.createElement(base_icons_1.IconX, null))))),
|
|
135
132
|
react_1.default.createElement(core_1.DialogContent, null,
|
|
136
133
|
react_1.default.createElement("div", { className: "bg-white rounded-lg w-full overflow-hidden flex flex-col p-2 mt-12" },
|
|
137
134
|
react_1.default.createElement(DiscussionSection_1.DiscussionSection, { escalationNumber: activeChatIssue.escalationNumber, currentUser: user, messages: (_d = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.chatMessages) !== null && _d !== void 0 ? _d : [], onCreateMessage: createEscalationChatMessage, isInternal: false }),
|
|
138
135
|
processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2 mt-4 mb-2" },
|
|
139
136
|
react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
|
|
140
|
-
processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1], customColor:
|
|
137
|
+
processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1], customColor: `bg-success border-success` }))))),
|
|
141
138
|
react_1.default.createElement("div", { className: "bg-white mt-2" },
|
|
142
139
|
react_1.default.createElement("div", { className: "space-y-3" },
|
|
143
140
|
react_1.default.createElement("div", { className: "flex items-center justify-between" },
|
|
@@ -145,6 +142,6 @@ const EscalationChat = ({ activeChatIssue, showEscalationChat, setShowEscalation
|
|
|
145
142
|
react_1.default.createElement("input", { id: "upload-file", type: "file", multiple: false, accept: ".pdf,.doc,.docx,.jpeg,.png,.gif,.csv,.xslx", style: { display: 'none' }, ref: fileInputRef, onChange: handleFileUpload }),
|
|
146
143
|
react_1.default.createElement(base_ui_1.Button, { label: "Attach Files", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: "sm" }), onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, color: "info", className: "mx-2", isLoading: uploadingFile })),
|
|
147
144
|
react_1.default.createElement("div", { className: "flex space-x-2" },
|
|
148
|
-
react_1.default.createElement(base_ui_1.Button, { label: "cancel", onClick:
|
|
145
|
+
react_1.default.createElement(base_ui_1.Button, { label: "cancel", onClick: onClose, disabled: uploadingFile })))))))));
|
|
149
146
|
};
|
|
150
147
|
exports.default = EscalationChat;
|
|
@@ -34,6 +34,7 @@ const base_icons_1 = require("@paro.io/base-icons");
|
|
|
34
34
|
const dayjs_1 = __importDefault(require("dayjs"));
|
|
35
35
|
const ViewResponseModal_1 = __importDefault(require("./ViewResponseModal"));
|
|
36
36
|
const MarkResolvedModal_1 = __importDefault(require("./MarkResolvedModal"));
|
|
37
|
+
const utils_1 = require("../shared/utils");
|
|
37
38
|
const getBackgroundColor = (type) => {
|
|
38
39
|
switch (type) {
|
|
39
40
|
case 'Critical':
|
|
@@ -49,8 +50,9 @@ const getBackgroundColor = (type) => {
|
|
|
49
50
|
}
|
|
50
51
|
};
|
|
51
52
|
const CustomTag = ({ label, iconLeft, onClick, customColor, }) => {
|
|
52
|
-
const
|
|
53
|
-
|
|
53
|
+
const getColor = getBackgroundColor(label);
|
|
54
|
+
const color = customColor ? customColor : `bg-${getColor} border-${getColor}`;
|
|
55
|
+
return (react_1.default.createElement("div", { onClick: onClick, className: `flex flex-row gap-1 border box-border text-center px-4 pb-0.5 pt-1 text-sm inline-block break-words text-white rounded-full ${color} ml-2 font-medium ${onClick ? 'cursor-pointer' : ''}` },
|
|
54
56
|
iconLeft && react_1.default.createElement("span", null, iconLeft), label === null || label === void 0 ? void 0 :
|
|
55
57
|
label.toUpperCase()));
|
|
56
58
|
};
|
|
@@ -60,23 +62,44 @@ const EscalationIssueCard = ({ issues, isExpert, openEscalationChat, showRespond
|
|
|
60
62
|
const [viewResponseModal, setViewResponseModal] = (0, react_1.useState)(null);
|
|
61
63
|
const [markAsResolved, setMarkAsResolved] = (0, react_1.useState)(null);
|
|
62
64
|
const getResponseButtonText = (issue) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
var _a;
|
|
66
|
+
const userTypeId = (_a = issue === null || issue === void 0 ? void 0 : issue.submittedByUser) === null || _a === void 0 ? void 0 : _a.userTypeId;
|
|
67
|
+
if (userTypeId === 3) { // Submitted by Client
|
|
68
|
+
if (isExpert) {
|
|
69
|
+
return "View Response";
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
return issue.expertResponse ? "View Response" : "Awaiting Response";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (userTypeId === 1) { // Submitted by Expert
|
|
76
|
+
if (isExpert) {
|
|
77
|
+
return issue.clientResponse ? "View Response" : "Awaiting Response";
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return "View Response";
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (userTypeId === 2) { // Submitted by Paro internal
|
|
84
|
+
if (isExpert) {
|
|
85
|
+
return issue.clientResponse ? "View Response" : "Awaiting Response";
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
return issue.expertResponse ? "View Response" : "Awaiting Response";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return "Awaiting Response";
|
|
65
92
|
};
|
|
66
93
|
if (!issues.length)
|
|
67
94
|
return react_1.default.createElement("div", null, "No issues.");
|
|
68
95
|
return (react_1.default.createElement("div", { className: "space-y-4" },
|
|
69
96
|
issues.map((issue) => {
|
|
70
|
-
var _a;
|
|
97
|
+
var _a, _b, _c, _d, _e;
|
|
71
98
|
const project = issue.projectDetails && Array.isArray(issue.projectDetails) && issue.projectDetails.length > 0
|
|
72
99
|
? `${(_a = issue.projectDetails[0]) === null || _a === void 0 ? void 0 : _a.projectName}${issue.projectDetails.length > 1 ? ` +${issue.projectDetails.length - 1} more` : ''} `
|
|
73
100
|
: '';
|
|
74
101
|
const docs = [issue.expertSupportingDocuments, issue.clientSupportingDocuments, issue.internalSupportingDocuments];
|
|
75
|
-
const processedDocs = docs
|
|
76
|
-
.filter(doc => doc !== null && doc !== undefined && doc !== '' && doc !== "NULL")
|
|
77
|
-
.flatMap(doc => doc.split(','))
|
|
78
|
-
.map(doc => doc.trim())
|
|
79
|
-
.filter(doc => doc !== '' || doc !== "NULL");
|
|
102
|
+
const processedDocs = (0, utils_1.processDocs)(docs);
|
|
80
103
|
return (react_1.default.createElement("div", { key: issue.id, className: "border border-gray-200 rounded-lg bg-white p-4" },
|
|
81
104
|
react_1.default.createElement("div", { className: "flex items-center justify-between mb-3" },
|
|
82
105
|
react_1.default.createElement("div", { className: "flex-1 ml-2" },
|
|
@@ -84,31 +107,34 @@ const EscalationIssueCard = ({ issues, isExpert, openEscalationChat, showRespond
|
|
|
84
107
|
react_1.default.createElement("div", { className: "font-bold" }, issue.problem),
|
|
85
108
|
react_1.default.createElement(exports.CustomTag, { label: issue.severityLevel })),
|
|
86
109
|
react_1.default.createElement("div", { className: "text-xs text-gray-500 font-bold" },
|
|
110
|
+
isExpert ? (_b = issue === null || issue === void 0 ? void 0 : issue.client) === null || _b === void 0 ? void 0 : _b.name : (_c = issue === null || issue === void 0 ? void 0 : issue.freelancer) === null || _c === void 0 ? void 0 : _c.name,
|
|
111
|
+
" \u2022 ",
|
|
87
112
|
project,
|
|
88
113
|
" \u2022 Case #",
|
|
89
114
|
issue.escalationNumber)),
|
|
90
|
-
react_1.default.createElement(exports.CustomTag, { label: issue.escalationType, customColor:
|
|
115
|
+
react_1.default.createElement(exports.CustomTag, { label: issue.escalationType, customColor: `bg-[#B0B5D3] border-[#181027]` })),
|
|
91
116
|
react_1.default.createElement("div", { className: "bg-gray-50 rounded-md p-3 mb-4 border" },
|
|
92
117
|
react_1.default.createElement("div", { className: "flex items-center justify-between mb-2" },
|
|
93
118
|
react_1.default.createElement("div", { className: "text-sm text-gray-500" },
|
|
94
119
|
"Submitted by: ",
|
|
95
|
-
react_1.default.createElement("span", { className: "font-bold" }, issue.submittedByUser.firstName + " " + issue.submittedByUser.lastName),
|
|
96
|
-
issue.createdAt && react_1.default.createElement(react_1.default.Fragment, null,
|
|
120
|
+
react_1.default.createElement("span", { className: "font-bold" }, ((_d = issue === null || issue === void 0 ? void 0 : issue.submittedByUser) === null || _d === void 0 ? void 0 : _d.firstName) + " " + ((_e = issue === null || issue === void 0 ? void 0 : issue.submittedByUser) === null || _e === void 0 ? void 0 : _e.lastName)),
|
|
121
|
+
(issue === null || issue === void 0 ? void 0 : issue.createdAt) && react_1.default.createElement(react_1.default.Fragment, null,
|
|
97
122
|
" \u2022 Submitted on: ",
|
|
98
|
-
react_1.default.createElement("span", { className: "font-bold" }, (0, dayjs_1.default)(issue.createdAt).format("MM-DD-YYYY"))))),
|
|
123
|
+
react_1.default.createElement("span", { className: "font-bold" }, (0, dayjs_1.default)(issue === null || issue === void 0 ? void 0 : issue.createdAt).format("MM-DD-YYYY"))))),
|
|
99
124
|
react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-3" }, issue.outcome),
|
|
100
125
|
processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2" },
|
|
101
126
|
react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
|
|
102
|
-
processedDocs.map((d, idx) => (react_1.default.createElement(exports.CustomTag, { key: idx, customColor:
|
|
127
|
+
processedDocs.map((d, idx) => (react_1.default.createElement(exports.CustomTag, { key: idx, customColor: `bg-success border-success`, label: d.split('%2F')[1], iconLeft: react_1.default.createElement(base_icons_1.IconDocumentDownload, { size: "xs" }), onClick: () => {
|
|
103
128
|
(0, ClientDisputeProjectCard_1.handleDownloadDocument)(issue.escalationId, d.split('%2F')[1], downloadDocumentUrl, bucketName);
|
|
104
129
|
} })))))),
|
|
105
130
|
react_1.default.createElement("div", { className: "flex flex-wrap gap-2" },
|
|
106
|
-
react_1.default.createElement(base_ui_1.Button, { onClick: () => openEscalationChat(issue), label: "Chat", color: "primary" }),
|
|
131
|
+
react_1.default.createElement(base_ui_1.Button, { onClick: () => openEscalationChat(issue.escalationNumber), label: "Chat", color: "primary" }),
|
|
107
132
|
showRespondButton && setSelectedIssueId && (react_1.default.createElement(base_ui_1.Button, { label: "Respond to Escalation", onClick: () => setSelectedIssueId(issue.escalationNumber), color: 'primary' })),
|
|
108
133
|
showMarkResolvedButton && (react_1.default.createElement(base_ui_1.Button, { label: getResponseButtonText(issue), onClick: () => { setViewResponseModal(issue); }, color: 'primary', disabled: getResponseButtonText(issue) === 'Awaiting Response' })),
|
|
109
|
-
showMarkResolvedButton && !isExpert &&
|
|
134
|
+
showMarkResolvedButton && !isExpert && issue.submittedByUser.userTypeId === 3 && ( // only client can resolve issue raised by client
|
|
135
|
+
react_1.default.createElement(base_ui_1.Button, { onClick: () => { setMarkAsResolved(issue); }, label: "Mark as Resolved", color: "primary" })))));
|
|
110
136
|
}),
|
|
111
|
-
!!viewResponseModal && react_1.default.createElement(ViewResponseModal_1.default, {
|
|
137
|
+
!!viewResponseModal && react_1.default.createElement(ViewResponseModal_1.default, { selectedIssue: viewResponseModal, isExpert: isExpert, open: !!viewResponseModal, onClose: () => setViewResponseModal(null) }),
|
|
112
138
|
!!markAsResolved && react_1.default.createElement(MarkResolvedModal_1.default, { escalationId: markAsResolved.escalationId, expertName: (_b = (_a = markAsResolved === null || markAsResolved === void 0 ? void 0 : markAsResolved.freelancer) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'Expert', open: !!markAsResolved, onClose: () => setMarkAsResolved(false), updateProjectEscalation: updateProjectEscalation, userId: userId })));
|
|
113
139
|
};
|
|
114
140
|
exports.default = EscalationIssueCard;
|
|
@@ -158,7 +158,7 @@ const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downl
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
});
|
|
161
|
-
(0, utils_1.showToast)("success", "Response submitted!");
|
|
161
|
+
(0, utils_1.showToast)("success", "Response submitted! The issue has been moved to in-progress.");
|
|
162
162
|
}
|
|
163
163
|
catch (error) {
|
|
164
164
|
console.error("Failed to send response!", error);
|
|
@@ -170,11 +170,7 @@ const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downl
|
|
|
170
170
|
}
|
|
171
171
|
});
|
|
172
172
|
const docs = [selectedIssue.expertSupportingDocuments, selectedIssue.clientSupportingDocuments, selectedIssue.internalSupportingDocuments, ...uploadFiles];
|
|
173
|
-
const processedDocs = docs
|
|
174
|
-
.filter(doc => doc !== null && doc !== undefined && doc !== '')
|
|
175
|
-
.flatMap(doc => doc.split(','))
|
|
176
|
-
.map(doc => doc.trim())
|
|
177
|
-
.filter(doc => doc !== '');
|
|
173
|
+
const processedDocs = (0, utils_1.processDocs)(docs);
|
|
178
174
|
return (react_1.default.createElement("div", null,
|
|
179
175
|
react_1.default.createElement("button", { onClick: goBack, className: "flex items-center text-blue-600 mb-6" },
|
|
180
176
|
react_1.default.createElement(base_icons_1.IconChevronLeft, { size: "xs" }),
|
|
@@ -203,7 +199,7 @@ const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downl
|
|
|
203
199
|
: "text-gray-500 text-xs mt-1" }, type.description))))))),
|
|
204
200
|
react_1.default.createElement("div", null,
|
|
205
201
|
react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" }, "Your Response"),
|
|
206
|
-
react_1.default.createElement(base_ui_1.Input, { type: "text", value: responseInput, placeholder: "Address the concern...", onChange: (e) => setResponseInput(e.target.value) })),
|
|
202
|
+
react_1.default.createElement(base_ui_1.Input, { type: "text", value: responseInput, placeholder: "Address the concern...", isRequired: true, onChange: (e) => setResponseInput(e.target.value) })),
|
|
207
203
|
react_1.default.createElement("div", null,
|
|
208
204
|
react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" }, "Supporting Documents (Optional)"),
|
|
209
205
|
react_1.default.createElement("div", { className: "border border-dashed border-gray-300 rounded-md p-6 text-center" },
|
|
@@ -212,7 +208,7 @@ const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downl
|
|
|
212
208
|
react_1.default.createElement(base_ui_1.Button, { label: "Attach Files", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: "sm" }), onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, color: "info", className: "mx-2", isLoading: uploadingFile, size: "sm" }),
|
|
213
209
|
processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2 mt-4" },
|
|
214
210
|
react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
|
|
215
|
-
processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1], customColor:
|
|
211
|
+
processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1], customColor: `bg-success border-success` }))))))),
|
|
216
212
|
react_1.default.createElement("div", { className: "bg-blue-50 border border-blue-200 rounded-md p-3" },
|
|
217
213
|
react_1.default.createElement("div", { className: "flex items-center" },
|
|
218
214
|
react_1.default.createElement(base_icons_1.IconInfoCircle, { size: "md" }),
|
|
@@ -221,6 +217,6 @@ const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downl
|
|
|
221
217
|
react_1.default.createElement("p", { className: "mt-1" }, "Your response will be visible to the client and Paro support team. Be professional and focus on resolution.")))),
|
|
222
218
|
react_1.default.createElement("div", { className: "flex justify-end space-x-3" },
|
|
223
219
|
react_1.default.createElement(base_ui_1.Button, { label: "Cancel", onClick: goBack, disabled: uploadingFile || submitting }),
|
|
224
|
-
react_1.default.createElement(base_ui_1.Button, { label: "Submit Response", color: "primary", onClick: submitResponse, isLoading: submitting, disabled: uploadingFile })))))));
|
|
220
|
+
react_1.default.createElement(base_ui_1.Button, { label: "Submit Response", color: "primary", onClick: submitResponse, isLoading: submitting, disabled: uploadingFile || responseInput === '' })))))));
|
|
225
221
|
};
|
|
226
222
|
exports.default = EscalationRespondForm;
|
|
@@ -193,11 +193,11 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
|
|
|
193
193
|
input: formData
|
|
194
194
|
}
|
|
195
195
|
});
|
|
196
|
-
(0, utils_1.showToast)("success", "
|
|
196
|
+
(0, utils_1.showToast)("success", "Issue created successfully!");
|
|
197
197
|
}
|
|
198
198
|
catch (error) {
|
|
199
|
-
console.error("Failed to create an
|
|
200
|
-
(0, utils_1.showToast)("warning", "Failed to create
|
|
199
|
+
console.error("Failed to create an issue!", error);
|
|
200
|
+
(0, utils_1.showToast)("warning", "Failed to create an issue!");
|
|
201
201
|
}
|
|
202
202
|
finally {
|
|
203
203
|
setSubmitting(false);
|
|
@@ -77,7 +77,8 @@ const EscalationTabsContent = ({ activeTab, openEscalationChat, setSelectedIssue
|
|
|
77
77
|
react_1.default.createElement("span", { className: "text-xs text-gray-500" },
|
|
78
78
|
"Resolved By ",
|
|
79
79
|
issue.statusChangedByUser.firstName + " " + issue.statusChangedByUser.lastName)))),
|
|
80
|
-
|
|
80
|
+
issue.status === 'Resolved' && (0, dayjs_1.default)().diff((0, dayjs_1.default)(issue.updatedAt), 'day') <= 30 &&
|
|
81
|
+
react_1.default.createElement(base_ui_1.Button, { onClick: () => openEscalationChat(issue.escalationNumber), label: "Chat", color: "primary" }))));
|
|
81
82
|
}))
|
|
82
83
|
:
|
|
83
84
|
react_1.default.createElement("div", null, "No resolved issues.")));
|
|
@@ -45,7 +45,7 @@ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations
|
|
|
45
45
|
const [selectedProject, setSelectedProject] = (0, react_1.useState)(null);
|
|
46
46
|
const [selectedIssueId, setSelectedIssueId] = (0, react_1.useState)(null); // using selectedIssueId 0 for new escalation submission
|
|
47
47
|
const [showEscalationChat, setShowEscalationChat] = (0, react_1.useState)(false);
|
|
48
|
-
const [
|
|
48
|
+
const [activeChatEscalationNumber, setActiveChatEscalationNumber] = (0, react_1.useState)(null);
|
|
49
49
|
const [activeEscalationTab, setActiveEscalationTab] = (0, react_1.useState)('action-required');
|
|
50
50
|
const [showSuspensionModal, setShowSuspensionModal] = (0, react_1.useState)(false);
|
|
51
51
|
const activeIssues = escalations.filter(issue => {
|
|
@@ -79,15 +79,16 @@ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations
|
|
|
79
79
|
setSelectedProject(null);
|
|
80
80
|
setActiveSection('support');
|
|
81
81
|
};
|
|
82
|
-
const openEscalationChat = (
|
|
83
|
-
|
|
82
|
+
const openEscalationChat = (escalationNumber) => {
|
|
83
|
+
setActiveChatEscalationNumber(escalationNumber);
|
|
84
84
|
setShowEscalationChat(true);
|
|
85
85
|
};
|
|
86
|
+
const activeChatIssue = escalations.find((issue) => issue.escalationNumber === activeChatEscalationNumber);
|
|
86
87
|
return (react_1.default.createElement("div", { className: "bg-white w-full" },
|
|
87
88
|
react_1.default.createElement("div", { className: isExpert ? "p-6" : "mx-auto p-6 border-solid border-t-2" },
|
|
88
89
|
activeSection === 'support' && selectedIssueId === null && react_1.default.createElement("div", null,
|
|
89
90
|
react_1.default.createElement("div", { className: "flex justify-between items-center mb-1 mt-2" },
|
|
90
|
-
react_1.default.createElement("h2", { className: "text-xl font-bold" }, "Support &
|
|
91
|
+
react_1.default.createElement("h2", { className: "text-xl font-bold" }, "Support & Engagement Management"),
|
|
91
92
|
activeIssues.length > 0 ? react_1.default.createElement("div", { className: "flex items-center space-x-2" },
|
|
92
93
|
react_1.default.createElement("div", { className: `border box-border text-center px-4 pb-0.5 pt-1 text-sm inline-block break-words text-[#A73A43] rounded-full bg-[#F9BABF] border-[#F9BABF] font-medium` },
|
|
93
94
|
activeIssues.length,
|
|
@@ -95,7 +96,7 @@ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations
|
|
|
95
96
|
react_1.default.createElement("div", { className: "border-b pb-4 mb-6" },
|
|
96
97
|
react_1.default.createElement("p", { className: "text-gray-600" }, `Manage escalations with integrated chat between you, your ${isExpert ? 'client' : 'expert'}, and Paro support. All conversations are organized by priority and status.`)),
|
|
97
98
|
react_1.default.createElement("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6" },
|
|
98
|
-
react_1.default.createElement("h3", { className: "font-medium text-blue-800 mb-3" }, "How Our
|
|
99
|
+
react_1.default.createElement("h3", { className: "font-medium text-blue-800 mb-3" }, "How Our Engagement Support System Works"),
|
|
99
100
|
react_1.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6" },
|
|
100
101
|
react_1.default.createElement("div", null,
|
|
101
102
|
react_1.default.createElement("h4", { className: "font-medium text-gray-900 mb-2" }, "Standard Resolution Process"),
|
|
@@ -155,7 +156,10 @@ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations
|
|
|
155
156
|
react_1.default.createElement(EscalationTabsContent_1.default, { activeTab: activeEscalationTab, openEscalationChat: openEscalationChat, setSelectedIssueId: setSelectedIssueId, activeIssues: activeIssues, inProgressIssues: inProgressIssues, resolvedIssues: resolvedIssues, updateProjectEscalation: updateProjectEscalation, isExpert: isExpert, downloadDocumentUrl: downloadDocumentUrl, bucketName: bucketName, userId: user.userId })),
|
|
156
157
|
activeSection === 'support' && activeIssues.filter((issue) => issue.escalationNumber === selectedIssueId).length > 0 && (react_1.default.createElement(EscalationRespondForm_1.default, { goBack: goBack, selectedIssue: activeIssues.find((issue) => issue.escalationNumber === selectedIssueId), documentUploadUrl: documentUploadUrl, downloadDocumentUrl: downloadDocumentUrl, bucketName: bucketName, uploadExpertClientFiles: uploadExpertClientFiles, updateProjectEscalation: updateProjectEscalation, goHome: goHome, isExpert: isExpert, userId: user.userId })),
|
|
157
158
|
activeSection === 'support' && selectedIssueId === 0 && (react_1.default.createElement(EscalationSubmitForm_1.default, { goBack: goBack, goHome: goHome, expertsOrClients: expertsOrClients, projects: projects, documentUploadUrl: documentUploadUrl, bucketName: bucketName, uploadExpertClientFiles: uploadExpertClientFiles, createProjectEscalation: createProjectEscalation, isExpert: isExpert, user: user, clientId: clientId })),
|
|
158
|
-
showEscalationChat && activeChatIssue && (react_1.default.createElement(EscalationChat_1.default, { activeChatIssue: activeChatIssue, showEscalationChat: showEscalationChat,
|
|
159
|
+
showEscalationChat && activeChatIssue && (react_1.default.createElement(EscalationChat_1.default, { activeChatIssue: activeChatIssue, showEscalationChat: showEscalationChat, onClose: () => {
|
|
160
|
+
setActiveChatEscalationNumber(null);
|
|
161
|
+
setShowEscalationChat(false);
|
|
162
|
+
}, user: user, createEscalationChatMessage: createEscalationChatMessage, documentUploadUrl: documentUploadUrl, bucketName: bucketName, uploadExpertClientFiles: uploadExpertClientFiles, updateProjectEscalation: updateProjectEscalation, isExpert: isExpert })),
|
|
159
163
|
showSuspensionModal &&
|
|
160
164
|
react_1.default.createElement(AccountSuspensionModal_1.default, { showSuspensionModal: showSuspensionModal, onClose: () => setShowSuspensionModal(false) })),
|
|
161
165
|
react_1.default.createElement(react_hot_toast_1.Toaster, { position: "top-center", toastOptions: {
|
|
@@ -53,11 +53,11 @@ const MarkResolvedModal = ({ escalationId, expertName, open, onClose, updateProj
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
|
-
(0, utils_1.showToast)("success", "
|
|
56
|
+
(0, utils_1.showToast)("success", "Issue marked as resolved!");
|
|
57
57
|
}
|
|
58
58
|
catch (error) {
|
|
59
59
|
console.error("Failed to update escalation!", error);
|
|
60
|
-
(0, utils_1.showToast)("warning", "Failed to update
|
|
60
|
+
(0, utils_1.showToast)("warning", "Failed to update an issue!");
|
|
61
61
|
}
|
|
62
62
|
finally {
|
|
63
63
|
setSubmitting(false);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
declare const ViewResponseModal: ({
|
|
3
|
-
|
|
2
|
+
declare const ViewResponseModal: ({ selectedIssue, open, onClose, isExpert }: {
|
|
3
|
+
selectedIssue: any;
|
|
4
4
|
open: boolean;
|
|
5
5
|
onClose: () => void;
|
|
6
6
|
isExpert: boolean;
|
|
@@ -6,7 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const react_1 = __importDefault(require("react"));
|
|
7
7
|
const base_icons_1 = require("@paro.io/base-icons");
|
|
8
8
|
const core_1 = require("@material-ui/core");
|
|
9
|
-
const
|
|
9
|
+
const utils_1 = require("../shared/utils");
|
|
10
|
+
const EscalationIssueCard_1 = require("./EscalationIssueCard");
|
|
11
|
+
const ViewResponseModal = ({ selectedIssue, open, onClose, isExpert }) => {
|
|
12
|
+
const docs = [selectedIssue.expertSupportingDocuments, selectedIssue.clientSupportingDocuments, selectedIssue.internalSupportingDocuments];
|
|
13
|
+
const processedDocs = (0, utils_1.processDocs)(docs);
|
|
10
14
|
return (react_1.default.createElement(core_1.Dialog, { open: open, onClose: onClose, maxWidth: 'sm' },
|
|
11
15
|
react_1.default.createElement(core_1.DialogTitle, null,
|
|
12
16
|
react_1.default.createElement("div", { className: "text-black mb-1 p-2 pl-4 absolute top-0 left-0 w-full flex flex-row justify-between items-center z-50" },
|
|
@@ -20,8 +24,14 @@ const ViewResponseModal = ({ response, open, onClose, isExpert }) => {
|
|
|
20
24
|
react_1.default.createElement("p", { className: "text-sm font-medium" },
|
|
21
25
|
"Status: ",
|
|
22
26
|
react_1.default.createElement("span", { className: "font-normal" }, "Responded")),
|
|
27
|
+
react_1.default.createElement("p", { className: "text-sm font-medium" },
|
|
28
|
+
"Response Type: ",
|
|
29
|
+
react_1.default.createElement("span", { className: "font-normal" }, isExpert ? selectedIssue.clientResponseType : selectedIssue.expertResponseType)),
|
|
23
30
|
react_1.default.createElement("p", { className: "text-sm font-medium" },
|
|
24
31
|
"Response: ",
|
|
25
|
-
react_1.default.createElement("span", { className: "font-normal" },
|
|
32
|
+
react_1.default.createElement("span", { className: "font-normal" }, isExpert ? selectedIssue.clientResponse : selectedIssue.expertResponse))),
|
|
33
|
+
processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2 mt-4 mb-2" },
|
|
34
|
+
react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
|
|
35
|
+
processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1], customColor: `bg-success border-success` }))))))));
|
|
26
36
|
};
|
|
27
37
|
exports.default = ViewResponseModal;
|
|
@@ -45,6 +45,11 @@ const DiscussionSection = ({ disputeId, escalationNumber, currentUser, messages,
|
|
|
45
45
|
const [visibility, setVisibility] = (0, react_1.useState)('ALL');
|
|
46
46
|
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
47
47
|
const threadsEndRef = (0, react_1.useRef)(null);
|
|
48
|
+
(0, react_1.useEffect)(() => {
|
|
49
|
+
if (threadsEndRef.current) {
|
|
50
|
+
threadsEndRef.current.scrollIntoView({ behavior: 'smooth' });
|
|
51
|
+
}
|
|
52
|
+
}, [messages]);
|
|
48
53
|
// Get the sequence of unique userTypeIds to determine alignment
|
|
49
54
|
const userSequence = (0, react_1.useMemo)(() => {
|
|
50
55
|
const uniqueUsers = Array.from(new Set(messages.map(m => m.sender.userTypeId)));
|
|
@@ -109,7 +114,7 @@ const DiscussionSection = ({ disputeId, escalationNumber, currentUser, messages,
|
|
|
109
114
|
return userTypeId !== currentUser.userTypeId ? 'justify-start' : 'justify-end';
|
|
110
115
|
};
|
|
111
116
|
const displayMessageVisibility = (visibility) => {
|
|
112
|
-
switch (visibility) {
|
|
117
|
+
switch (visibility.toUpperCase()) {
|
|
113
118
|
case 'ALL':
|
|
114
119
|
return 'All';
|
|
115
120
|
case 'EXPERT_INTERNAL_ONLY':
|
|
@@ -141,27 +146,28 @@ const DiscussionSection = ({ disputeId, escalationNumber, currentUser, messages,
|
|
|
141
146
|
react_1.default.createElement(base_icons_1.IconChat, { size: "sm", className: "text-blue-600 mr-2" }),
|
|
142
147
|
react_1.default.createElement("p", null, "This discussion applies to all projects in this dispute."))),
|
|
143
148
|
react_1.default.createElement("div", { className: "rounded" },
|
|
144
|
-
messages.length ? react_1.default.createElement("div", { className: "flex-1 max-h-[40vh] overflow-y-auto border rounded-md p-2 space-y-6" },
|
|
145
|
-
react_1.default.createElement("div", { className: `flex
|
|
146
|
-
react_1.default.createElement("div", {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
react_1.default.createElement("div", { className:
|
|
153
|
-
react_1.default.createElement("
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
react_1.default.createElement("
|
|
164
|
-
|
|
149
|
+
messages.length ? react_1.default.createElement("div", { className: "flex-1 max-h-[40vh] overflow-y-auto border rounded-md p-2 space-y-6" },
|
|
150
|
+
messages.map((message) => (react_1.default.createElement("div", { key: message.id, className: `flex ${getMessageAlignment(message.sender.userTypeId)}` },
|
|
151
|
+
react_1.default.createElement("div", { className: `flex space-x-4 ${getMessageOrder(message.sender.userTypeId)} ${getMessageAlignment(message.sender.userTypeId)}` },
|
|
152
|
+
react_1.default.createElement("div", { style: {
|
|
153
|
+
backgroundColor: getSenderBackgroundColor(message.sender.userTypeId),
|
|
154
|
+
color: getSenderTextColor(message.sender.userTypeId)
|
|
155
|
+
}, className: "w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0" },
|
|
156
|
+
react_1.default.createElement("span", { className: "text-sm font-bold" }, getSenderInitial(message.sender))),
|
|
157
|
+
react_1.default.createElement("div", { className: "flex-1" },
|
|
158
|
+
react_1.default.createElement("div", { className: `flex items-center ${getHeaderAlignment(message.sender.userTypeId)} space-x-2 mr-1` },
|
|
159
|
+
react_1.default.createElement("span", { className: "text-sm font-bold text-[#333333]" },
|
|
160
|
+
message.sender.firstName,
|
|
161
|
+
" ",
|
|
162
|
+
message.sender.lastName),
|
|
163
|
+
react_1.default.createElement("span", { className: "text-xs text-[#666666]" }, (0, dayjs_1.default)(message.createdAt).format('MMM D, YYYY • h:mm A')),
|
|
164
|
+
isInternal && (react_1.default.createElement("span", { className: "text-xs text-[#666666]" },
|
|
165
|
+
"(",
|
|
166
|
+
displayMessageVisibility(message.visibility),
|
|
167
|
+
")"))),
|
|
168
|
+
react_1.default.createElement("div", { style: { backgroundColor: getSenderBackgroundColor(message.sender.userTypeId) }, className: "mt-1 p-3 rounded-lg" },
|
|
169
|
+
react_1.default.createElement("p", { className: `text-sm ${getHeaderAlignment(message.sender.userTypeId)}`, style: { color: getSenderTextColor(message.sender.userTypeId) } }, message.messageText))))))),
|
|
170
|
+
react_1.default.createElement("div", { ref: threadsEndRef })) : react_1.default.createElement(react_1.default.Fragment, null),
|
|
165
171
|
react_1.default.createElement("div", { className: "space-y-4 p-6 space-y-6 rounded mt-4", style: { backgroundColor: '#F5F7F9' } },
|
|
166
172
|
react_1.default.createElement("div", null,
|
|
167
173
|
react_1.default.createElement("div", { className: "font-bold text-[#333333] mb-2" }, "Add Comment"),
|
|
@@ -42,6 +42,7 @@ export declare const titleFeatures: string[];
|
|
|
42
42
|
export declare const serviceDescriptions: Record<string, string>;
|
|
43
43
|
export declare const selectedServicesReducer: (selectedServices: any, action: any) => any;
|
|
44
44
|
export declare const generateUUID: () => string;
|
|
45
|
+
export declare const processDocs: (docs: (string | null | undefined)[]) => string[];
|
|
45
46
|
export declare const sharedUtils: {
|
|
46
47
|
selectedServicesReducer: (selectedServices: any, action: any) => any;
|
|
47
48
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.sharedUtils = exports.generateUUID = exports.selectedServicesReducer = exports.serviceDescriptions = exports.titleFeatures = exports.features = exports.titleMappings = exports.DOCUMENT_TYPE_CONSTANTS = exports.validateFileUpload = exports.showToast = exports.MAX_FILE_SIZE = exports.ACCEPTED_FILE_TYPES = exports.formatDate = exports.CustomPaper = exports.handleDownloadPdf = exports.getFileMimeType = exports.stateAbbreviationMap = exports.getPreviousMonthStartDate = exports.isOlderThan30Days = exports.formatTenure = exports.isOnClickEvent = void 0;
|
|
3
|
+
exports.sharedUtils = exports.processDocs = exports.generateUUID = exports.selectedServicesReducer = exports.serviceDescriptions = exports.titleFeatures = exports.features = exports.titleMappings = exports.DOCUMENT_TYPE_CONSTANTS = exports.validateFileUpload = exports.showToast = exports.MAX_FILE_SIZE = exports.ACCEPTED_FILE_TYPES = exports.formatDate = exports.CustomPaper = exports.handleDownloadPdf = exports.getFileMimeType = exports.stateAbbreviationMap = exports.getPreviousMonthStartDate = exports.isOlderThan30Days = exports.formatTenure = exports.isOnClickEvent = void 0;
|
|
4
4
|
exports.getComparator = getComparator;
|
|
5
5
|
exports.stableSort = stableSort;
|
|
6
6
|
exports.compareItems = compareItems;
|
|
@@ -363,4 +363,13 @@ const generateUUID = () => {
|
|
|
363
363
|
return (0, uuid_1.v4)();
|
|
364
364
|
};
|
|
365
365
|
exports.generateUUID = generateUUID;
|
|
366
|
+
const processDocs = (docs) => {
|
|
367
|
+
return docs
|
|
368
|
+
.filter(doc => doc !== null && doc !== undefined && doc !== '' && doc !== "NULL")
|
|
369
|
+
.flatMap(doc => doc.split(','))
|
|
370
|
+
.map(doc => doc.trim())
|
|
371
|
+
//@ts-ignore
|
|
372
|
+
.filter(doc => doc !== '' || doc !== "NULL");
|
|
373
|
+
};
|
|
374
|
+
exports.processDocs = processDocs;
|
|
366
375
|
exports.sharedUtils = { selectedServicesReducer: exports.selectedServicesReducer };
|