@paro.io/expert-shared-components 1.13.7 → 1.13.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.
Files changed (23) hide show
  1. package/lib/components/Escalations/AccountSuspensionBanner.d.ts +6 -2
  2. package/lib/components/Escalations/AccountSuspensionBanner.js +59 -5
  3. package/lib/components/Escalations/AccountSuspensionModal.js +2 -2
  4. package/lib/components/Escalations/EscalationIssueCard.js +22 -15
  5. package/lib/components/Escalations/EscalationReportBanner.d.ts +2 -1
  6. package/lib/components/Escalations/EscalationReportBanner.js +7 -2
  7. package/lib/components/Escalations/EscalationRespondForm.d.ts +10 -0
  8. package/lib/components/Escalations/EscalationRespondForm.js +22 -3
  9. package/lib/components/Escalations/EscalationSubmitForm.js +39 -15
  10. package/lib/components/Escalations/EscalationTabsContent.js +18 -7
  11. package/lib/components/Escalations/Escalations.d.ts +2 -1
  12. package/lib/components/Escalations/Escalations.js +17 -10
  13. package/lib/components/Escalations/MarkResolvedModal.js +16 -1
  14. package/lib/components/Escalations/ViewResponseModal.js +7 -5
  15. package/lib/components/ExpertProfileHeader/EarningsSection.d.ts +1 -0
  16. package/lib/components/ExpertProfileHeader/EarningsSection.js +6 -4
  17. package/lib/components/ExpertProfileHeader/ExpertProfileHeader.d.ts +3 -1
  18. package/lib/components/ExpertProfileHeader/ExpertProfileHeader.js +4 -4
  19. package/lib/components/ExpertProfileHeader/ExpertStatusCalculator.d.ts +1 -1
  20. package/lib/components/ExpertProfileHeader/ExpertStatusCalculator.js +14 -3
  21. package/lib/components/ExpertProfileHeader/NetworkSection.d.ts +3 -1
  22. package/lib/components/ExpertProfileHeader/NetworkSection.js +49 -3
  23. package/package.json +1 -1
