@paro.io/expert-shared-components 1.14.7 → 1.14.9
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/AccountSuspensionBanner.js +3 -3
- package/lib/components/Escalations/AccountSuspensionModal.js +16 -7
- package/lib/components/Escalations/EscalationChat.js +1 -1
- package/lib/components/Escalations/EscalationRespondForm.js +1 -1
- package/lib/components/Escalations/EscalationSubmitForm.js +6 -2
- package/lib/components/Escalations/Escalations.js +7 -3
- package/lib/components/ExpertProfileHeader/NetworkSection.js +18 -15
- package/lib/components/Invoices/DiscussionSection.d.ts +4 -1
- package/lib/components/Invoices/DiscussionSection.js +44 -17
- package/lib/components/ProjectIntelligence/FocusAreas/index.js +1 -2
- package/lib/components/ProjectIntelligence/index.d.ts +1 -0
- package/lib/components/ProjectIntelligence/index.js +14 -69
- package/lib/components/shared/utils.js +2 -3
- package/package.json +1 -1
|
@@ -66,8 +66,8 @@ const AccountSuspensionBanner = ({ setShowSuspensionModal, escalationDisputeStat
|
|
|
66
66
|
react_1.default.createElement("div", { className: "bg-white bg-opacity-20 rounded-full p-2 mr-3" },
|
|
67
67
|
react_1.default.createElement(base_icons_1.IconExclamation, { className: "h-6 w-6 text-white" })),
|
|
68
68
|
react_1.default.createElement("div", null,
|
|
69
|
-
react_1.default.createElement("h3", { className: "text-lg font-bold text-white" }, "Account Suspension Risk"),
|
|
70
|
-
react_1.default.createElement("p", { className: "text-red-100 text-sm mt-1" }, "Unresolved escalations can lead to
|
|
69
|
+
react_1.default.createElement("h3", { className: "text-lg font-bold text-white" }, "Account Suspension Risk \u2013 Your account is currently active"),
|
|
70
|
+
react_1.default.createElement("p", { className: "text-red-100 text-sm mt-1" }, "Unresolved escalations can lead to suspension, but you are not suspended at this time. Please address issues promptly to avoid future suspension."),
|
|
71
71
|
react_1.default.createElement("div", { className: "flex items-center mt-2 text-red-100 text-xs" },
|
|
72
72
|
react_1.default.createElement("span", null,
|
|
73
73
|
mediumWarnings,
|
|
@@ -76,6 +76,6 @@ const AccountSuspensionBanner = ({ setShowSuspensionModal, escalationDisputeStat
|
|
|
76
76
|
"/2 warnings: High = 60 days \u2022 ",
|
|
77
77
|
criticalWarnings,
|
|
78
78
|
"/1 offense: Critical = Permanent")))),
|
|
79
|
-
react_1.default.createElement(base_ui_1.Button, { label: "view details", onClick: () => setShowSuspensionModal(true), iconLeft: react_1.default.createElement(base_icons_1.IconInfoCircle, { size: "sm" }), color: "danger", className: "bg-white hover:bg-
|
|
79
|
+
react_1.default.createElement(base_ui_1.Button, { label: "view details", onClick: () => setShowSuspensionModal(true), iconLeft: react_1.default.createElement(base_icons_1.IconInfoCircle, { size: "sm" }), color: "danger", className: "bg-white text-danger-dark hover:bg-white hover:!text-danger-dark" }))));
|
|
80
80
|
};
|
|
81
81
|
exports.default = AccountSuspensionBanner;
|
|
@@ -8,7 +8,7 @@ const base_icons_1 = require("@paro.io/base-icons");
|
|
|
8
8
|
const core_1 = require("@material-ui/core");
|
|
9
9
|
const AccountSuspensionModal = ({ showSuspensionModal, onClose }) => {
|
|
10
10
|
return (react_1.default.createElement(core_1.Dialog, { open: showSuspensionModal, onClose: onClose, "aria-labelledby": "responsive-dialog-title", maxWidth: "sm", scroll: "paper" },
|
|
11
|
-
react_1.default.createElement("div", { className: "bg-[#
|
|
11
|
+
react_1.default.createElement("div", { className: "bg-[#282B52] text-white mb-1 p-1 pl-4 absolute top-0 left-0 w-full flex flex-row justify-between items-center z-50" },
|
|
12
12
|
react_1.default.createElement("b", null, "Automated Suspension Process"),
|
|
13
13
|
react_1.default.createElement(core_1.IconButton, { onClick: () => onClose() },
|
|
14
14
|
react_1.default.createElement(base_icons_1.IconX, { className: "text-white" }))),
|
|
@@ -20,7 +20,9 @@ const AccountSuspensionModal = ({ showSuspensionModal, onClose }) => {
|
|
|
20
20
|
react_1.default.createElement(base_icons_1.IconBriefcase, { className: "h-5 w-5 text-red-500 mt-0.5 mr-2 flex-shrink-0" }),
|
|
21
21
|
react_1.default.createElement("div", null,
|
|
22
22
|
react_1.default.createElement("p", { className: "font-medium text-red-800" }, "Critical Information"),
|
|
23
|
-
react_1.default.createElement("p", { className: "text-sm text-red-700 mt-1" }, "Engagment support issues require timely attention to maintain client relationships and project success. Multiple unresolved issues may result in account warnings and potential suspension.")
|
|
23
|
+
react_1.default.createElement("p", { className: "text-sm text-red-700 mt-1" }, "Engagment support issues require timely attention to maintain client relationships and project success. Multiple unresolved issues may result in account warnings and potential suspension."),
|
|
24
|
+
react_1.default.createElement("p", { className: "text-xs text-red-700 mt-1" },
|
|
25
|
+
react_1.default.createElement("b", null, "\u26A0\uFE0F Suspension thresholds are based on the number of warnings within each severity level, not total warnings across all levels")))))),
|
|
24
26
|
react_1.default.createElement("div", { className: "space-y-6" },
|
|
25
27
|
react_1.default.createElement("div", { className: "relative" },
|
|
26
28
|
react_1.default.createElement("div", { className: "absolute left-4 top-8 bottom-0 w-0.5 bg-gray-200" }),
|
|
@@ -43,6 +45,9 @@ const AccountSuspensionModal = ({ showSuspensionModal, onClose }) => {
|
|
|
43
45
|
react_1.default.createElement("h4", { className: "font-semibold text-orange-800" }, "Level 2: Medium Severity"),
|
|
44
46
|
react_1.default.createElement("div", { className: "text-xs bg-orange-100 text-orange-700 px-2 py-1 rounded-full" }, "3 Warnings System")),
|
|
45
47
|
react_1.default.createElement("p", { className: "text-sm mb-2 font-medium text-red-800" }, "After 3 warnings: 30-day suspension"),
|
|
48
|
+
react_1.default.createElement("div", { className: "text-xs text-gray-500 mb-2" },
|
|
49
|
+
react_1.default.createElement("strong", null, "Examples:"),
|
|
50
|
+
" Poor client communication, missed project deadlines, quality concerns, repeated light violations"),
|
|
46
51
|
react_1.default.createElement("div", null,
|
|
47
52
|
react_1.default.createElement("b", null, "Note: "),
|
|
48
53
|
"Warnings are counted within this level, not as a total. Suspension is triggered after 3 warnings at this severity. ",
|
|
@@ -56,6 +61,9 @@ const AccountSuspensionModal = ({ showSuspensionModal, onClose }) => {
|
|
|
56
61
|
react_1.default.createElement("h4", { className: "font-semibold text-red-800" }, "Level 3: High Severity"),
|
|
57
62
|
react_1.default.createElement("div", { className: "text-xs bg-red-100 text-red-700 px-2 py-1 rounded-full" }, "2 Warnings System")),
|
|
58
63
|
react_1.default.createElement("p", { className: "text-sm mb-2 font-medium text-red-800" }, "After 2 warnings: 60-day suspension"),
|
|
64
|
+
react_1.default.createElement("div", { className: "text-xs text-gray-500 mb-2" },
|
|
65
|
+
react_1.default.createElement("strong", null, "Examples:"),
|
|
66
|
+
" Significant project failures,client relationship damage, contract violations, repeated medium violations"),
|
|
59
67
|
react_1.default.createElement("div", null,
|
|
60
68
|
react_1.default.createElement("b", null, "Note: "),
|
|
61
69
|
"Warnings are counted within this level, not as a total. Suspension is triggered after 2 warnings at this severity. ",
|
|
@@ -69,20 +77,21 @@ const AccountSuspensionModal = ({ showSuspensionModal, onClose }) => {
|
|
|
69
77
|
react_1.default.createElement("h4", { className: "font-semibold text-gray-900" }, "Level 4: Critical Severity"),
|
|
70
78
|
react_1.default.createElement("div", { className: "text-xs bg-gray-800 text-white px-2 py-1 rounded-full" }, "One Time Offense")),
|
|
71
79
|
react_1.default.createElement("p", { className: "text-sm mb-2 font-medium text-red-800" }, "Permanent suspension"),
|
|
80
|
+
react_1.default.createElement("div", { className: "text-xs text-gray-500 mb-2" },
|
|
81
|
+
react_1.default.createElement("strong", null, "Examples:"),
|
|
82
|
+
" Project abandonment, terms of service violations, non-circumvention breaches, fraudulent activity, severe misconduct"),
|
|
72
83
|
react_1.default.createElement("div", null,
|
|
73
84
|
react_1.default.createElement("b", null, "Note: "),
|
|
74
85
|
"Warnings are counted within this level, not as a total. Suspension is triggered after 1 warning at this severity. ",
|
|
75
86
|
react_1.default.createElement("b", null, "After 1 warning in this level"),
|
|
76
|
-
": Permanent suspension")))),
|
|
77
|
-
react_1.default.createElement("div", { className: "text-xs" },
|
|
78
|
-
react_1.default.createElement("b", null, "\u26A0\uFE0F Suspension thresholds are based on the number of warnings within each severity level, not total warnings across all levels"))),
|
|
87
|
+
": Permanent suspension"))))),
|
|
79
88
|
react_1.default.createElement("div", { className: "mt-6 bg-gray-50 rounded-lg p-4" },
|
|
80
89
|
react_1.default.createElement("h4", { className: "font-medium text-gray-900 mb-2" }, "Important Reminders"),
|
|
81
90
|
react_1.default.createElement("ul", { className: "text-sm text-gray-600 space-y-1" },
|
|
82
91
|
react_1.default.createElement("li", null,
|
|
83
|
-
"
|
|
92
|
+
"Warnings are tracked separately per severity level. Suspensions are triggered only when the threshold is met ",
|
|
84
93
|
react_1.default.createElement("b", null, "within a specific level"),
|
|
85
94
|
" (e.g., 3 Medium-level warnings = Medium suspension)"),
|
|
86
|
-
react_1.default.createElement("li", null, "
|
|
95
|
+
react_1.default.createElement("li", null, "Warnings reset after 6 months of good standing (no new warnings)")))))));
|
|
87
96
|
};
|
|
88
97
|
exports.default = AccountSuspensionModal;
|
|
@@ -127,7 +127,7 @@ const EscalationChat = ({ activeChatIssue, showEscalationChat, onClose, user, cr
|
|
|
127
127
|
react_1.default.createElement(base_icons_1.IconX, null))))),
|
|
128
128
|
react_1.default.createElement(core_1.DialogContent, null,
|
|
129
129
|
react_1.default.createElement("div", { className: "bg-white rounded-lg w-full overflow-hidden flex flex-col p-2 mt-12" },
|
|
130
|
-
react_1.default.createElement(DiscussionSection_1.DiscussionSection, { escalationNumber: activeChatIssue.escalationNumber, currentUser: user, messages: (_b = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.chatMessages) !== null && _b !== void 0 ? _b : [], onCreateMessage: createEscalationChatMessage, isInternal: false }),
|
|
130
|
+
react_1.default.createElement(DiscussionSection_1.DiscussionSection, { escalationNumber: activeChatIssue.escalationNumber, currentUser: user, messages: (_b = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.chatMessages) !== null && _b !== void 0 ? _b : [], onCreateMessage: createEscalationChatMessage, isInternal: false, isExpert: isExpert, internalEscalationTo: activeChatIssue.internalEscalationTo, clientEscalationTo: activeChatIssue.clientEscalationTo }),
|
|
131
131
|
processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2 mt-4 mb-2" },
|
|
132
132
|
react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
|
|
133
133
|
processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1], customColor: `bg-success border-success` }))))),
|
|
@@ -168,7 +168,7 @@ const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downl
|
|
|
168
168
|
escalationId: selectedIssue.escalationId,
|
|
169
169
|
[isExpert ? 'expertResponseType' : 'clientResponseType']: selectedType,
|
|
170
170
|
[isExpert ? 'expertResponse' : 'clientResponse']: responseInput,
|
|
171
|
-
[isExpert ? 'expertSupportingDocuments' : 'clientSupportingDocuments']: uploadFiles.length > 0 ? uploadFiles.join(", ") : '',
|
|
171
|
+
[isExpert ? 'expertSupportingDocuments' : 'clientSupportingDocuments']: uploadFiles.length > 0 ? uploadFiles.filter(f => !!f && f !== "NULL").join(", ") : '',
|
|
172
172
|
statusChangedBy: userId,
|
|
173
173
|
}
|
|
174
174
|
}
|
|
@@ -71,7 +71,7 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
|
|
|
71
71
|
const [issueStartDate, setIssueStartDate] = (0, react_1.useState)((0, dayjs_1.default)(new Date).format('MM-DD-YYYY'));
|
|
72
72
|
const [isDateInvalid, setIsDateInvalid] = (0, react_1.useState)(false);
|
|
73
73
|
const [submitting, setSubmitting] = (0, react_1.useState)(false);
|
|
74
|
-
const [clientEscalationTo, setClientEscalationTo] = (0, react_1.useState)('');
|
|
74
|
+
const [clientEscalationTo, setClientEscalationTo] = (0, react_1.useState)('paro');
|
|
75
75
|
const fileInputRef = (0, react_1.useRef)(null);
|
|
76
76
|
const escalationId = (0, utils_1.generateUUID)();
|
|
77
77
|
(0, react_1.useEffect)(() => {
|
|
@@ -328,7 +328,11 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
|
|
|
328
328
|
react_1.default.createElement(core_1.MenuItem, { value: "paro" }, "Paro only"),
|
|
329
329
|
react_1.default.createElement(core_1.MenuItem, { value: "both" }, "Both Expert And Paro"))),
|
|
330
330
|
react_1.default.createElement("div", { className: "bg-[#EFF6FF] p-3 rounded" },
|
|
331
|
-
react_1.default.createElement(base_ui_1.Checkbox, { id: "checkbox-1", label:
|
|
331
|
+
react_1.default.createElement(base_ui_1.Checkbox, { id: "checkbox-1", label: isExpert
|
|
332
|
+
? `I understand this will notify my client and the Paro support team`
|
|
333
|
+
: clientEscalationTo === 'both'
|
|
334
|
+
? `I understand this will notify my expert and the Paro support team`
|
|
335
|
+
: `I understand this issue will be created for Paro first and internal users could involve the Expert if needed`, name: "acknowledge", isChecked: isChecked, onChange: () => setIsChecked(prev => !prev) })),
|
|
332
336
|
react_1.default.createElement("div", { className: "flex justify-end space-x-3 pt-4" },
|
|
333
337
|
react_1.default.createElement(base_ui_1.Button, { label: "Cancel", onClick: goBack, disabled: submitting || uploadingFile }),
|
|
334
338
|
react_1.default.createElement(base_ui_1.Button, { label: "Submit issue", onClick: handleSubmit, color: "primary", isLoading: submitting, disabled: !isFormValid() || uploadingFile }))))));
|
|
@@ -28,6 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.Escalations = void 0;
|
|
30
30
|
const react_1 = __importStar(require("react"));
|
|
31
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
31
32
|
const EscalationReportBanner_1 = __importDefault(require("./EscalationReportBanner"));
|
|
32
33
|
const base_ui_1 = require("@paro.io/base-ui");
|
|
33
34
|
const EscalationTabs_1 = __importDefault(require("./EscalationTabs"));
|
|
@@ -35,6 +36,7 @@ const EscalationTabsContent_1 = __importDefault(require("./EscalationTabsContent
|
|
|
35
36
|
const EscalationRespondForm_1 = __importDefault(require("./EscalationRespondForm"));
|
|
36
37
|
const EscalationSubmitForm_1 = __importDefault(require("./EscalationSubmitForm"));
|
|
37
38
|
const EscalationChat_1 = __importDefault(require("./EscalationChat"));
|
|
39
|
+
const AccountSuspensionBanner_1 = __importDefault(require("./AccountSuspensionBanner"));
|
|
38
40
|
const AccountSuspensionModal_1 = __importDefault(require("./AccountSuspensionModal"));
|
|
39
41
|
const base_icons_1 = require("@paro.io/base-icons");
|
|
40
42
|
const EscalationIssueCard_1 = require("./EscalationIssueCard");
|
|
@@ -79,9 +81,9 @@ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations
|
|
|
79
81
|
isValidEscalation &&
|
|
80
82
|
status === 'InProgress';
|
|
81
83
|
return shouldInclude;
|
|
82
|
-
});
|
|
83
|
-
const inProgressIssues = escalations.filter(issue => { var _a; return ((((_a = issue === null || issue === void 0 ? void 0 : issue.submittedByUser) === null || _a === void 0 ? void 0 : _a.userTypeId) === user.userTypeId) || (isExpert ? issue.expertResponse !== null : issue.clientResponse !== null)) && (issue === null || issue === void 0 ? void 0 : issue.status) === 'InProgress'; });
|
|
84
|
-
const resolvedIssues = escalations.filter(issue => (issue === null || issue === void 0 ? void 0 : issue.status) === 'Resolved');
|
|
84
|
+
}).sort((a, b) => (0, dayjs_1.default)(b.createdAt).valueOf() - (0, dayjs_1.default)(a.createdAt).valueOf());
|
|
85
|
+
const inProgressIssues = escalations.filter(issue => { var _a; return ((((_a = issue === null || issue === void 0 ? void 0 : issue.submittedByUser) === null || _a === void 0 ? void 0 : _a.userTypeId) === user.userTypeId) || (isExpert ? issue.expertResponse !== null : issue.clientResponse !== null)) && (issue === null || issue === void 0 ? void 0 : issue.status) === 'InProgress'; }).sort((a, b) => (0, dayjs_1.default)(b.createdAt).valueOf() - (0, dayjs_1.default)(a.createdAt).valueOf());
|
|
86
|
+
const resolvedIssues = escalations.filter(issue => (issue === null || issue === void 0 ? void 0 : issue.status) === 'Resolved').sort((a, b) => (0, dayjs_1.default)(b.updatedAt).valueOf() - (0, dayjs_1.default)(a.updatedAt).valueOf());
|
|
85
87
|
const goBack = () => {
|
|
86
88
|
if (selectedIssueId !== null) {
|
|
87
89
|
setSelectedIssueId(null);
|
|
@@ -167,6 +169,8 @@ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations
|
|
|
167
169
|
react_1.default.createElement("h3", { className: "font-semibold text-sm mb-1" }, "Need Support with a Client?"),
|
|
168
170
|
react_1.default.createElement("p", { className: "text-xs" }, "Report payment, scope, or communication activeIssues")))),
|
|
169
171
|
react_1.default.createElement(base_ui_1.Button, { label: "Report issue", onClick: () => setSelectedIssueId(0), iconLeft: react_1.default.createElement(base_icons_1.IconExclamation, { size: "sm", className: "text-white" }), color: "primary" }))),
|
|
172
|
+
isExpert &&
|
|
173
|
+
react_1.default.createElement(AccountSuspensionBanner_1.default, { setShowSuspensionModal: setShowSuspensionModal, escalationDisputeStatistics: escalationDisputeStatistics }),
|
|
170
174
|
!isExpert &&
|
|
171
175
|
react_1.default.createElement(EscalationReportBanner_1.default, { onReport: () => setSelectedIssueId(0), isExpert: isExpert }),
|
|
172
176
|
escalations.length > 0 ? react_1.default.createElement(EscalationTabs_1.default, { activeTab: activeEscalationTab, setActiveTab: setActiveEscalationTab, activeIssues: activeIssues.length, inProgressIssues: inProgressIssues.length, resolvedIssues: resolvedIssues.length }) : null,
|
|
@@ -154,21 +154,24 @@ const NetworkSection = ({ handleScrollToBottom, preferenceTasks, isWhiteLabel, d
|
|
|
154
154
|
react_1.default.createElement(icons_1.Cached, null))),
|
|
155
155
|
react_1.default.createElement(core_1.Box, { mt: 1, mb: 1, mr: 2 },
|
|
156
156
|
react_1.default.createElement(core_1.Divider, null))),
|
|
157
|
-
|
|
158
|
-
react_1.default.createElement(
|
|
159
|
-
react_1.default.createElement(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
157
|
+
react_1.default.createElement(core_1.Grid, { style: { marginRight: '8px', marginLeft: '2px' } },
|
|
158
|
+
react_1.default.createElement(core_1.Box, { mb: 1 },
|
|
159
|
+
react_1.default.createElement("b", null, "Engagement Issues :")),
|
|
160
|
+
escalationDisputeStatistics &&
|
|
161
|
+
react_1.default.createElement(react_1.default.Fragment, null,
|
|
162
|
+
react_1.default.createElement(EarningsSection_1.EarningsInfo, { label: "# of Escalations in last 3 months", value: (_c = escalationDisputeStatistics.recentResolvedEscalations) !== null && _c !== void 0 ? _c : 0 }),
|
|
163
|
+
react_1.default.createElement(core_1.Box, { mb: 2 },
|
|
164
|
+
react_1.default.createElement(core_1.Divider, null)),
|
|
165
|
+
react_1.default.createElement(EarningsSection_1.EarningsInfo, { label: "Total # of Escalations", value: (_d = escalationDisputeStatistics.totalResolvedEscalations) !== null && _d !== void 0 ? _d : 0 }),
|
|
166
|
+
react_1.default.createElement(core_1.Box, { mb: 2 },
|
|
167
|
+
react_1.default.createElement(core_1.Divider, null)),
|
|
168
|
+
react_1.default.createElement(EarningsSection_1.EarningsInfo, { label: "# of Disputes in last 3 months", value: (_e = escalationDisputeStatistics.recentResolvedDisputes) !== null && _e !== void 0 ? _e : 0 }),
|
|
169
|
+
react_1.default.createElement(core_1.Box, { mb: 2 },
|
|
170
|
+
react_1.default.createElement(core_1.Divider, null)),
|
|
171
|
+
react_1.default.createElement(EarningsSection_1.EarningsInfo, { label: "Total # of Disputes", value: (_f = escalationDisputeStatistics.totalResolvedDisputes) !== null && _f !== void 0 ? _f : 0 }),
|
|
172
|
+
react_1.default.createElement(core_1.Box, { mb: 0.5 },
|
|
173
|
+
react_1.default.createElement(core_1.Divider, null)),
|
|
174
|
+
!isInternal && react_1.default.createElement("a", { href: `${paroAppUrl}/engagement-support`, className: "text-xs underline text-[#1878BD] cursor-pointer block text-right mb-2", target: "_blank", rel: "noopener noreferrer" }, "See more Disputes & Escalations"))),
|
|
172
175
|
react_1.default.createElement(core_1.Grid, { style: { marginRight: '8px', marginLeft: '2px' } },
|
|
173
176
|
react_1.default.createElement(core_1.Box, { mb: 1 },
|
|
174
177
|
react_1.default.createElement("b", null, "Network Availability :")),
|
|
@@ -17,6 +17,9 @@ interface DiscussionSectionProps {
|
|
|
17
17
|
messages: Message[];
|
|
18
18
|
onCreateMessage: (variables: any) => Promise<any>;
|
|
19
19
|
isInternal?: boolean;
|
|
20
|
+
isExpert?: boolean;
|
|
21
|
+
internalEscalationTo?: string;
|
|
22
|
+
clientEscalationTo?: string;
|
|
20
23
|
}
|
|
21
|
-
export declare const DiscussionSection: ({ disputeId, escalationNumber, currentUser, messages, onCreateMessage, isInternal, }: DiscussionSectionProps) => JSX.Element;
|
|
24
|
+
export declare const DiscussionSection: ({ disputeId, escalationNumber, currentUser, messages, onCreateMessage, isInternal, isExpert, internalEscalationTo, clientEscalationTo, }: DiscussionSectionProps) => JSX.Element;
|
|
22
25
|
export {};
|
|
@@ -40,7 +40,7 @@ const react_1 = __importStar(require("react"));
|
|
|
40
40
|
const base_ui_1 = require("@paro.io/base-ui");
|
|
41
41
|
const dayjs_1 = __importDefault(require("dayjs"));
|
|
42
42
|
const base_icons_1 = require("@paro.io/base-icons");
|
|
43
|
-
const DiscussionSection = ({ disputeId, escalationNumber, currentUser, messages, onCreateMessage, isInternal = false, }) => {
|
|
43
|
+
const DiscussionSection = ({ disputeId, escalationNumber, currentUser, messages, onCreateMessage, isInternal = false, isExpert = true, internalEscalationTo, clientEscalationTo, }) => {
|
|
44
44
|
const [newMessage, setNewMessage] = (0, react_1.useState)('');
|
|
45
45
|
const [visibility, setVisibility] = (0, react_1.useState)('ALL');
|
|
46
46
|
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
@@ -144,7 +144,10 @@ const DiscussionSection = ({ disputeId, escalationNumber, currentUser, messages,
|
|
|
144
144
|
react_1.default.createElement("span", null, "\u00A0Paro Support")))),
|
|
145
145
|
react_1.default.createElement("div", { className: "flex flex-row justify-start mr-4 text-gray-600" },
|
|
146
146
|
react_1.default.createElement(base_icons_1.IconChat, { size: "sm", className: "text-blue-600 mr-2" }),
|
|
147
|
-
react_1.default.createElement("p", null,
|
|
147
|
+
react_1.default.createElement("p", null,
|
|
148
|
+
"This discussion applies to all projects in this ",
|
|
149
|
+
disputeId ? 'dispute' : 'escalation',
|
|
150
|
+
"."))),
|
|
148
151
|
react_1.default.createElement("div", { className: "rounded" },
|
|
149
152
|
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
153
|
messages.map((message) => (react_1.default.createElement("div", { key: message.id, className: `flex ${getMessageAlignment(message.sender.userTypeId)}` },
|
|
@@ -173,21 +176,45 @@ const DiscussionSection = ({ disputeId, escalationNumber, currentUser, messages,
|
|
|
173
176
|
react_1.default.createElement("div", { className: "font-bold text-[#333333] mb-2" }, "Add Comment"),
|
|
174
177
|
react_1.default.createElement("textarea", { value: newMessage, onChange: (e) => setNewMessage(e.target.value), placeholder: "Type your comment here...", className: "w-full h-24 p-3 border border-[#CCCCCC] rounded-lg text-sm resize-none focus:outline-none focus:ring-2 focus:ring-[#248384]" })),
|
|
175
178
|
react_1.default.createElement("div", { className: "flex items-center justify-between" },
|
|
176
|
-
react_1.default.createElement("div", { className: "flex items-center space-x-4" },
|
|
177
|
-
react_1.default.createElement(
|
|
178
|
-
|
|
179
|
-
react_1.default.createElement("
|
|
180
|
-
react_1.default.createElement("
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
react_1.default.createElement("
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
179
|
+
react_1.default.createElement("div", { className: "flex items-center space-x-4" },
|
|
180
|
+
isInternal && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
181
|
+
react_1.default.createElement("span", { className: "text-sm text-[#666666]" }, "Visible to:"),
|
|
182
|
+
react_1.default.createElement("div", { className: "flex items-center space-x-2" },
|
|
183
|
+
internalEscalationTo === 'expert' && (react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
184
|
+
react_1.default.createElement("input", { type: "radio", checked: true, readOnly: true, onChange: () => setVisibility('EXPERT_INTERNAL_ONLY'), className: "form-radio text-[#248384]" }),
|
|
185
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "Expert Only"))),
|
|
186
|
+
internalEscalationTo === 'client' && (react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
187
|
+
react_1.default.createElement("input", { type: "radio", checked: true, readOnly: true, className: "form-radio text-[#248384]" }),
|
|
188
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "Client Only"))),
|
|
189
|
+
internalEscalationTo === 'both' && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
190
|
+
react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
191
|
+
react_1.default.createElement("input", { type: "radio", checked: visibility === 'EXPERT_INTERNAL_ONLY', onChange: () => setVisibility('EXPERT_INTERNAL_ONLY'), className: "form-radio text-[#248384]" }),
|
|
192
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "Expert Only")),
|
|
193
|
+
react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
194
|
+
react_1.default.createElement("input", { type: "radio", checked: visibility === 'CLIENT_INTERNAL_ONLY', onChange: () => setVisibility('CLIENT_INTERNAL_ONLY'), className: "form-radio text-[#248384]" }),
|
|
195
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "Client Only")),
|
|
196
|
+
react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
197
|
+
react_1.default.createElement("input", { type: "radio", checked: visibility === 'INTERNAL_ONLY', onChange: () => setVisibility('INTERNAL_ONLY'), className: "form-radio text-[#248384]" }),
|
|
198
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "Internal Only")),
|
|
199
|
+
react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
200
|
+
react_1.default.createElement("input", { type: "radio", checked: visibility === 'ALL', onChange: () => setVisibility('ALL'), className: "form-radio text-[#248384]" }),
|
|
201
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "All"))))))),
|
|
202
|
+
!isExpert && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
203
|
+
react_1.default.createElement("span", { className: "text-sm text-[#666666]" }, "Visible to:"),
|
|
204
|
+
react_1.default.createElement("div", { className: "flex items-center space-x-2" },
|
|
205
|
+
clientEscalationTo === 'paro' && (react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
206
|
+
react_1.default.createElement("input", { type: "radio", checked: true, readOnly: true, onChange: () => setVisibility('INTERNAL_ONLY'), className: "form-radio text-[#248384]" }),
|
|
207
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "Internal Only"))),
|
|
208
|
+
clientEscalationTo === 'both' && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
209
|
+
react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
210
|
+
react_1.default.createElement("input", { type: "radio", checked: visibility === 'EXPERT_INTERNAL_ONLY', onChange: () => setVisibility('EXPERT_INTERNAL_ONLY'), className: "form-radio text-[#248384]" }),
|
|
211
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "Expert Only")),
|
|
212
|
+
react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
213
|
+
react_1.default.createElement("input", { type: "radio", checked: visibility === 'INTERNAL_ONLY', onChange: () => setVisibility('INTERNAL_ONLY'), className: "form-radio text-[#248384]" }),
|
|
214
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "Internal Only")),
|
|
215
|
+
react_1.default.createElement("label", { className: "flex items-center space-x-2 cursor-pointer" },
|
|
216
|
+
react_1.default.createElement("input", { type: "radio", checked: visibility === 'ALL', onChange: () => setVisibility('ALL'), className: "form-radio text-[#248384]" }),
|
|
217
|
+
react_1.default.createElement("span", { className: "text-sm text-[#333333]" }, "All")))))))),
|
|
191
218
|
react_1.default.createElement(base_ui_1.Button, { label: "Reply", color: "primary", isLoading: isLoading, onClick: handleSendMessage, disabled: !newMessage.trim() }))))));
|
|
192
219
|
};
|
|
193
220
|
exports.DiscussionSection = DiscussionSection;
|
|
@@ -25,7 +25,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.FocusAreas = void 0;
|
|
27
27
|
const react_1 = __importStar(require("react"));
|
|
28
|
-
const date_fns_1 = require("date-fns");
|
|
29
28
|
const utils_1 = require("../../shared/utils");
|
|
30
29
|
const STATUS_COLORS = {
|
|
31
30
|
CONFIRMED: 'bg-blue-100 text-blue-800 border-blue-200',
|
|
@@ -180,7 +179,7 @@ const FocusAreas = ({ focusAreas, updateOpportunityFocusArea, GetOpportunityInsi
|
|
|
180
179
|
react_1.default.createElement("span", null, "Edit Focus Area")))),
|
|
181
180
|
react_1.default.createElement("p", { className: "text-sm text-gray-600 mb-2" }, area.description),
|
|
182
181
|
react_1.default.createElement("div", { className: "flex items-center space-x-4 text-xs text-gray-500" },
|
|
183
|
-
react_1.default.createElement("span", null,
|
|
182
|
+
react_1.default.createElement("span", null, area.dueDate),
|
|
184
183
|
react_1.default.createElement("span", { className: `font-medium ${PRIORITY_COLORS[area.priority]}` },
|
|
185
184
|
area.priority,
|
|
186
185
|
" Priority"),
|
|
@@ -15,6 +15,7 @@ interface ProjectIntelligenceProps {
|
|
|
15
15
|
onSaveFocusArea?: any;
|
|
16
16
|
onSaveMissingInformation?: any;
|
|
17
17
|
isParoIntelligenceRolePresent?: boolean;
|
|
18
|
+
updateOpportunityPhase?: any;
|
|
18
19
|
}
|
|
19
20
|
export declare const ProjectIntelligence: React.FC<ProjectIntelligenceProps>;
|
|
20
21
|
export {};
|
|
@@ -32,7 +32,8 @@ const TeamSection_1 = require("./TeamSection");
|
|
|
32
32
|
const ProjectHealth_1 = require("./ProjectHealth");
|
|
33
33
|
const KeyMetrics_1 = require("./KeyMetrics");
|
|
34
34
|
const MissingInformation_1 = require("./MissingInformation");
|
|
35
|
-
const
|
|
35
|
+
const utils_1 = require("../shared/utils");
|
|
36
|
+
const ProjectIntelligence = ({ checkIfOpportunityInsightsExistData, opportunityInsightsData, selectedOpportunityId, setSelectedOpportunityId, GetOpportunityInsightsDocument, updateOpportunityMissingInformation, documentCenterController = null, updateOpportunityFocusArea, isInternal = false, handleRouteToDocuments, onSaveFocusArea, onSaveMissingInformation, isParoIntelligenceRolePresent = false, updateOpportunityPhase, }) => {
|
|
36
37
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10;
|
|
37
38
|
const [isLoading, setIsLoading] = (0, react_1.useState)(false);
|
|
38
39
|
const [currentPhase, setCurrentPhase] = (0, react_1.useState)('Setup');
|
|
@@ -128,76 +129,20 @@ const ProjectIntelligence = ({ checkIfOpportunityInsightsExistData, opportunityI
|
|
|
128
129
|
// Handle moving to the next stage
|
|
129
130
|
const handleMoveToNextStage = () => {
|
|
130
131
|
setIsLoading(true);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
id: 'next-focus-1',
|
|
135
|
-
title: 'Clean up prior accounting periods',
|
|
136
|
-
description: 'Review and bring the company\'s books up-to-date for all prior accounting periods before the project start date. This includes entering invoices, applying payments, entering bills, categorizing transactions, and reconciling accounts test',
|
|
137
|
-
status: 'CONFIRMED',
|
|
138
|
-
dueDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), // 7 days from now
|
|
139
|
-
priority: 'HIGH'
|
|
132
|
+
updateOpportunityPhase({
|
|
133
|
+
variables: {
|
|
134
|
+
opportunityId: selectedOpportunityId
|
|
140
135
|
},
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
status: 'CONFIRMED',
|
|
146
|
-
dueDate: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString(), // 14 days from now
|
|
147
|
-
priority: 'MEDIUM'
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
id: 'next-focus-3',
|
|
151
|
-
title: 'Transition to new accounting system',
|
|
152
|
-
description: 'Assist in preparing the books and migrating data to the company\'s new front-end accounting system once implemented.',
|
|
153
|
-
status: 'CONFIRMED',
|
|
154
|
-
dueDate: new Date(Date.now() + 10 * 24 * 60 * 60 * 1000).toISOString(), // 10 days from now
|
|
155
|
-
priority: 'HIGH'
|
|
156
|
-
}
|
|
157
|
-
];
|
|
158
|
-
// Carry over missing information that doesn't have CLIENT_RESPONDED status
|
|
159
|
-
const carriedOverMissingInfo = (opportunityInsights === null || opportunityInsights === void 0 ? void 0 : opportunityInsights.missingInformation)
|
|
160
|
-
? opportunityInsights.missingInformation
|
|
161
|
-
.filter((item) => (item === null || item === void 0 ? void 0 : item.status) !== 'CLIENT_RESPONDED')
|
|
162
|
-
.map((item, index) => (Object.assign(Object.assign({}, item), { id: `carried-${item.id || index}` })))
|
|
163
|
-
: [];
|
|
164
|
-
// Add new missing information items
|
|
165
|
-
const newMissingInfo = [
|
|
166
|
-
{
|
|
167
|
-
id: 'new-missing-1',
|
|
168
|
-
title: 'Financial Transaction History',
|
|
169
|
-
description: 'Need access to the last 6 months of financial transaction history for the project',
|
|
170
|
-
priority: 'HIGH',
|
|
171
|
-
category: 'Financial',
|
|
172
|
-
status: 'PENDING'
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
id: 'new-missing-2',
|
|
176
|
-
title: 'Budget Approval Documentation',
|
|
177
|
-
description: 'Require documentation showing approval of the current budget allocation',
|
|
178
|
-
priority: 'MEDIUM',
|
|
179
|
-
category: 'Documentation',
|
|
180
|
-
status: 'PENDING'
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
id: 'new-missing-3',
|
|
184
|
-
title: 'Financial Stakeholder Contact Information',
|
|
185
|
-
description: 'Need contact details for all financial stakeholders involved in the project',
|
|
186
|
-
priority: 'LOW',
|
|
187
|
-
category: 'Contact',
|
|
188
|
-
status: 'PENDING'
|
|
189
|
-
}
|
|
190
|
-
];
|
|
191
|
-
// Set the next stage data
|
|
192
|
-
setNextStageData({
|
|
193
|
-
focusAreas: nextStageFocusAreas,
|
|
194
|
-
missingInformation: [...carriedOverMissingInfo, ...newMissingInfo]
|
|
195
|
-
});
|
|
196
|
-
// Simulate loading and then update the UI
|
|
197
|
-
setTimeout(() => {
|
|
198
|
-
setCurrentPhase('Active');
|
|
136
|
+
refetchQueries: [
|
|
137
|
+
{ query: GetOpportunityInsightsDocument, variables: { opportunityId: selectedOpportunityId } }
|
|
138
|
+
]
|
|
139
|
+
}).then(() => {
|
|
199
140
|
setIsLoading(false);
|
|
200
|
-
}
|
|
141
|
+
}).catch((error) => {
|
|
142
|
+
setIsLoading(false);
|
|
143
|
+
console.error('Error updating opportunity phase:', error);
|
|
144
|
+
(0, utils_1.showToast)('warning', 'Error updating opportunity phase. Please try again.');
|
|
145
|
+
});
|
|
201
146
|
};
|
|
202
147
|
const hasNoProjectIntelligence = !(checkIfOpportunityInsightsExistData === null || checkIfOpportunityInsightsExistData === void 0 ? void 0 : checkIfOpportunityInsightsExistData.checkIfOpportunityInsightsExist) ||
|
|
203
148
|
checkIfOpportunityInsightsExistData.checkIfOpportunityInsightsExist.length === 0;
|
|
@@ -365,11 +365,10 @@ const generateUUID = () => {
|
|
|
365
365
|
exports.generateUUID = generateUUID;
|
|
366
366
|
const processDocs = (docs) => {
|
|
367
367
|
return docs
|
|
368
|
-
.filter(doc => doc
|
|
368
|
+
.filter(doc => doc != null && doc !== '' && doc !== 'NULL')
|
|
369
369
|
.flatMap(doc => doc.split(','))
|
|
370
370
|
.map(doc => doc.trim())
|
|
371
|
-
|
|
372
|
-
.filter(doc => doc !== '' || doc !== "NULL");
|
|
371
|
+
.filter(doc => doc !== '' && doc !== 'NULL');
|
|
373
372
|
};
|
|
374
373
|
exports.processDocs = processDocs;
|
|
375
374
|
exports.sharedUtils = { selectedServicesReducer: exports.selectedServicesReducer };
|