@@ -1,5 +1,9 @@
1
- declare const AccountSuspensionBanner: ({ setShowSuspensionModal, suspended }: {
1
+ export declare const suspensionLevels: {
2
+ value: string;
3
+ label: string;
4
+ }[];
5
+ declare const AccountSuspensionBanner: ({ setShowSuspensionModal, escalationDisputeStatistics, }: {
2
6
  setShowSuspensionModal: (showSuspensionModal: boolean) => void;
3
- suspended: boolean;
7
+ escalationDisputeStatistics: any;
4
8
  }) => JSX.Element;
5
9
  export default AccountSuspensionBanner;
@@ -3,17 +3,63 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.suspensionLevels = void 0;
6
7
  const react_1 = __importDefault(require("react"));
7
8
  const base_icons_1 = require("@paro.io/base-icons");
8
9
  const base_ui_1 = require("@paro.io/base-ui");
9
- const AccountSuspensionBanner = ({ setShowSuspensionModal, suspended = false }) => {
10
- return (react_1.default.createElement("div", { className: "bg-[#EF5360] rounded-lg p-4 mb-6 shadow-lg" }, suspended ?
10
+ const dayjs_1 = __importDefault(require("dayjs"));
11
+ exports.suspensionLevels = [
12
+ { value: "LEVEL_1", label: "Low" },
13
+ { value: "LEVEL_2", label: "Medium" },
14
+ { value: "LEVEL_3", label: "High" },
15
+ { value: "LEVEL_4", label: "Critical" },
16
+ ];
17
+ const getSuspensionDuration = (label) => {
18
+ switch (label) {
19
+ case "Medium":
20
+ return "30 days";
21
+ case "High":
22
+ return "60 days";
23
+ case "Critical":
24
+ return "Permanent";
25
+ case "Low":
26
+ default:
27
+ return "Low";
28
+ }
29
+ };
30
+ const AccountSuspensionBanner = ({ setShowSuspensionModal, escalationDisputeStatistics, }) => {
31
+ var _a, _b, _c, _d, _e, _f, _g;
32
+ const suspensionLevel = (_b = (_a = exports.suspensionLevels.find((obj) => obj.value === escalationDisputeStatistics.suspensionLevel)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : "Low";
33
+ const suspensionStartDate = (_c = (0, dayjs_1.default)(escalationDisputeStatistics.suspensionStartDate).format("MM/DD/YYYY")) !== null && _c !== void 0 ? _c : "N/A";
34
+ const suspensionEndDate = (_d = (0, dayjs_1.default)(escalationDisputeStatistics.suspensionEndDate).format("MM/DD/YYYY")) !== null && _d !== void 0 ? _d : "N/A";
35
+ const mediumWarnings = (_e = escalationDisputeStatistics.mediumSeverityEscalationCount) !== null && _e !== void 0 ? _e : 0;
36
+ const highWarnings = (_f = escalationDisputeStatistics.highSeverityEscalationCount) !== null && _f !== void 0 ? _f : 0;
37
+ const criticalWarnings = (_g = escalationDisputeStatistics.criticalSeverityEscalationCount) !== null && _g !== void 0 ? _g : 0;
38
+ return (react_1.default.createElement("div", { className: "bg-[#EF5360] rounded-lg p-4 mb-6 shadow-lg" }, suspensionLevel !== "Low" ?
11
39
  react_1.default.createElement("div", { className: "flex items-center" },
12
40
  react_1.default.createElement("div", { className: "bg-white bg-opacity-20 rounded-full p-2 mr-3" },
13
41
  react_1.default.createElement(base_icons_1.IconExclamation, { className: "h-6 w-6 text-white" })),
14
42
  react_1.default.createElement("div", { className: "flex-1" },
15
- react_1.default.createElement("h3", { className: "text-lg font-bold text-white" }, "\uD83D\uDEAB Account Suspended"),
16
- react_1.default.createElement("p", { className: "text-red-100 text-sm mt-1" }, "Your account has been suspended due to an escalation. You must complete comprehensive training to regain access to new opportunities.")))
43
+ react_1.default.createElement("h3", { className: "text-lg font-bold text-white" }, "\uD83D\uDEAB Account Suspended due to: Engagement Issues"),
44
+ react_1.default.createElement("p", { className: "text-red-100 text-sm mt-1" },
45
+ "Your account has been suspended due to to engagement issues. if you have any problems with the suspension, please go to the Engagement Support section to respond to your issues or reach out to",
46
+ ' ',
47
+ react_1.default.createElement("a", { href: "mailto:expertsupport@paro.io", className: "underline text-white hover:text-red-200 cursor-pointer" }, "expertsupport@paro.io"),
48
+ "."),
49
+ react_1.default.createElement("div", { className: "mt-3 bg-white bg-opacity-10 rounded p-3" },
50
+ react_1.default.createElement("div", { className: "flex items-center justify-between text-sm" },
51
+ react_1.default.createElement("div", null,
52
+ react_1.default.createElement("span", { className: "text-red-100" }, "Suspension: "),
53
+ react_1.default.createElement("span", { className: "text-white font-medium" },
54
+ getSuspensionDuration(suspensionLevel),
55
+ ' ',
56
+ suspensionLevel)),
57
+ react_1.default.createElement("div", null,
58
+ react_1.default.createElement("span", { className: "text-red-100" }, "Suspension Started Date: "),
59
+ react_1.default.createElement("span", { className: "text-white font-medium" }, suspensionStartDate)),
60
+ react_1.default.createElement("div", null,
61
+ react_1.default.createElement("span", { className: "text-red-100" }, "Suspension End Date: "),
62
+ react_1.default.createElement("span", { className: "text-white font-medium" }, suspensionEndDate))))))
17
63
  :
18
64
  react_1.default.createElement("div", { className: "flex items-center justify-between" },
19
65
  react_1.default.createElement("div", { className: "flex items-center" },
@@ -21,7 +67,15 @@ const AccountSuspensionBanner = ({ setShowSuspensionModal, suspended = false })
21
67
  react_1.default.createElement(base_icons_1.IconExclamation, { className: "h-6 w-6 text-white" })),
22
68
  react_1.default.createElement("div", null,
23
69
  react_1.default.createElement("h3", { className: "text-lg font-bold text-white" }, "Account Suspension Risk"),
24
- react_1.default.createElement("p", { className: "text-red-100 text-sm mt-1" }, "Unresolved escalations can lead to automatic suspension. Response times matter for client satisfaction."))),
70
+ react_1.default.createElement("p", { className: "text-red-100 text-sm mt-1" }, "Unresolved escalations can lead to automatic suspension. Response times matter for client satisfaction."),
71
+ react_1.default.createElement("div", { className: "flex items-center mt-2 text-red-100 text-xs" },
72
+ react_1.default.createElement("span", null,
73
+ mediumWarnings,
74
+ "/3 warnings: Medium = 30 days \u2022 ",
75
+ highWarnings,
76
+ "/2 warnings: High = 60 days \u2022 ",
77
+ criticalWarnings,
78
+ "/1 offense: Critical = Permanent")))),
25
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-danger text-danger-dark hover:text-white" }))));
26
80
  };
27
81
  exports.default = AccountSuspensionBanner;
@@ -29,7 +29,7 @@ const AccountSuspensionModal = ({ showSuspensionModal, onClose }) => {
29
29
  react_1.default.createElement(base_icons_1.IconCheckCircle, { className: "h-5 w-5 text-white" })),
30
30
  react_1.default.createElement("div", { className: "flex-1 pb-8" },
31
31
  react_1.default.createElement("div", { className: "flex justify-between items-start mb-2" },
32
- react_1.default.createElement("h4", { className: "font-semibold text-green-800" }, "Level 1: Light Issues"),
32
+ react_1.default.createElement("h4", { className: "font-semibold text-green-800" }, "Level 1: Low Issues"),
33
33
  react_1.default.createElement("div", { className: "text-xs bg-green-100 text-green-700 px-2 py-1 rounded-full" }, "Coaching Only")),
34
34
  react_1.default.createElement("p", { className: "text-sm text-gray-600 mb-2" }, "Email coaching and guidance. No account restrictions."),
35
35
  react_1.default.createElement("div", { className: "text-xs text-gray-500" },
@@ -104,7 +104,7 @@ const AccountSuspensionModal = ({ showSuspensionModal, onClose }) => {
104
104
  react_1.default.createElement("div", { className: "mt-6 bg-gray-50 rounded-lg p-4" },
105
105
  react_1.default.createElement("h4", { className: "font-medium text-gray-900 mb-2" }, "Important Reminders"),
106
106
  react_1.default.createElement("ul", { className: "text-sm text-gray-600 space-y-1" },
107
- react_1.default.createElement("li", null, "\u2022 All escalations are tracked and contribute to your warning count"),
107
+ react_1.default.createElement("li", null, "\u2022 All issues are tracked and contribute to your warning count"),
108
108
  react_1.default.createElement("li", null, "\u2022 Training completion is required before suspension can be lifted"),
109
109
  react_1.default.createElement("li", null, "\u2022 Warnings are cumulative across all severity levels"),
110
110
  react_1.default.createElement("li", null, "\u2022 All actions are logged and affect your expert rating")))))));
@@ -69,24 +69,19 @@ const EscalationIssueCard = ({ issues, isExpert, openEscalationChat, showRespond
69
69
  return "View Response";
70
70
  }
71
71
  else {
72
- return issue.expertResponse ? "View Response" : "Awaiting Response";
72
+ return issue.expertResponse || issue.clientResponse ? "View Response" : "Awaiting Response";
73
73
  }
74
74
  }
75
75
  if (userTypeId === 1) { // Submitted by Expert
76
76
  if (isExpert) {
77
- return issue.clientResponse ? "View Response" : "Awaiting Response";
77
+ return issue.clientResponse || issue.expertResponse ? "View Response" : "Awaiting Response";
78
78
  }
79
79
  else {
80
80
  return "View Response";
81
81
  }
82
82
  }
83
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
- }
84
+ return issue.clientResponse || issue.expertResponse ? "View Response" : "Awaiting Response";
90
85
  }
91
86
  return "Awaiting Response";
92
87
  };
@@ -94,7 +89,7 @@ const EscalationIssueCard = ({ issues, isExpert, openEscalationChat, showRespond
94
89
  return react_1.default.createElement("div", null, "No issues.");
95
90
  return (react_1.default.createElement("div", { className: "space-y-4" },
96
91
  issues.map((issue) => {
97
- var _a, _b, _c, _d, _e, _f, _g;
92
+ var _a, _b, _c, _d, _e;
98
93
  const project = issue.projectDetails && Array.isArray(issue.projectDetails) && issue.projectDetails.length > 0
99
94
  ? `${(_a = issue.projectDetails[0]) === null || _a === void 0 ? void 0 : _a.projectName}${issue.projectDetails.length > 1 ? ` +${issue.projectDetails.length - 1} more` : ''} `
100
95
  : '';
@@ -104,12 +99,10 @@ const EscalationIssueCard = ({ issues, isExpert, openEscalationChat, showRespond
104
99
  react_1.default.createElement("div", { className: "flex items-center justify-between mb-3" },
105
100
  react_1.default.createElement("div", { className: "flex-1 ml-2" },
106
101
  react_1.default.createElement("div", { className: "flex flex-row justify-start gap-2" },
107
- react_1.default.createElement("div", { className: "font-bold" }, issue.problem),
102
+ react_1.default.createElement("div", { className: "font-bold" }, project),
108
103
  react_1.default.createElement(exports.CustomTag, { label: issue.severityLevel })),
109
104
  react_1.default.createElement("div", { className: "text-xs text-gray-500 font-bold" },
110
- isExpert ? (_c = (_b = issue === null || issue === void 0 ? void 0 : issue.client) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : "Client" : (_e = (_d = issue === null || issue === void 0 ? void 0 : issue.freelancer) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : 'Expert',
111
- " \u2022 ",
112
- project,
105
+ isExpert ? `${(_b = issue === null || issue === void 0 ? void 0 : issue.client) === null || _b === void 0 ? void 0 : _b.name} (Client)` : `${(_c = issue === null || issue === void 0 ? void 0 : issue.freelancer) === null || _c === void 0 ? void 0 : _c.name} (Expert)`,
113
106
  " \u2022 Case #",
114
107
  issue.escalationNumber)),
115
108
  react_1.default.createElement(exports.CustomTag, { label: issue.escalationType, customColor: `bg-[#B0B5D3] border-[#181027]` })),
@@ -117,11 +110,25 @@ const EscalationIssueCard = ({ issues, isExpert, openEscalationChat, showRespond
117
110
  react_1.default.createElement("div", { className: "flex items-center justify-between mb-2" },
118
111
  react_1.default.createElement("div", { className: "text-sm text-gray-500" },
119
112
  "Submitted by: ",
120
- react_1.default.createElement("span", { className: "font-bold" }, ((_f = issue === null || issue === void 0 ? void 0 : issue.submittedByUser) === null || _f === void 0 ? void 0 : _f.firstName) + " " + ((_g = issue === null || issue === void 0 ? void 0 : issue.submittedByUser) === null || _g === void 0 ? void 0 : _g.lastName)),
113
+ react_1.default.createElement("span", { className: "font-bold" },
114
+ ((_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),
115
+ " ",
116
+ issue.submittedByUser.userTypeId === 1 ? '(Expert)' : issue.submittedByUser.userTypeId === 2 ? '(Paro)' : '(Client)'),
121
117
  (issue === null || issue === void 0 ? void 0 : issue.createdAt) && react_1.default.createElement(react_1.default.Fragment, null,
122
118
  " \u2022 Submitted on: ",
123
119
  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"))))),
124
- react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-3" }, issue.outcome),
120
+ react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-2" },
121
+ react_1.default.createElement("span", { className: "font-bold" }, "Projects Affected:"),
122
+ " ",
123
+ issue.projectDetails.map((p) => p.projectName).join(", ")),
124
+ react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-2" },
125
+ react_1.default.createElement("span", { className: "font-bold" }, "Problem:"),
126
+ " ",
127
+ issue.problem),
128
+ react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-2" },
129
+ react_1.default.createElement("span", { className: "font-bold" }, "Desired Outcome:"),
130
+ " ",
131
+ issue.outcome),
125
132
  processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2" },
126
133
  react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
127
134
  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: () => {
@@ -1,4 +1,5 @@
1
- declare const EscalationReportBanner: ({ onReport }: {
1
+ declare const EscalationReportBanner: ({ onReport, isExpert }: {
2
2
  onReport: () => void;
3
+ isExpert: boolean;
3
4
  }) => JSX.Element;
4
5
  export default EscalationReportBanner;
@@ -6,7 +6,7 @@ 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 base_ui_1 = require("@paro.io/base-ui");
9
- const EscalationReportBanner = ({ onReport }) => {
9
+ const EscalationReportBanner = ({ onReport, isExpert }) => {
10
10
  return (react_1.default.createElement("div", { className: "bg-[#EF5360] rounded-lg p-2 mb-4 shadow-lg" },
11
11
  react_1.default.createElement("div", { className: "flex items-center justify-between" },
12
12
  react_1.default.createElement("div", { className: "flex items-center" },
@@ -14,7 +14,12 @@ const EscalationReportBanner = ({ onReport }) => {
14
14
  react_1.default.createElement(base_icons_1.IconExclamation, { className: "text-white" })),
15
15
  react_1.default.createElement("div", null,
16
16
  react_1.default.createElement("h3", { className: "text-xl font-bold text-white" }, "Having Issues with Your Expert?"),
17
- react_1.default.createElement("p", { className: "text-red-100 text-sm mt-1" }, "Report communication problems, quality concerns, or missed deadlines. We'll resolve it within 4-8 hours."))),
17
+ react_1.default.createElement("p", { className: "text-red-100 text-sm mt-1" }, isExpert ? (`Report communication problems, quality concerns, or missed deadlines. We'll resolve it within 4-8 hours.`) : (react_1.default.createElement(react_1.default.Fragment, null,
18
+ "Report communication problems, quality concerns, or missed deadlines. All issues right now will be submitted to the Expert and Paro. If you want to submit issues directly to Paro please email",
19
+ ' ',
20
+ react_1.default.createElement("a", { href: "mailto:clientsupport@paro.io", className: "underline text-white hover:text-red-200 cursor-pointer" }, "clientsupport@paro.io"),
21
+ ' ',
22
+ "or your Account Executive."))))),
18
23
  react_1.default.createElement(base_ui_1.Button, { label: "Report issue now", onClick: onReport, size: "sm", color: "danger", className: "bg-white hover:bg-danger text-danger-dark hover:text-white" }))));
19
24
  };
20
25
  exports.default = EscalationReportBanner;
@@ -1,5 +1,15 @@
1
1
  export declare const ACCEPTED_FILE_TYPES: string[];
2
2
  export declare const validateFileUpload: (file: File | null) => boolean;
3
+ export declare const clientResponseTypes: {
4
+ label: string;
5
+ description: string;
6
+ value: string;
7
+ }[];
8
+ export declare const expertResponseTypes: {
9
+ label: string;
10
+ description: string;
11
+ value: string;
12
+ }[];
3
13
  declare const EscalationRespondForm: ({ goBack, selectedIssue, documentUploadUrl, downloadDocumentUrl, uploadExpertClientFiles, updateProjectEscalation, bucketName, goHome, isExpert, userId, }: {
4
14
  goBack: () => void;
5
15
  selectedIssue: any;
@@ -32,7 +32,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
32
32
  });
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.validateFileUpload = exports.ACCEPTED_FILE_TYPES = void 0;
35
+ exports.expertResponseTypes = exports.clientResponseTypes = exports.validateFileUpload = exports.ACCEPTED_FILE_TYPES = void 0;
36
36
  const react_1 = __importStar(require("react"));
37
37
  const base_icons_1 = require("@paro.io/base-icons");
38
38
  const base_ui_1 = require("@paro.io/base-ui");
@@ -58,7 +58,7 @@ const validateFileUpload = (file) => {
58
58
  return true;
59
59
  };
60
60
  exports.validateFileUpload = validateFileUpload;
61
- const responseTypes = [
61
+ exports.clientResponseTypes = [
62
62
  {
63
63
  label: "Acknowledge issue and provide resolution plan",
64
64
  description: "Explain circumstances and apologize",
@@ -66,7 +66,7 @@ const responseTypes = [
66
66
  },
67
67
  {
68
68
  label: "Dispute issue and provide counter-evidence",
69
- description: "Challenge the client's concerns with documentation",
69
+ description: "Challenge the expert's concerns with documentation",
70
70
  value: "Disputed",
71
71
  },
72
72
  {
@@ -75,7 +75,25 @@ const responseTypes = [
75
75
  value: "NoResponse",
76
76
  },
77
77
  ];
78
+ exports.expertResponseTypes = [
79
+ {
80
+ label: "Acknowledge issue and provide resolution plan",
81
+ description: "Explain circumstances and apologize",
82
+ value: "Acknowledged",
83
+ },
84
+ {
85
+ label: "Challenge the client's concerns with documentation",
86
+ description: "Challenge the client's concerns with documentation",
87
+ value: "NeedsHelp",
88
+ },
89
+ {
90
+ label: "Request clarification",
91
+ description: "Ask for more details about the issue",
92
+ value: "NoResponse",
93
+ },
94
+ ];
78
95
  const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downloadDocumentUrl, uploadExpertClientFiles, updateProjectEscalation, bucketName, goHome, isExpert, userId, }) => {
96
+ const responseTypes = isExpert ? exports.expertResponseTypes : exports.clientResponseTypes;
79
97
  const [selectedType, setSelectedType] = (0, react_1.useState)(responseTypes[0].value);
80
98
  const [responseInput, setResponseInput] = (0, react_1.useState)('');
81
99
  const [uploadFiles, setUploadFiles] = (0, react_1.useState)([]);
@@ -149,6 +167,7 @@ const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downl
149
167
  variables: {
150
168
  input: {
151
169
  escalationId: selectedIssue.escalationId,
170
+ [isExpert ? 'expertResponseType' : 'clientResponseType']: selectedType,
152
171
  [isExpert ? 'expertResponse' : 'clientResponse']: responseInput,
153
172
  [isExpert ? 'expertSupportingDocuments' : 'clientSupportingDocuments']: uploadFiles.length > 0 ? uploadFiles.join(", ") : '',
154
173
  statusChangedBy: userId,
@@ -44,6 +44,7 @@ const dayjs_1 = __importDefault(require("dayjs"));
44
44
  const EscalationRespondForm_1 = require("./EscalationRespondForm");
45
45
  const FileUploader_1 = require("../FileUploader");
46
46
  const utils_1 = require("../shared/utils");
47
+ const EscalationIssueCard_1 = require("./EscalationIssueCard");
47
48
  const issueTypeOptions = [
48
49
  { value: 'CommunicationIssues', label: 'Communication Issues' },
49
50
  { value: 'Professionalism', label: 'Professionalism' },
@@ -176,7 +177,7 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
176
177
  escalationId: escalationId,
177
178
  freelancerId: isExpert ? user.userId : selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.id,
178
179
  clientId: isExpert ? selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.id : clientId,
179
- projectDetails: selectedProjects.map((p) => { return { projectId: p.id, projectName: p.name }; }),
180
+ projectDetails: selectedProjects.filter((p) => p !== undefined).map((p) => { return { projectId: p.id, projectName: p.name }; }),
180
181
  issueStartDate: issueStartDate,
181
182
  escalationType: issueType,
182
183
  severityLevel: severity,
@@ -219,18 +220,27 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
219
220
  react_1.default.createElement("h2", { className: "text-xl font-bold" },
220
221
  "Report Issue with Your ",
221
222
  isExpert ? 'Client' : 'Expert'),
222
- react_1.default.createElement("p", { className: "text-gray-600 mt-1" }, "Provide details about the issue you're experiencing and we'll resolve it within 4-8 hours")),
223
- react_1.default.createElement("div", { className: "bg-red-50 border border-red-200 rounded-lg p-4 mb-6" },
224
- react_1.default.createElement("div", { className: "flex items-start" },
225
- react_1.default.createElement("span", { className: "mr-3" }, "!"),
226
- react_1.default.createElement("div", null,
227
- react_1.default.createElement("p", { className: "font-medium text-red-800" }, "Common Issues We Can Help With"),
228
- react_1.default.createElement("ul", { className: "mt-1 text-sm text-red-700 list-disc list-inside space-y-1" },
229
- react_1.default.createElement("li", null, `Communication delays (${isExpert ? 'client' : 'expert'} not responding)`),
230
- !isExpert && react_1.default.createElement("li", null, "Missed deadlines or project delays"),
231
- !isExpert && react_1.default.createElement("li", null, "Quality concerns with deliverables"),
232
- react_1.default.createElement("li", null, "Scope changes or unexpected requests"),
233
- react_1.default.createElement("li", null, "Billing or payment disputes"))))),
223
+ react_1.default.createElement("p", { className: "text-gray-600 mt-1" }, isExpert ? (`Provide details about the issue you're experiencing and we'll resolve it within 4-8 hours</p>`) : (react_1.default.createElement(react_1.default.Fragment, null,
224
+ "Report communication problems, quality concerns, or missed deadlines. All issues right now will be submitted to the Expert and Paro. If you want to submit issues directly to Paro please email",
225
+ ' ',
226
+ react_1.default.createElement("a", { href: "mailto:clientsupport@paro.io", className: "underline text-white hover:text-red-200 cursor-pointer" }, "clientsupport@paro.io"),
227
+ ' ',
228
+ "or your Account Executive.")))),
229
+ react_1.default.createElement("div", null,
230
+ react_1.default.createElement("h4", { className: "font-medium text-gray-900 mb-2" }, "Priority Levels for Issues"),
231
+ react_1.default.createElement("div", { className: "space-y-2 text-sm" },
232
+ react_1.default.createElement("div", { className: "flex items-center gap-x-2" },
233
+ react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: "Critical" }),
234
+ react_1.default.createElement("span", null, "All deliverables are currently blocked; the project cannot move forward.")),
235
+ react_1.default.createElement("div", { className: "flex items-center gap-x-2" },
236
+ react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: "High" }),
237
+ react_1.default.createElement("span", null, "Key deliverables are blocked, preventing meaningful progress.")),
238
+ react_1.default.createElement("div", { className: "flex items-center gap-x-2" },
239
+ react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: "Medium" }),
240
+ react_1.default.createElement("span", null, "Deliverables are still in progress, but timelines are at risk.")),
241
+ react_1.default.createElement("div", { className: "flex items-center gap-x-2" },
242
+ react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: "Low" }),
243
+ react_1.default.createElement("span", null, "Minor issue or inconvenience that does not affect overall project flow.")))),
234
244
  react_1.default.createElement("div", { className: "border rounded-lg overflow-hidden mb-6" },
235
245
  react_1.default.createElement("div", { className: "bg-gray-50 p-3 border-b" },
236
246
  react_1.default.createElement("h3", { className: "font-medium" }, "Issue Details")),
@@ -263,10 +273,24 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
263
273
  .filter(opt => selected.includes(opt.value))
264
274
  .map(opt => opt.label)
265
275
  .join(', ');
266
- }, placeholder: `Select Project(s)` },
276
+ }, placeholder: `Select Project(s)`, MenuProps: {
277
+ PaperProps: {
278
+ style: {
279
+ maxHeight: 300,
280
+ },
281
+ },
282
+ } },
267
283
  react_1.default.createElement(core_1.MenuItem, { disabled: true, value: "" },
268
284
  react_1.default.createElement("em", null, "Select Project(s)...")),
269
- projectOptions.map(option => (react_1.default.createElement(core_1.MenuItem, { key: option.value.id, value: option.value }, option.label))))),
285
+ projectOptions.map(option => (react_1.default.createElement(core_1.MenuItem, { key: option.value.id, value: option.value }, option.label))),
286
+ react_1.default.createElement(core_1.MenuItem, { disableRipple: true, disableGutters: true },
287
+ react_1.default.createElement(base_ui_1.Button, { label: "save & continue", className: "mx-4", color: "primary", onClick: (e) => {
288
+ const menu = e.target.closest('[role="presentation"]');
289
+ if (menu) {
290
+ const escEvent = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true });
291
+ menu.dispatchEvent(escEvent);
292
+ }
293
+ } })))),
270
294
  react_1.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" },
271
295
  react_1.default.createElement("div", null,
272
296
  react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" }, "Issue Type"),
@@ -58,24 +58,35 @@ const EscalationTabsContent = ({ activeTab, openEscalationChat, setSelectedIssue
58
58
  react_1.default.createElement("div", { className: "flex items-start" },
59
59
  react_1.default.createElement("div", null,
60
60
  react_1.default.createElement("div", { className: "flex flex-row justify-start items-center mb-3" },
61
- react_1.default.createElement("h4", { className: "font-medium text-gray-900 mb-1 mr-4" }, issue.problem),
61
+ react_1.default.createElement("h4", { className: "font-medium text-gray-900 mb-1 mr-4" }, project),
62
62
  react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: issue.severityLevel })),
63
63
  react_1.default.createElement("div", { className: "flex items-center text-sm text-gray-600 mb-2" },
64
- react_1.default.createElement("span", null, issue.submittedByUser.firstName + " " + issue.submittedByUser.lastName),
65
- react_1.default.createElement("span", { className: "mx-2" }, "\u2022"),
66
- react_1.default.createElement("span", null, project),
64
+ react_1.default.createElement("span", null,
65
+ "Submitted By: ",
66
+ issue.submittedByUser.firstName + " " + issue.submittedByUser.lastName),
67
67
  react_1.default.createElement("span", { className: "mx-2" }, "\u2022"),
68
68
  react_1.default.createElement("span", null,
69
69
  "Case #",
70
70
  issue.escalationNumber)),
71
- react_1.default.createElement("p", { className: "text-sm text-gray-600 mb-3" }, issue.internalResolution ? issue.internalResolution : isExpert ? issue.clientResolution : issue.expertResolution),
71
+ react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-2" },
72
+ react_1.default.createElement("span", { className: "font-bold" }, "Problem:"),
73
+ " ",
74
+ issue.problem),
75
+ react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-2" },
76
+ react_1.default.createElement("span", { className: "font-bold" }, "Desired Outcome:"),
77
+ " ",
78
+ issue.outcome),
79
+ react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-2" },
80
+ react_1.default.createElement("span", { className: "font-bold" }, "Resolution:"),
81
+ " ",
82
+ issue.internalResolution ? issue.internalResolution : issue.clientResolution),
72
83
  react_1.default.createElement("div", { className: "flex items-center text-sm text-gray-600 mb-2" },
73
84
  react_1.default.createElement("span", { className: "text-xs text-gray-500" },
74
- "Resolved ",
85
+ "Resolved: ",
75
86
  (0, dayjs_1.default)(issue.updatedAt).format("MM-DD-YYYY")),
76
87
  react_1.default.createElement("span", { className: "mx-2" }, "\u2022"),
77
88
  react_1.default.createElement("span", { className: "text-xs text-gray-500" },
78
- "Resolved By ",
89
+ "Resolved By: ",
79
90
  issue.statusChangedByUser.firstName + " " + issue.statusChangedByUser.lastName,
80
91
  " ",
81
92
  issue.statusChangedByUser.userTypeId === 2 && '(Paro)')))),
@@ -12,6 +12,7 @@ interface EscalationsProps {
12
12
  bucketName: string;
13
13
  user: any;
14
14
  clientId?: number;
15
+ escalationDisputeStatistics?: any;
15
16
  }
16
- export declare const Escalations: ({ expertsOrClients, projects, isExpert, escalations, documentUploadUrl, downloadDocumentUrl, uploadExpertClientFiles, createProjectEscalation, updateProjectEscalation, createEscalationChatMessage, bucketName, user, clientId, }: EscalationsProps) => JSX.Element;
17
+ export declare const Escalations: ({ expertsOrClients, projects, isExpert, escalations, documentUploadUrl, downloadDocumentUrl, uploadExpertClientFiles, createProjectEscalation, updateProjectEscalation, createEscalationChatMessage, bucketName, user, clientId, escalationDisputeStatistics, }: EscalationsProps) => JSX.Element;
17
18
  export {};
@@ -40,7 +40,7 @@ const AccountSuspensionModal_1 = __importDefault(require("./AccountSuspensionMod
40
40
  const base_icons_1 = require("@paro.io/base-icons");
41
41
  const EscalationIssueCard_1 = require("./EscalationIssueCard");
42
42
  const react_hot_toast_1 = require("react-hot-toast");
43
- const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations, documentUploadUrl, downloadDocumentUrl, uploadExpertClientFiles, createProjectEscalation, updateProjectEscalation, createEscalationChatMessage, bucketName, user, clientId = 0, }) => {
43
+ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations, documentUploadUrl, downloadDocumentUrl, uploadExpertClientFiles, createProjectEscalation, updateProjectEscalation, createEscalationChatMessage, bucketName, user, clientId = 0, escalationDisputeStatistics, }) => {
44
44
  const [activeSection, setActiveSection] = (0, react_1.useState)('support');
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
@@ -53,13 +53,20 @@ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations
53
53
  const userTypeId = (_a = issue === null || issue === void 0 ? void 0 : issue.submittedByUser) === null || _a === void 0 ? void 0 : _a.userTypeId;
54
54
  const internalEscalationTo = issue === null || issue === void 0 ? void 0 : issue.internalEscalationTo;
55
55
  const status = issue === null || issue === void 0 ? void 0 : issue.status;
56
- // Determine if this issue should be shown to the current user
57
- const isRelevantEscalation = (isExpert
58
- ? (internalEscalationTo === 'expert' || internalEscalationTo === 'both')
59
- : (internalEscalationTo === 'client' || internalEscalationTo === 'both'));
60
- return (((userTypeId !== user.userTypeId && (isExpert ? issue.expertResponse === null : issue.clientResponse === null)) || //once responded will move to inProgress from active issues
61
- (userTypeId === 2 && isRelevantEscalation)) &&
62
- status === 'InProgress');
56
+ const isDifferentUserType = userTypeId !== user.userTypeId;
57
+ const isPendingResponse = isExpert
58
+ ? issue.expertResponse === null
59
+ : issue.clientResponse === null;
60
+ const isValidInternalEscalation = userTypeId === 2
61
+ ? (isExpert
62
+ ? internalEscalationTo !== "client" // expert should NOT see escalations to client
63
+ : internalEscalationTo !== "expert") // client should NOT see escalations to expert
64
+ : userTypeId !== user.userTypeId;
65
+ const shouldInclude = isDifferentUserType &&
66
+ isPendingResponse &&
67
+ isValidInternalEscalation &&
68
+ status === 'InProgress';
69
+ return shouldInclude;
63
70
  });
64
71
  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'; });
65
72
  const resolvedIssues = escalations.filter(issue => (issue === null || issue === void 0 ? void 0 : issue.status) === 'Resolved');
@@ -149,9 +156,9 @@ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations
149
156
  react_1.default.createElement("p", { className: "text-xs" }, "Report payment, scope, or communication activeIssues")))),
150
157
  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" }))),
151
158
  isExpert &&
152
- react_1.default.createElement(AccountSuspensionBanner_1.default, { setShowSuspensionModal: setShowSuspensionModal, suspended: false }),
159
+ react_1.default.createElement(AccountSuspensionBanner_1.default, { setShowSuspensionModal: setShowSuspensionModal, escalationDisputeStatistics: escalationDisputeStatistics }),
153
160
  !isExpert &&
154
- react_1.default.createElement(EscalationReportBanner_1.default, { onReport: () => setSelectedIssueId(0) }),
161
+ react_1.default.createElement(EscalationReportBanner_1.default, { onReport: () => setSelectedIssueId(0), isExpert: isExpert }),
155
162
  escalations.length > 0 ? react_1.default.createElement(EscalationTabs_1.default, { activeTab: activeEscalationTab, setActiveTab: setActiveEscalationTab, activeIssues: activeIssues.length, inProgressIssues: inProgressIssues.length, resolvedIssues: resolvedIssues.length }) : null,
156
163
  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 })),
157
164
  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 })),
@@ -40,6 +40,7 @@ const utils_1 = require("../shared/utils");
40
40
  const MarkResolvedModal = ({ escalationId, expertName, open, onClose, updateProjectEscalation, userId, }) => {
41
41
  const [resolutionText, setResolutionText] = (0, react_1.useState)(null);
42
42
  const [submitting, setSubmitting] = (0, react_1.useState)(false);
43
+ const [expertResponsibility, setExpertResponsibility] = (0, react_1.useState)('');
43
44
  const handleSubmit = () => __awaiter(void 0, void 0, void 0, function* () {
44
45
  setSubmitting(true);
45
46
  try {
@@ -50,6 +51,7 @@ const MarkResolvedModal = ({ escalationId, expertName, open, onClose, updateProj
50
51
  clientResolution: resolutionText,
51
52
  status: 'Resolved',
52
53
  statusChangedBy: userId,
54
+ isExpertAtFault: expertResponsibility === 'atFault' ? true : false,
53
55
  }
54
56
  }
55
57
  });
@@ -78,10 +80,23 @@ const MarkResolvedModal = ({ escalationId, expertName, open, onClose, updateProj
78
80
  react_1.default.createElement("div", { className: "mt-6 mb-4" },
79
81
  react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" }, "Please provide additional details before marking this issue as resolved."),
80
82
  react_1.default.createElement(base_ui_1.Input, { type: "text", value: resolutionText, placeholder: "Enter details here...", onChange: (e) => setResolutionText(e.target.value) })),
83
+ react_1.default.createElement("p", null, "Please provide additional details before marking this issue as resolved."),
84
+ react_1.default.createElement("div", { style: { marginTop: '1em', marginBottom: '1em' } },
85
+ react_1.default.createElement("label", { className: "block text-sm font-normal mb-1" },
86
+ "Expert Responsibility ",
87
+ react_1.default.createElement("span", { className: "text-sm text-red-800" }, "*")),
88
+ react_1.default.createElement("div", null,
89
+ react_1.default.createElement("label", null,
90
+ react_1.default.createElement("input", { type: "radio", name: "expertResponsibility", value: "atFault", checked: expertResponsibility === 'atFault', onChange: () => setExpertResponsibility('atFault'), required: true }),
91
+ "Expert is at fault for this issue")),
92
+ react_1.default.createElement("div", null,
93
+ react_1.default.createElement("label", null,
94
+ react_1.default.createElement("input", { type: "radio", name: "expertResponsibility", value: "notAtFault", checked: expertResponsibility === 'notAtFault', onChange: () => setExpertResponsibility('notAtFault'), required: true }),
95
+ "Expert is NOT at fault"))),
81
96
  react_1.default.createElement("div", { className: "flex items-center justify-between" },
82
97
  react_1.default.createElement("div", { className: "flex space-x-2" },
83
98
  react_1.default.createElement(base_ui_1.Button, { label: "Cancel", onClick: onClose, disabled: submitting })),
84
99
  react_1.default.createElement("div", { className: "flex space-x-2" },
85
- react_1.default.createElement(base_ui_1.Button, { label: "Submit", color: "primary", onClick: handleSubmit, isLoading: submitting }))))));
100
+ react_1.default.createElement(base_ui_1.Button, { label: "Submit", color: "primary", onClick: handleSubmit, isLoading: submitting, disabled: expertResponsibility === '' }))))));
86
101
  };
87
102
  exports.default = MarkResolvedModal;
@@ -8,9 +8,14 @@ const base_icons_1 = require("@paro.io/base-icons");
8
8
  const core_1 = require("@material-ui/core");
9
9
  const utils_1 = require("../shared/utils");
10
10
  const EscalationIssueCard_1 = require("./EscalationIssueCard");
11
+ const EscalationRespondForm_1 = require("./EscalationRespondForm");
11
12
  const ViewResponseModal = ({ selectedIssue, open, onClose, isExpert }) => {
13
+ var _a, _b, _c, _d, _e;
12
14
  const docs = [selectedIssue.expertSupportingDocuments, selectedIssue.clientSupportingDocuments, selectedIssue.internalSupportingDocuments];
13
15
  const processedDocs = (0, utils_1.processDocs)(docs);
16
+ const responseType = isExpert ? (_a = selectedIssue.clientResponseType) !== null && _a !== void 0 ? _a : selectedIssue.expertResponseType : (_b = selectedIssue.expertResponseType) !== null && _b !== void 0 ? _b : selectedIssue.clientResponseType;
17
+ const responseTypeLabel = ((_c = [...new Set([...EscalationRespondForm_1.clientResponseTypes, ...EscalationRespondForm_1.expertResponseTypes])].find(opt => opt.value === responseType)) === null || _c === void 0 ? void 0 : _c.label) || responseType || "";
18
+ const response = isExpert ? (_d = selectedIssue.clientResponse) !== null && _d !== void 0 ? _d : selectedIssue.expertResponse : (_e = selectedIssue.expertResponse) !== null && _e !== void 0 ? _e : selectedIssue.clientResponse;
14
19
  return (react_1.default.createElement(core_1.Dialog, { open: open, onClose: onClose, maxWidth: 'md', PaperProps: {
15
20
  style: { minWidth: '40%' }
16
21
  } },
@@ -23,15 +28,12 @@ const ViewResponseModal = ({ selectedIssue, open, onClose, isExpert }) => {
23
28
  react_1.default.createElement(base_icons_1.IconX, null))))),
24
29
  react_1.default.createElement(core_1.DialogContent, null,
25
30
  react_1.default.createElement("div", { className: "bg-green-50 border-green-800 border border-l-4 rounded p-4 mt-4 mb-4" },
26
- react_1.default.createElement("p", { className: "text-sm font-medium" },
27
- "Status: ",
28
- react_1.default.createElement("span", { className: "font-normal" }, "Responded")),
29
31
  react_1.default.createElement("p", { className: "text-sm font-medium" },
30
32
  "Response Type: ",
31
- react_1.default.createElement("span", { className: "font-normal" }, isExpert ? selectedIssue.clientResponseType : selectedIssue.expertResponseType)),
33
+ react_1.default.createElement("span", { className: "font-normal" }, responseTypeLabel)),
32
34
  react_1.default.createElement("p", { className: "text-sm font-medium" },
33
35
  "Response: ",
34
- react_1.default.createElement("span", { className: "font-normal" }, isExpert ? selectedIssue.clientResponse : selectedIssue.expertResponse))),
36
+ react_1.default.createElement("span", { className: "font-normal" }, response))),
35
37
  processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2 mt-4 mb-2" },
36
38
  react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
37
39
  processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1], customColor: `bg-success border-success` }))))))));
@@ -16,5 +16,6 @@ interface EarningsSectionProps {
16
16
  hasCompletedProjects: boolean;
17
17
  lifetimeFSV: any;
18
18
  }
19
+ export declare const EarningsInfo: ({ label, value, textColor }: any) => JSX.Element;
19
20
  declare const EarningsSection: ({ expertServiceLinesPlus, firmTags, haveATeamProp, expertLevels, currentMonthGoalHours, expertIRPRRatio, winRate, expertIRPRRatioPrev, winRatePrev, earnings, upsell, crossSell, lifetimeIRPR, lifetimeWinRate, hasCompletedProjects, lifetimeFSV }: EarningsSectionProps) => JSX.Element;
20
21
  export default EarningsSection;
@@ -14,6 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.EarningsInfo = void 0;
17
18
  const core_1 = require("@material-ui/core");
18
19
  const styles_1 = require("@material-ui/core/styles");
19
20
  const react_1 = __importDefault(require("react"));
@@ -64,6 +65,7 @@ const FirmTags = (_a) => {
64
65
  const EarningsInfo = ({ label, value, textColor = 'black' }) => (react_1.default.createElement(core_1.Box, { mr: 2, display: "flex", justifyContent: "space-between", alignItems: "center" },
65
66
  react_1.default.createElement(core_1.Typography, { variant: "body2" }, label),
66
67
  react_1.default.createElement("b", { style: { color: textColor } }, value)));
68
+ exports.EarningsInfo = EarningsInfo;
67
69
  const DataCell = ({ label, value }) => {
68
70
  //@ts-ignore
69
71
  const classes = useStyles();
@@ -129,16 +131,16 @@ const EarningsSection = ({ expertServiceLinesPlus, firmTags, haveATeamProp, expe
129
131
  react_1.default.createElement(core_1.Box, { mb: 1 },
130
132
  react_1.default.createElement("b", null, "Expert Earnings :")),
131
133
  hasCompletedProjects ? (react_1.default.createElement(react_1.default.Fragment, null,
132
- react_1.default.createElement(EarningsInfo, { label: "Monthly Goal", value: currentMonthGoalHours > 0 ? `$ ${ToLocalStringFn(currentMonthGoalHours)}` : 'N/A' }),
134
+ react_1.default.createElement(exports.EarningsInfo, { label: "Monthly Goal", value: currentMonthGoalHours > 0 ? `$ ${ToLocalStringFn(currentMonthGoalHours)}` : 'N/A' }),
133
135
  react_1.default.createElement(core_1.Box, { mb: 2 },
134
136
  react_1.default.createElement(core_1.Divider, null)),
135
- react_1.default.createElement(EarningsInfo, { label: "Monthly Earnings", value: (earnings === null || earnings === void 0 ? void 0 : earnings.length) > 0 ? `$ ${ToLocalStringFn(earning)}` : 'N/A' }),
137
+ react_1.default.createElement(exports.EarningsInfo, { label: "Monthly Earnings", value: (earnings === null || earnings === void 0 ? void 0 : earnings.length) > 0 ? `$ ${ToLocalStringFn(earning)}` : 'N/A' }),
136
138
  react_1.default.createElement(core_1.Box, { mb: 2 },
137
139
  react_1.default.createElement(core_1.Divider, null)),
138
- react_1.default.createElement(EarningsInfo, { label: "% to Goal", value: currentMonthGoalHours && earning ? `${ToLocalStringFn(((earning / currentMonthGoalHours) * 100).toFixed(2))} %` : 'N/A' }),
140
+ react_1.default.createElement(exports.EarningsInfo, { label: "% to Goal", value: currentMonthGoalHours && earning ? `${ToLocalStringFn(((earning / currentMonthGoalHours) * 100).toFixed(2))} %` : 'N/A' }),
139
141
  react_1.default.createElement(core_1.Box, { mb: 2 },
140
142
  react_1.default.createElement(core_1.Divider, null)),
141
- react_1.default.createElement(EarningsInfo, { label: "Lifetime FSV", value: lifetimeFSV ? ToLocalStringFn(lifetimeFSV) : 'N/A', textColor: backgroundColor }),
143
+ react_1.default.createElement(exports.EarningsInfo, { label: "Lifetime FSV", value: lifetimeFSV ? ToLocalStringFn(lifetimeFSV) : 'N/A', textColor: backgroundColor }),
142
144
  react_1.default.createElement(core_1.Box, { mb: 2 },
143
145
  react_1.default.createElement(core_1.Divider, null)),
144
146
  react_1.default.createElement(ExpertStatsTable, { expertIRPRRatioPrev: expertIRPRRatioPrev, expertIRPRRatio: expertIRPRRatio, winRatePrev: winRatePrev, winRate: winRate, lifetimeIRPR: lifetimeIRPR, lifetimeWinRate: lifetimeWinRate }))) : (react_1.default.createElement(core_1.Typography, { variant: "body1" }, "This Expert has not billed yet")))));
@@ -64,6 +64,8 @@ type QueryAndMutationProps = {
64
64
  getExpertVanityTitles?: any;
65
65
  getExpertRates?: any;
66
66
  updateExpert?: any;
67
+ escalationDisputeStatistics?: any;
68
+ escalationDisputeStatisticsLoading?: any;
67
69
  };
68
70
  type ChangeEmailPasswordProps = {
69
71
  getUserByEmail?: any;
@@ -79,5 +81,5 @@ type ProfileCompletedPercentageProps = {
79
81
  handleScrollToBottom?: () => void;
80
82
  clientReferencesSectionCompleted: boolean;
81
83
  };
82
- export declare const ExpertProfileHeader: ({ expertId, legacyFreelancerId, address: addressForReducer, companyName: companyNameForReducer, legacyMetadata: legacyMetadataForReducer, legacyMetadata: { primaryServiceLine, applicationStatus }, user: userForReducer, user: { id, imageUrl, email }, firmTags, detailsSectionCompleted, clientReferencesSectionCompleted, preferenceTasks, isWhiteLabel, handleScrollToBottom, haveATeamProp, expertFirms, paroAppUrl, isExpertOps, internalUserId, getExpertByLegacyFreelancerIdDocument, createExpertPublicProfileTrackingRecord, updateFreelancerServiceLine, serviceLineLoading, serviceLineData, serviceLineError, reviewData, profileReviewError, availabilityData, nextMonthAvailabilityData, expertStatusData, expertStatusLoading, expertLevelsData, projectsData, paroProjectsLoading, expertMetricsData, expertMetricsLoading, upSellCrossSellData, upSellCrossSellLoading, projectChangeLogData, projectChangeLogLoading, updateAddressMutation, addressUpdateLoading, updateUserMutation, userUpdateLoading, updateUserError, updateFreelancerMutation, updateFreelancerLoading, updateFreelancerError, getFreelancerEarnings, getQualityKPIs, expertLevelsTrainings, trainingsDataLoading, assignLetterTrainingToExpert, assignTrainingLoading, assignTrainingError, getUserDocument, getExpertStatusDocument, uploadUserPhotoMutation, loadingNewImage, imageUpdateError, getUserByEmail, updateUserEmail, getUserByEmailLazyQuery, updateUserPassword, verifyUserPassword, openServiceLinesTemplate, setOpenServiceLinesTemplate, getExpertVanityTitles, getExpertRates, updateExpert, vanityTitle, }: SectionContents & PersonalInformationType & ProfileCompletedPercentageProps & QueryAndMutationProps & ChangeEmailPasswordProps) => JSX.Element;
84
+ export declare const ExpertProfileHeader: ({ expertId, legacyFreelancerId, address: addressForReducer, companyName: companyNameForReducer, legacyMetadata: legacyMetadataForReducer, legacyMetadata: { primaryServiceLine, applicationStatus }, user: userForReducer, user: { id, imageUrl, email }, firmTags, detailsSectionCompleted, clientReferencesSectionCompleted, preferenceTasks, isWhiteLabel, handleScrollToBottom, haveATeamProp, expertFirms, paroAppUrl, isExpertOps, internalUserId, getExpertByLegacyFreelancerIdDocument, createExpertPublicProfileTrackingRecord, updateFreelancerServiceLine, serviceLineLoading, serviceLineData, serviceLineError, reviewData, profileReviewError, availabilityData, nextMonthAvailabilityData, expertStatusData, expertStatusLoading, expertLevelsData, projectsData, paroProjectsLoading, expertMetricsData, expertMetricsLoading, upSellCrossSellData, upSellCrossSellLoading, projectChangeLogData, projectChangeLogLoading, updateAddressMutation, addressUpdateLoading, updateUserMutation, userUpdateLoading, updateUserError, updateFreelancerMutation, updateFreelancerLoading, updateFreelancerError, getFreelancerEarnings, getQualityKPIs, expertLevelsTrainings, trainingsDataLoading, assignLetterTrainingToExpert, assignTrainingLoading, assignTrainingError, getUserDocument, getExpertStatusDocument, uploadUserPhotoMutation, loadingNewImage, imageUpdateError, getUserByEmail, updateUserEmail, getUserByEmailLazyQuery, updateUserPassword, verifyUserPassword, openServiceLinesTemplate, setOpenServiceLinesTemplate, getExpertVanityTitles, getExpertRates, updateExpert, vanityTitle, escalationDisputeStatistics, escalationDisputeStatisticsLoading, }: SectionContents & PersonalInformationType & ProfileCompletedPercentageProps & QueryAndMutationProps & ChangeEmailPasswordProps) => JSX.Element;
83
85
  export {};
@@ -76,7 +76,7 @@ const convertRegionToStateAbbreviation = (region) => {
76
76
  const personalInformationReducer = (state, updatedState) => {
77
77
  return Object.assign(Object.assign({}, state), updatedState);
78
78
  };
79
- const ExpertProfileHeader = ({ expertId, legacyFreelancerId, address: addressForReducer, companyName: companyNameForReducer, legacyMetadata: legacyMetadataForReducer, legacyMetadata: { primaryServiceLine, applicationStatus }, user: userForReducer, user: { id, imageUrl, email }, firmTags, detailsSectionCompleted, clientReferencesSectionCompleted, preferenceTasks, isWhiteLabel, handleScrollToBottom, haveATeamProp, expertFirms, paroAppUrl, isExpertOps, internalUserId, getExpertByLegacyFreelancerIdDocument, createExpertPublicProfileTrackingRecord, updateFreelancerServiceLine, serviceLineLoading, serviceLineData, serviceLineError, reviewData, profileReviewError, availabilityData, nextMonthAvailabilityData, expertStatusData, expertStatusLoading, expertLevelsData, projectsData, paroProjectsLoading, expertMetricsData, expertMetricsLoading, upSellCrossSellData, upSellCrossSellLoading, projectChangeLogData, projectChangeLogLoading, updateAddressMutation, addressUpdateLoading, updateUserMutation, userUpdateLoading, updateUserError, updateFreelancerMutation, updateFreelancerLoading, updateFreelancerError, getFreelancerEarnings, getQualityKPIs, expertLevelsTrainings, trainingsDataLoading, assignLetterTrainingToExpert, assignTrainingLoading, assignTrainingError, getUserDocument, getExpertStatusDocument, uploadUserPhotoMutation, loadingNewImage, imageUpdateError, getUserByEmail, updateUserEmail, getUserByEmailLazyQuery, updateUserPassword, verifyUserPassword, openServiceLinesTemplate, setOpenServiceLinesTemplate, getExpertVanityTitles, getExpertRates, updateExpert, vanityTitle, }) => {
79
+ const ExpertProfileHeader = ({ expertId, legacyFreelancerId, address: addressForReducer, companyName: companyNameForReducer, legacyMetadata: legacyMetadataForReducer, legacyMetadata: { primaryServiceLine, applicationStatus }, user: userForReducer, user: { id, imageUrl, email }, firmTags, detailsSectionCompleted, clientReferencesSectionCompleted, preferenceTasks, isWhiteLabel, handleScrollToBottom, haveATeamProp, expertFirms, paroAppUrl, isExpertOps, internalUserId, getExpertByLegacyFreelancerIdDocument, createExpertPublicProfileTrackingRecord, updateFreelancerServiceLine, serviceLineLoading, serviceLineData, serviceLineError, reviewData, profileReviewError, availabilityData, nextMonthAvailabilityData, expertStatusData, expertStatusLoading, expertLevelsData, projectsData, paroProjectsLoading, expertMetricsData, expertMetricsLoading, upSellCrossSellData, upSellCrossSellLoading, projectChangeLogData, projectChangeLogLoading, updateAddressMutation, addressUpdateLoading, updateUserMutation, userUpdateLoading, updateUserError, updateFreelancerMutation, updateFreelancerLoading, updateFreelancerError, getFreelancerEarnings, getQualityKPIs, expertLevelsTrainings, trainingsDataLoading, assignLetterTrainingToExpert, assignTrainingLoading, assignTrainingError, getUserDocument, getExpertStatusDocument, uploadUserPhotoMutation, loadingNewImage, imageUpdateError, getUserByEmail, updateUserEmail, getUserByEmailLazyQuery, updateUserPassword, verifyUserPassword, openServiceLinesTemplate, setOpenServiceLinesTemplate, getExpertVanityTitles, getExpertRates, updateExpert, vanityTitle, escalationDisputeStatistics, escalationDisputeStatisticsLoading, }) => {
80
80
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
81
81
  const [leftSideStatus, setLeftSideStatus] = react_1.default.useState("");
82
82
  const [rightSideStatus, setRightSideStatus] = react_1.default.useState("");
@@ -142,7 +142,7 @@ const ExpertProfileHeader = ({ expertId, legacyFreelancerId, address: addressFor
142
142
  const expertServiceLinesPlus = (serviceLineData === null || serviceLineData === void 0 ? void 0 : serviceLineData.getExpertByLegacyFreelancerId.serviceLinesPlus) || [];
143
143
  const expertLevels = expertLevelsData === null || expertLevelsData === void 0 ? void 0 : expertLevelsData.getExpertLevelsData;
144
144
  if ((expertStatuses && expertMetricsData && leftSideStatus === "" && rightSideStatus === "") || triggerNewStatus) {
145
- (0, ExpertStatusCalculator_1.default)(expertStatuses, setLeftSideStatus, setRightSideStatus, setInfoColor, expertMetricsData, earnings, applicationStatus, setTriggerNewStatus);
145
+ (0, ExpertStatusCalculator_1.default)(expertStatuses, setLeftSideStatus, setRightSideStatus, setInfoColor, expertMetricsData, earnings, applicationStatus, setTriggerNewStatus, escalationDisputeStatistics);
146
146
  }
147
147
  const [open, setOpen] = react_1.default.useState(false);
148
148
  const [reducedPersonalInformation, dispatchUpdatedPersonalInformationUpdate] = react_1.default.useReducer(personalInformationReducer, {
@@ -165,7 +165,7 @@ const ExpertProfileHeader = ({ expertId, legacyFreelancerId, address: addressFor
165
165
  return react_1.default.createElement(ParoError_1.ParoError, null);
166
166
  }
167
167
  const publicProfileLink = `${paroAppUrl}/public/${id}`;
168
- if (expertStatusLoading || expertMetricsLoading || serviceLineLoading || paroProjectsLoading || projectChangeLogLoading || upSellCrossSellLoading) {
168
+ if (expertStatusLoading || expertMetricsLoading || serviceLineLoading || paroProjectsLoading || projectChangeLogLoading || upSellCrossSellLoading || escalationDisputeStatisticsLoading) {
169
169
  return react_1.default.createElement(Loader_1.default, { size: '30px', text: 'Loading Expert Stats...' });
170
170
  }
171
171
  const ServiceLines = [
@@ -219,7 +219,7 @@ const ExpertProfileHeader = ({ expertId, legacyFreelancerId, address: addressFor
219
219
  react_1.default.createElement(ProfileSection_1.default, { legacyFreelancerId: Number(legacyFreelancerId), imageUrl: imageUrl, shouldAllowEditProfile: isExpertOps !== null && isExpertOps !== void 0 ? isExpertOps : false, firstName: firstName, lastName: lastName, primaryServiceLine: primaryServiceLine, editServiceLine: editServiceLine, city: city, stateAbbreviation: stateAbbreviation, email: email, phone: phone, setOpen: setOpen, paroTenure: paroTenure, hourlyRate: defaultHourlyRate, paroProjectsData: paroProjectsData, getUserDocument: getUserDocument, uploadUserPhotoMutation: uploadUserPhotoMutation, loadingNewImage: loadingNewImage, imageUpdateError: imageUpdateError, isInternal: isInternal, getUserByEmail: getUserByEmail, updateUserEmail: updateUserEmail, updateUserMutation: updateUserMutation, getUserByEmailLazyQuery: getUserByEmailLazyQuery, updateUserPassword: updateUserPassword, verifyUserPassword: verifyUserPassword, getExpertRates: getExpertRates }),
220
220
  react_1.default.createElement(core_1.Divider, { orientation: isSmallScreen ? 'horizontal' : 'vertical', style: { marginLeft: '0px !important' } })),
221
221
  react_1.default.createElement(core_1.Grid, { item: true, container: true, direction: 'column', justify: 'space-between', xs: 12, md: true, style: { flex: '1', width: 'auto' } },
222
- react_1.default.createElement(NetworkSection_1.default, { handleScrollToBottom: isInternal && handleScrollToBottom ? handleScrollToBottom : () => { }, preferenceTasks: preferenceTasks, isWhiteLabel: isWhiteLabel, detailsSectionCompleted: detailsSectionCompleted, clientReferencesSectionCompleted: clientReferencesSectionCompleted, infoColor: infoColor, leftSideStatus: leftSideStatus, rightSideStatus: rightSideStatus, isInternal: isInternal, paroTenure: paroTenure, getExpertVanityTitles: getExpertVanityTitles, updateExpert: updateExpert, expertId: expertId, legacyFreelancerId: Number(legacyFreelancerId), vanityTitle: vanityTitle, getExpertByLegacyFreelancerIdDocument: getExpertByLegacyFreelancerIdDocument }),
222
+ react_1.default.createElement(NetworkSection_1.default, { handleScrollToBottom: isInternal && handleScrollToBottom ? handleScrollToBottom : () => { }, preferenceTasks: preferenceTasks, isWhiteLabel: isWhiteLabel, detailsSectionCompleted: detailsSectionCompleted, clientReferencesSectionCompleted: clientReferencesSectionCompleted, infoColor: infoColor, leftSideStatus: leftSideStatus, rightSideStatus: rightSideStatus, isInternal: isInternal, paroTenure: paroTenure, getExpertVanityTitles: getExpertVanityTitles, updateExpert: updateExpert, expertId: expertId, legacyFreelancerId: Number(legacyFreelancerId), vanityTitle: vanityTitle, getExpertByLegacyFreelancerIdDocument: getExpertByLegacyFreelancerIdDocument, escalationDisputeStatistics: escalationDisputeStatistics, paroAppUrl: paroAppUrl }),
223
223
  react_1.default.createElement(core_1.Divider, { orientation: isSmallScreen ? 'horizontal' : 'vertical' })),
224
224
  react_1.default.createElement(core_1.Grid, { item: true, container: true, direction: 'column', justify: 'space-between', xs: 12, md: true, style: { flex: '1', width: 'auto' } },
225
225
  react_1.default.createElement(EarningsSection_1.default, { expertServiceLinesPlus: expertServiceLinesPlus, firmTags: firmTags, haveATeamProp: haveATeamProp, expertLevels: expertLevels, currentMonthGoalHours: currentMonthGoalHours, expertIRPRRatio: expertIRPRRatio, winRate: winRate, expertIRPRRatioPrev: expertIRPRRatioPrev, winRatePrev: winRatePrev, earnings: earnings, upsell: upsell, crossSell: crossSell, lifetimeIRPR: lifetimeIRPR, lifetimeWinRate: lifetimeWinRate, hasCompletedProjects: (_k = expertMetricsData === null || expertMetricsData === void 0 ? void 0 : expertMetricsData.getExpertMetrics) === null || _k === void 0 ? void 0 : _k.lastProjectCompleted, lifetimeFSV: lifetimeFSV }),
@@ -20,5 +20,5 @@ export type ExpertStatusData = {
20
20
  hasValidInsurance: boolean;
21
21
  insuranceExpiryDate: Date;
22
22
  };
23
- declare const ExpertStatusCalculator: (statusData: ExpertStatusData, setLeftSideStatus: (leftSideStatus: string) => void, setRightSideStatus: (rightSideStatus: string) => void, setInfoColor: ({ leftSideStatus, rightSideStatus, Matching, FaF, JobBoard, Available }: any) => void, expertMetricsData: any, earningsData: any, applicationStatus: any, setTriggerNewStatus: any) => void;
23
+ declare const ExpertStatusCalculator: (statusData: ExpertStatusData, setLeftSideStatus: (leftSideStatus: string) => void, setRightSideStatus: (rightSideStatus: string) => void, setInfoColor: ({ leftSideStatus, rightSideStatus, Matching, FaF, JobBoard, Available }: any) => void, expertMetricsData: any, earningsData: any, applicationStatus: any, setTriggerNewStatus: any, escalationDisputeStatistics: any) => void;
24
24
  export default ExpertStatusCalculator;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const utils_1 = require("../shared/utils");
4
+ const AccountSuspensionBanner_1 = require("../Escalations/AccountSuspensionBanner");
4
5
  const isDespiseExpert = (earningsToShow, lastPitchDate, lastLoginDate, applicationStatus) => {
5
6
  // Expert is in Despise Status IF:
6
7
  // Active Expert who has no logins, no pitches, no earnings in the last 30 days
@@ -11,18 +12,28 @@ const isDespiseExpert = (earningsToShow, lastPitchDate, lastLoginDate, applicati
11
12
  const earnedInLast2Months = earningsToShow.filter((earning) => earning.earnings_type === 'actual' && (earning.month === formattedPreviousMonthDate || earning.month === formattedCurrentMonthDate));
12
13
  return (0, utils_1.isOlderThan30Days)(lastPitchDate) && (0, utils_1.isOlderThan30Days)(lastLoginDate) && earnedInLast2Months.length === 0 && applicationStatus === 'ACTIVE';
13
14
  };
14
- const ExpertStatusCalculator = (statusData, setLeftSideStatus, setRightSideStatus, setInfoColor, expertMetricsData, earningsData, applicationStatus, setTriggerNewStatus) => {
15
+ const ExpertStatusCalculator = (statusData, setLeftSideStatus, setRightSideStatus, setInfoColor, expertMetricsData, earningsData, applicationStatus, setTriggerNewStatus, escalationDisputeStatistics) => {
16
+ var _a, _b;
15
17
  const suspensionStatus = (statusData.suspensionEndDate && statusData.suspensionEndDate !== "")
16
18
  ? `! Suspended till ${statusData.suspensionEndDate}, see notes.`
17
19
  : '! Suspended, see notes.';
20
+ const suspensionLevel = (_b = (_a = AccountSuspensionBanner_1.suspensionLevels.find((obj) => obj.value === escalationDisputeStatistics.suspensionLevel)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : "Low";
21
+ const startDate = escalationDisputeStatistics.suspensionStartDate ? new Date(escalationDisputeStatistics.suspensionStartDate).toLocaleDateString() : '';
22
+ const endDate = escalationDisputeStatistics.suspensionEndDate ? new Date(escalationDisputeStatistics.suspensionEndDate).toLocaleDateString() : '';
18
23
  if (statusData.churnedPermanently) {
19
24
  const formattedDate = new Date(statusData.churnedDate).toLocaleDateString();
20
25
  setLeftSideStatus('This Expert has been churned from the Network and cannot take on new projects.');
21
26
  setRightSideStatus(`! Churned ${formattedDate} - Not eligible for rehire. See notes.`);
22
27
  }
23
28
  else if (statusData.suspended) {
24
- setLeftSideStatus('This Expert is currently suspended and is unable to take on new projects.');
25
- setRightSideStatus(`${suspensionStatus}`);
29
+ if (suspensionLevel !== "Low" && startDate && endDate) { // suspension due to escalations
30
+ setLeftSideStatus(`The Expert is on ${suspensionLevel} severity level for Escalations.`);
31
+ setRightSideStatus(`This Expert has been suspended due to severity strikes on escalations and was suspended on ${startDate} and will come off suspension on ${endDate} due.`);
32
+ }
33
+ else { // suspension due to other reasons
34
+ setLeftSideStatus('This Expert is currently suspended and is unable to take on new projects.');
35
+ setRightSideStatus(`${suspensionStatus}`);
36
+ }
26
37
  }
27
38
  else if (statusData.churned) {
28
39
  const formattedDate = new Date(statusData.churnedDate).toLocaleDateString();
@@ -15,6 +15,8 @@ interface NetworkSectionProps {
15
15
  expertId: string;
16
16
  vanityTitle: string;
17
17
  getExpertByLegacyFreelancerIdDocument: any;
18
+ escalationDisputeStatistics: any;
19
+ paroAppUrl: string;
18
20
  }
19
- declare const NetworkSection: ({ handleScrollToBottom, preferenceTasks, isWhiteLabel, detailsSectionCompleted, clientReferencesSectionCompleted, infoColor, leftSideStatus, rightSideStatus, isInternal, paroTenure, getExpertVanityTitles, updateExpert, expertId, legacyFreelancerId, vanityTitle, getExpertByLegacyFreelancerIdDocument, }: NetworkSectionProps) => JSX.Element;
21
+ declare const NetworkSection: ({ handleScrollToBottom, preferenceTasks, isWhiteLabel, detailsSectionCompleted, clientReferencesSectionCompleted, infoColor, leftSideStatus, rightSideStatus, isInternal, paroTenure, getExpertVanityTitles, updateExpert, expertId, legacyFreelancerId, vanityTitle, getExpertByLegacyFreelancerIdDocument, escalationDisputeStatistics, paroAppUrl, }: NetworkSectionProps) => JSX.Element;
20
22
  export default NetworkSection;
@@ -39,6 +39,10 @@ const ProfileCompletedPercentange_1 = require("../ProfileCompletedPercentange");
39
39
  const icons_1 = require("@material-ui/icons");
40
40
  const ReviewsTab_1 = require("../ReviewsTab/ReviewsTab");
41
41
  const base_ui_1 = require("@paro.io/base-ui");
42
+ const EarningsSection_1 = require("./EarningsSection");
43
+ const base_icons_1 = require("@paro.io/base-icons");
44
+ const EscalationIssueCard_1 = require("../Escalations/EscalationIssueCard");
45
+ const AccountSuspensionBanner_1 = require("../Escalations/AccountSuspensionBanner");
42
46
  const useStyles = (0, styles_1.makeStyles)((theme) => ({
43
47
  textSuccess: {
44
48
  color: '#12756F',
@@ -75,11 +79,32 @@ const ExpertiseTitleModal = ({ openModal, updateTitle, titleOptions, selectedTit
75
79
  react_1.default.createElement(base_ui_1.Button, { label: "UPDATE PROFILE", onClick: handleUpdateExpertTitle, type: "button", isLoading: updateTitle, disabled: selectedTitle === null || (selectedTitle === 'Other' && (customTitle === null || customTitle === '')), color: "primary" }),
76
80
  react_1.default.createElement(base_ui_1.Button, { label: "CANCEL", onClick: handleOnClose, type: "button", disabled: updateTitle, isLoading: updateTitle })))));
77
81
  };
78
- const NetworkSection = ({ handleScrollToBottom, preferenceTasks, isWhiteLabel, detailsSectionCompleted, clientReferencesSectionCompleted, infoColor, leftSideStatus, rightSideStatus, isInternal, paroTenure, getExpertVanityTitles, updateExpert, expertId, legacyFreelancerId, vanityTitle, getExpertByLegacyFreelancerIdDocument, }) => {
82
+ const PriorityLevelModal = ({ openModal, onClose }) => {
83
+ return (react_1.default.createElement(base_ui_1.Modal, { open: openModal, size: "sm", onClose: onClose },
84
+ react_1.default.createElement("div", { className: "border border-1 border-gray-300 p-4 rounded-md gap-y-2" },
85
+ react_1.default.createElement("h4", { className: "font-medium text-gray-900 mb-2" }, "Severity Levels for Issues"),
86
+ react_1.default.createElement("div", { className: "space-y-2 text-sm" },
87
+ react_1.default.createElement("div", { className: "flex items-center gap-x-2" },
88
+ react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: "Critical" }),
89
+ react_1.default.createElement("span", null, "All deliverables are currently blocked; the project cannot move forward.")),
90
+ react_1.default.createElement("div", { className: "flex items-center gap-x-2" },
91
+ react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: "High" }),
92
+ react_1.default.createElement("span", null, "Key deliverables are blocked, preventing meaningful progress.")),
93
+ react_1.default.createElement("div", { className: "flex items-center gap-x-2" },
94
+ react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: "Medium" }),
95
+ react_1.default.createElement("span", null, "Deliverables are still in progress, but timelines are at risk.")),
96
+ react_1.default.createElement("div", { className: "flex items-center gap-x-2" },
97
+ react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: "Low" }),
98
+ react_1.default.createElement("span", null, "Minor issue or inconvenience that does not affect overall project flow."))))));
99
+ };
100
+ const NetworkSection = ({ handleScrollToBottom, preferenceTasks, isWhiteLabel, detailsSectionCompleted, clientReferencesSectionCompleted, infoColor, leftSideStatus, rightSideStatus, isInternal, paroTenure, getExpertVanityTitles, updateExpert, expertId, legacyFreelancerId, vanityTitle, getExpertByLegacyFreelancerIdDocument, escalationDisputeStatistics, paroAppUrl, }) => {
101
+ var _a, _b, _c, _d, _e, _f;
79
102
  const [openModal, setOpenModal] = (0, react_1.useState)(false);
80
103
  const [selectedTitle, setSelectedTitle] = (0, react_1.useState)(vanityTitle);
81
104
  const [customTitle, setCustomTitle] = (0, react_1.useState)(null);
82
105
  const [updateTitle, setUpdateTitle] = (0, react_1.useState)(false);
106
+ const [showPriorityLevelModal, setShowPriorityLevelModal] = (0, react_1.useState)(false);
107
+ const suspensionLevel = (_b = (_a = AccountSuspensionBanner_1.suspensionLevels.find((obj) => obj.value === escalationDisputeStatistics.suspensionLevel)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : "Low";
83
108
  const handleUpdateExpertTitle = () => __awaiter(void 0, void 0, void 0, function* () {
84
109
  setUpdateTitle(true);
85
110
  updateExpert({
@@ -129,6 +154,21 @@ const NetworkSection = ({ handleScrollToBottom, preferenceTasks, isWhiteLabel, d
129
154
  react_1.default.createElement(icons_1.Cached, null))),
130
155
  react_1.default.createElement(core_1.Box, { mt: 1, mb: 1, mr: 2 },
131
156
  react_1.default.createElement(core_1.Divider, null))),
157
+ escalationDisputeStatistics &&
158
+ react_1.default.createElement(react_1.default.Fragment, null,
159
+ react_1.default.createElement(EarningsSection_1.EarningsInfo, { label: "# of Escalations in last 3 months", value: (_c = escalationDisputeStatistics.recentResolvedEscalations) !== null && _c !== void 0 ? _c : 0 }),
160
+ react_1.default.createElement(core_1.Box, { mb: 2 },
161
+ react_1.default.createElement(core_1.Divider, null)),
162
+ react_1.default.createElement(EarningsSection_1.EarningsInfo, { label: "Total # of Escalations", value: (_d = escalationDisputeStatistics.totalResolvedEscalations) !== null && _d !== void 0 ? _d : 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: "# of Disputes in last 3 months", value: (_e = escalationDisputeStatistics.recentResolvedDisputes) !== null && _e !== void 0 ? _e : 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: "Total # of Disputes", value: (_f = escalationDisputeStatistics.totalResolvedDisputes) !== null && _f !== void 0 ? _f : 0 }),
169
+ react_1.default.createElement(core_1.Box, { mb: 0.5 },
170
+ react_1.default.createElement(core_1.Divider, null)),
171
+ !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")),
132
172
  react_1.default.createElement(core_1.Grid, { style: { marginRight: '8px', marginLeft: '2px' } },
133
173
  react_1.default.createElement(core_1.Box, { mb: 1 },
134
174
  react_1.default.createElement("b", null, "Network Availability :")),
@@ -148,9 +188,15 @@ const NetworkSection = ({ handleScrollToBottom, preferenceTasks, isWhiteLabel, d
148
188
  react_1.default.createElement(core_1.Box, null,
149
189
  react_1.default.createElement("b", null, "Reason: "),
150
190
  react_1.default.createElement("ul", null,
151
- react_1.default.createElement("li", null, leftSideStatus),
191
+ react_1.default.createElement("li", null,
192
+ leftSideStatus,
193
+ " ",
194
+ suspensionLevel !== "Low" && react_1.default.createElement(core_1.IconButton, { onClick: () => { setShowPriorityLevelModal(true); } },
195
+ react_1.default.createElement(base_icons_1.IconInfoCircle, { size: "sm", className: "block text-right" }))),
152
196
  react_1.default.createElement("li", null, rightSideStatus)))),
153
197
  openModal &&
154
- react_1.default.createElement(ExpertiseTitleModal, { openModal: openModal, updateTitle: updateTitle, titleOptions: [...getExpertVanityTitles], selectedTitle: selectedTitle, customTitle: customTitle, setCustomTitle: setCustomTitle, handleChangeTitle: (event) => { setSelectedTitle(event.target.value); }, handleOnClose: () => setOpenModal(false), handleUpdateExpertTitle: handleUpdateExpertTitle })));
198
+ react_1.default.createElement(ExpertiseTitleModal, { openModal: openModal, updateTitle: updateTitle, titleOptions: [...getExpertVanityTitles], selectedTitle: selectedTitle, customTitle: customTitle, setCustomTitle: setCustomTitle, handleChangeTitle: (event) => { setSelectedTitle(event.target.value); }, handleOnClose: () => setOpenModal(false), handleUpdateExpertTitle: handleUpdateExpertTitle }),
199
+ showPriorityLevelModal &&
200
+ react_1.default.createElement(PriorityLevelModal, { openModal: showPriorityLevelModal, onClose: () => setShowPriorityLevelModal(false) })));
155
201
  };
156
202
  exports.default = NetworkSection;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paro.io/expert-shared-components",
3
- "version": "1.13.7",
3
+ "version": "1.13.9",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {