@paro.io/expert-shared-components 1.12.50 → 1.12.52

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.
@@ -13,15 +13,12 @@ const AccountSuspensionBanner = ({ setShowSuspensionModal, suspended = false })
13
13
  react_1.default.createElement(base_icons_1.IconExclamation, { className: "h-6 w-6 text-white" })),
14
14
  react_1.default.createElement("div", { className: "flex-1" },
15
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 escalation #12847. You must complete comprehensive training to regain access to new opportunities."),
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."),
17
17
  react_1.default.createElement("div", { className: "mt-3 bg-white bg-opacity-10 rounded p-3" },
18
18
  react_1.default.createElement("div", { className: "flex items-center justify-between text-sm" },
19
19
  react_1.default.createElement("div", null,
20
20
  react_1.default.createElement("span", { className: "text-red-100" }, "Suspension: "),
21
- react_1.default.createElement("span", { className: "text-white font-medium" }, "30 days (Medium Severity)")),
22
- react_1.default.createElement("div", null,
23
- react_1.default.createElement("span", { className: "text-red-100" }, "Started: "),
24
- react_1.default.createElement("span", { className: "text-white font-medium" }, "May 29, 2025"))))))
21
+ react_1.default.createElement("span", { className: "text-white font-medium" }, "30 days (Medium Severity)"))))))
25
22
  :
26
23
  react_1.default.createElement("div", { className: "flex items-center justify-between" },
27
24
  react_1.default.createElement("div", { className: "flex items-center" },
@@ -41,71 +41,67 @@ const EscalationIssueCard_1 = require("./EscalationIssueCard");
41
41
  const FileUploader_1 = require("../FileUploader");
42
42
  const EscalationRespondForm_1 = require("./EscalationRespondForm");
43
43
  const EscalationChat = ({ activeChatIssue, showEscalationChat, setShowEscalationChat, user, createEscalationChatMessage, documentUploadUrl, bucketName, uploadExpertClientFiles, createProjectEscalation, isExpert, }) => {
44
- var _a, _b;
45
- const [uploadFiles, setUploadFiles] = (0, react_1.useState)([]);
44
+ var _a, _b, _c, _d;
45
+ const [uploadFiles, setUploadFiles] = (0, react_1.useState)(isExpert
46
+ ? (((_a = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.expertSupportingDocuments) === null || _a === void 0 ? void 0 : _a.split(",")) || [])
47
+ : (((_b = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.clientSupportingDocuments) === null || _b === void 0 ? void 0 : _b.split(",")) || []));
46
48
  const [uploadingFile, setUploadingFile] = (0, react_1.useState)(false);
47
49
  const fileInputRef = (0, react_1.useRef)(null);
48
50
  const handleFileUpload = (event) => __awaiter(void 0, void 0, void 0, function* () {
49
- const selectedFiles = event.target.files;
50
- if (!selectedFiles)
51
- return;
52
51
  setUploadingFile(true);
53
- const validFileNames = Array.from(selectedFiles)
54
- .filter(file => (0, EscalationRespondForm_1.validateFileUpload)(file))
55
- .map(file => file.name);
56
- if (validFileNames.length === 0)
57
- return;
58
- if (validFileNames && validFileNames.length > 0) {
59
- const uploadPromises = Array.from(selectedFiles).map((selectedFile) => {
60
- return new Promise((resolve, reject) => {
61
- const reader = new FileReader();
62
- reader.onloadend = () => __awaiter(void 0, void 0, void 0, function* () {
63
- var _a, _b, _c, _d, _e, _f, _g, _h;
64
- try {
65
- const res = yield (0, FileUploader_1.fileUploader)({
66
- file: selectedFile,
67
- documentName: selectedFile.name,
68
- escalationId: activeChatIssue.escalationId,
69
- projectId: activeChatIssue.projectDetails.length > 0 ? activeChatIssue.projectDetails[0].projectId : '',
70
- documentUploadUrl: documentUploadUrl,
71
- bucketName: bucketName,
72
- isExpert: false,
73
- uploadExpertClientFiles: uploadExpertClientFiles,
74
- createProjectEscalation: createProjectEscalation,
75
- extraData: {
76
- clientId: (_a = activeChatIssue.client.id) !== null && _a !== void 0 ? _a : 0,
77
- clientName: (_b = activeChatIssue.client.name) !== null && _b !== void 0 ? _b : '',
78
- email: isExpert ? (_e = (_d = (_c = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.client) === null || _c === void 0 ? void 0 : _c.primaryContact) === null || _d === void 0 ? void 0 : _d.email) !== null && _e !== void 0 ? _e : '' : (_f = user === null || user === void 0 ? void 0 : user.email) !== null && _f !== void 0 ? _f : '',
79
- freelancerId: (_g = activeChatIssue.freelancer.id) !== null && _g !== void 0 ? _g : 0,
80
- freelancerName: (_h = activeChatIssue.freelancer.name) !== null && _h !== void 0 ? _h : '',
81
- projectName: activeChatIssue.projectDetails.length > 0 ? activeChatIssue.projectDetails[0].projectName : '',
82
- }
83
- });
84
- if (res) {
85
- setUploadFiles(prev => [...prev, ...res]);
86
- }
87
- }
88
- catch (error) {
89
- console.error("faile upload failed", error);
90
- }
91
- finally {
92
- resolve();
93
- }
94
- });
95
- reader.readAsDataURL(selectedFile);
96
- });
97
- });
98
- try {
99
- const res = yield Promise.all(uploadPromises);
100
- }
101
- catch (error) {
102
- console.error('Error uploading files:', error);
52
+ try {
53
+ const selectedFiles = event.target.files;
54
+ if (!selectedFiles) {
55
+ setUploadingFile(false);
56
+ return;
103
57
  }
104
- finally {
58
+ const validFiles = Array.from(selectedFiles).filter(file => (0, EscalationRespondForm_1.validateFileUpload)(file));
59
+ if (validFiles.length === 0) {
105
60
  setUploadingFile(false);
61
+ return;
106
62
  }
63
+ const uploadPromises = validFiles.map((selectedFile) => {
64
+ return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
65
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
66
+ try {
67
+ const res = yield (0, FileUploader_1.fileUploader)({
68
+ file: selectedFile,
69
+ documentName: selectedFile.name,
70
+ escalationId: activeChatIssue.escalationId,
71
+ projectId: activeChatIssue.projectDetails.length > 0 ? activeChatIssue.projectDetails[0].projectId : '',
72
+ documentUploadUrl: documentUploadUrl,
73
+ bucketName: bucketName,
74
+ previousFiles: isExpert ? activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.clientDocumentLinks : activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.expertDocumentlinks,
75
+ isExpert: isExpert,
76
+ uploadExpertClientFiles: uploadExpertClientFiles,
77
+ createProjectEscalation: createProjectEscalation,
78
+ extraData: {
79
+ clientId: isExpert ? (_b = (_a = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.client) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 0 : (_d = (_c = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.client) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : 0,
80
+ clientName: isExpert ? (_f = (_e = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.client) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : '' : (_g = user === null || user === void 0 ? void 0 : user.name) !== null && _g !== void 0 ? _g : '',
81
+ email: isExpert ? (_k = (_j = (_h = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.client) === null || _h === void 0 ? void 0 : _h.primaryContact) === null || _j === void 0 ? void 0 : _j.email) !== null && _k !== void 0 ? _k : '' : (_m = (_l = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.freelancer) === null || _l === void 0 ? void 0 : _l.email) !== null && _m !== void 0 ? _m : '',
82
+ freelancerId: isExpert ? (_o = user === null || user === void 0 ? void 0 : user.userId) !== null && _o !== void 0 ? _o : 0 : (_q = (_p = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.freelancer) === null || _p === void 0 ? void 0 : _p.id) !== null && _q !== void 0 ? _q : 0,
83
+ freelancerName: isExpert ? (_r = user === null || user === void 0 ? void 0 : user.name) !== null && _r !== void 0 ? _r : '' : (_t = (_s = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.freelancer) === null || _s === void 0 ? void 0 : _s.name) !== null && _t !== void 0 ? _t : '',
84
+ projectName: activeChatIssue.projectDetails.length > 0 ? activeChatIssue.projectDetails[0].projectName : '',
85
+ }
86
+ });
87
+ if (res) {
88
+ setUploadFiles(prev => [...prev, ...res]);
89
+ }
90
+ resolve();
91
+ }
92
+ catch (error) {
93
+ reject(error);
94
+ }
95
+ }));
96
+ });
97
+ yield Promise.all(uploadPromises);
98
+ }
99
+ catch (error) {
100
+ console.error('Error uploading files:', error);
101
+ }
102
+ finally {
103
+ setUploadingFile(false);
107
104
  }
108
- ;
109
105
  });
110
106
  const docs = [activeChatIssue.expertSupportingDocuments, activeChatIssue.clientSupportingDocuments, activeChatIssue.internalSupportingDocuments, ...uploadFiles];
111
107
  const processedDocs = docs
@@ -114,17 +110,17 @@ const EscalationChat = ({ activeChatIssue, showEscalationChat, setShowEscalation
114
110
  .map(doc => doc.trim())
115
111
  .filter(doc => doc !== '' || doc !== "NULL");
116
112
  const project = activeChatIssue.projectDetails && Array.isArray(activeChatIssue.projectDetails) && activeChatIssue.projectDetails.length > 0
117
- ? `${(_a = activeChatIssue.projectDetails[0]) === null || _a === void 0 ? void 0 : _a.projectName}${activeChatIssue.projectDetails.length > 1 ? ` +${activeChatIssue.projectDetails.length - 1} more` : ''} `
113
+ ? `${(_c = activeChatIssue.projectDetails[0]) === null || _c === void 0 ? void 0 : _c.projectName}${activeChatIssue.projectDetails.length > 1 ? ` +${activeChatIssue.projectDetails.length - 1} more` : ''} `
118
114
  : '';
119
115
  return (react_1.default.createElement(core_1.Dialog, { open: showEscalationChat, onClose: () => setShowEscalationChat(false), maxWidth: 'sm' },
120
116
  react_1.default.createElement(core_1.DialogTitle, null,
121
- react_1.default.createElement("div", { className: "text-black mb-1 p-2 pl-4 absolute top-0 left-0 w-full flex flex-row justify-between items-center z-50" },
117
+ react_1.default.createElement("div", { className: "text-black bg-white mb-1 p-2 pl-4 absolute top-0 left-0 w-full flex flex-row justify-between items-center z-50" },
122
118
  react_1.default.createElement("div", { className: "flex flex-col items-start" },
123
119
  react_1.default.createElement("div", { className: "flex flex-row items-center" },
124
120
  react_1.default.createElement("h1", { className: "text-md font-bold mr-2" },
125
121
  "Escalation Chat #",
126
122
  activeChatIssue.escalationNumber),
127
- react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: activeChatIssue.status })),
123
+ react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: activeChatIssue.status === "InProgress" ? "In Progress" : activeChatIssue.status })),
128
124
  react_1.default.createElement("p", { className: "text-xs" },
129
125
  activeChatIssue.problem,
130
126
  " \u2022 ",
@@ -134,15 +130,15 @@ const EscalationChat = ({ activeChatIssue, showEscalationChat, setShowEscalation
134
130
  react_1.default.createElement(base_icons_1.IconX, null))))),
135
131
  react_1.default.createElement(core_1.DialogContent, null,
136
132
  react_1.default.createElement("div", { className: "bg-white rounded-lg w-full overflow-hidden flex flex-col p-2 mt-12" },
137
- 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 }),
138
- processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2" },
133
+ react_1.default.createElement(DiscussionSection_1.DiscussionSection, { escalationNumber: activeChatIssue.escalationNumber, currentUser: user, messages: (_d = activeChatIssue === null || activeChatIssue === void 0 ? void 0 : activeChatIssue.chatMessages) !== null && _d !== void 0 ? _d : [], onCreateMessage: createEscalationChatMessage, isInternal: false }),
134
+ processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2 mt-4 mb-2" },
139
135
  react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
140
- processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1] }))))),
136
+ processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1], customColor: "success" }))))),
141
137
  react_1.default.createElement("div", { className: "bg-white mt-2" },
142
138
  react_1.default.createElement("div", { className: "space-y-3" },
143
139
  react_1.default.createElement("div", { className: "flex items-center justify-between" },
144
140
  react_1.default.createElement("div", { className: "flex items-center space-x-2" },
145
- react_1.default.createElement("input", { id: "upload-file", type: "file", multiple: true, accept: ".pdf,.doc,.docx,.jpeg,.png,.gif,.csv", style: { display: 'none' }, ref: fileInputRef, onChange: handleFileUpload }),
141
+ react_1.default.createElement("input", { id: "upload-file", type: "file", multiple: false, accept: ".pdf,.doc,.docx,.jpeg,.png,.gif,.csv,.xslx", style: { display: 'none' }, ref: fileInputRef, onChange: handleFileUpload }),
146
142
  react_1.default.createElement(base_ui_1.Button, { label: "Attach Files", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: "sm" }), onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, color: "info", className: "mx-2", isLoading: uploadingFile })),
147
143
  react_1.default.createElement("div", { className: "flex space-x-2" },
148
144
  react_1.default.createElement(base_ui_1.Button, { label: "cancel", onClick: () => setShowEscalationChat(false), disabled: uploadingFile })))))))));
@@ -1,8 +1,9 @@
1
1
  import React from 'react';
2
- export declare const CustomTag: ({ label, iconLeft, onClick, }: {
2
+ export declare const CustomTag: ({ label, iconLeft, onClick, customColor, }: {
3
3
  label: any;
4
4
  iconLeft?: React.ReactNode;
5
5
  onClick?: () => void;
6
+ customColor?: string;
6
7
  }) => React.JSX.Element;
7
8
  type EscalationIssueCardProps = {
8
9
  issues: any[];
@@ -1,14 +1,39 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.CustomTag = void 0;
7
- const react_1 = __importDefault(require("react"));
30
+ const react_1 = __importStar(require("react"));
8
31
  const base_ui_1 = require("@paro.io/base-ui");
9
32
  const ClientDisputeProjectCard_1 = require("../Invoices/ClientDisputeProjectCard");
10
33
  const base_icons_1 = require("@paro.io/base-icons");
11
34
  const dayjs_1 = __importDefault(require("dayjs"));
35
+ const ViewResponseModal_1 = __importDefault(require("./ViewResponseModal"));
36
+ const MarkResolvedModal_1 = __importDefault(require("./MarkResolvedModal"));
12
37
  const getBackgroundColor = (type) => {
13
38
  switch (type) {
14
39
  case 'Critical':
@@ -20,70 +45,70 @@ const getBackgroundColor = (type) => {
20
45
  case 'Low':
21
46
  return 'success';
22
47
  default:
23
- return 'success';
48
+ return 'neutral';
24
49
  }
25
50
  };
26
- const CustomTag = ({ label, iconLeft, onClick, }) => {
27
- const color = getBackgroundColor(label);
28
- return (react_1.default.createElement("div", { onClick: onClick, className: `flex flex-row gap-1 border box-border text-center px-4 pb-0.5 pt-1 text-sm inline-block break-words text-white rounded-full bg-${color} border-${color} ml-2 font-bold ${onClick ? 'cursor-pointer' : ''}` },
51
+ const CustomTag = ({ label, iconLeft, onClick, customColor, }) => {
52
+ const color = customColor ? customColor : getBackgroundColor(label);
53
+ return (react_1.default.createElement("div", { onClick: onClick, className: `flex flex-row gap-1 border box-border text-center px-4 pb-0.5 pt-1 text-sm inline-block break-words text-white rounded-full bg-${color} border-${color} ml-2 font-medium ${onClick ? 'cursor-pointer' : ''}` },
29
54
  iconLeft && react_1.default.createElement("span", null, iconLeft), label === null || label === void 0 ? void 0 :
30
55
  label.toUpperCase()));
31
56
  };
32
57
  exports.CustomTag = CustomTag;
33
58
  const EscalationIssueCard = ({ issues, isExpert, openEscalationChat, showRespondButton = false, setSelectedIssueId, showMarkResolvedButton = false, updateProjectEscalation, downloadDocumentUrl, bucketName, }) => {
59
+ var _a, _b;
60
+ const [viewResponseModal, setViewResponseModal] = (0, react_1.useState)(null);
61
+ const [markAsResolved, setMarkAsResolved] = (0, react_1.useState)(null);
62
+ const getResponseButtonText = (issue) => {
63
+ const hasResponse = isExpert ? issue.clientResponse : issue.expertResponse;
64
+ return hasResponse ? "View Response" : "Awaiting Response";
65
+ };
34
66
  if (!issues.length)
35
67
  return react_1.default.createElement("div", null, "No issues.");
36
- return (react_1.default.createElement("div", { className: "space-y-4" }, issues.map((issue) => {
37
- var _a;
38
- const project = issue.projectDetails && Array.isArray(issue.projectDetails) && issue.projectDetails.length > 0
39
- ? `${(_a = issue.projectDetails[0]) === null || _a === void 0 ? void 0 : _a.projectName}${issue.projectDetails.length > 1 ? ` +${issue.projectDetails.length - 1} more` : ''} `
40
- : '';
41
- const docs = [issue.expertSupportingDocuments, issue.clientSupportingDocuments, issue.internalSupportingDocuments];
42
- const processedDocs = docs
43
- .filter(doc => doc !== null && doc !== undefined && doc !== '' && doc !== "NULL")
44
- .flatMap(doc => doc.split(','))
45
- .map(doc => doc.trim())
46
- .filter(doc => doc !== '' || doc !== "NULL");
47
- return (react_1.default.createElement("div", { key: issue.id, className: "border border-gray-200 rounded-lg bg-white p-4" },
48
- react_1.default.createElement("div", { className: "flex items-center justify-between mb-3" },
49
- react_1.default.createElement("div", { className: "flex-1 ml-2" },
50
- react_1.default.createElement("div", { className: "flex flex-row justify-start gap-2" },
51
- react_1.default.createElement("div", { className: "font-bold" }, issue.problem),
52
- react_1.default.createElement(exports.CustomTag, { label: issue.severityLevel })),
53
- react_1.default.createElement("div", { className: "text-xs text-gray-500 font-bold" },
54
- project,
55
- " \u2022 Case #",
56
- issue.escalationNumber)),
57
- react_1.default.createElement(exports.CustomTag, { label: issue.escalationType })),
58
- react_1.default.createElement("div", { className: "bg-gray-50 rounded-md p-3 mb-4 border" },
59
- react_1.default.createElement("div", { className: "flex items-center justify-between mb-2" },
60
- react_1.default.createElement("div", { className: "text-sm text-gray-500" },
61
- "Submitted by: ",
62
- react_1.default.createElement("span", { className: "font-bold" }, issue.submittedByUser.firstName + " " + issue.submittedByUser.lastName),
63
- issue.createdAt && react_1.default.createElement(react_1.default.Fragment, null,
64
- " \u2022 Submitted on: ",
65
- react_1.default.createElement("span", { className: "font-bold" }, (0, dayjs_1.default)(issue.createdAt).format("MM-DD-YYYY"))))),
66
- react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-3" }, issue.outcome),
67
- processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2" },
68
- react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
69
- processedDocs.map((d, idx) => (react_1.default.createElement(exports.CustomTag, { key: idx, label: d.split('%2F')[1], iconLeft: react_1.default.createElement(base_icons_1.IconDocumentDownload, { size: "xs" }), onClick: () => {
70
- (0, ClientDisputeProjectCard_1.handleDownloadDocument)(issue.escalationId, d.split('%2F')[1], downloadDocumentUrl, bucketName);
71
- } })))))),
72
- react_1.default.createElement("div", { className: "flex flex-wrap gap-2" },
73
- react_1.default.createElement(base_ui_1.Button, { onClick: () => openEscalationChat(issue), label: "Chat", color: "primary" }),
74
- showRespondButton && setSelectedIssueId && (react_1.default.createElement(base_ui_1.Button, { label: "Respond to Escalation", onClick: () => setSelectedIssueId(issue.escalationNumber), color: 'primary' })),
75
- showMarkResolvedButton && !isExpert && (react_1.default.createElement(base_ui_1.Button, { onClick: () => {
76
- updateProjectEscalation({
77
- variables: {
78
- input: {
79
- escalationId: issue.escalationId,
80
- status: 'Resolved'
81
- }
82
- }
83
- }).then(() => { console.log("its marked as resolved"); }).catch((error) => {
84
- console.error("Error updating escalation status:", error);
85
- });
86
- }, label: "Mark as Resolved", color: "primary" })))));
87
- })));
68
+ return (react_1.default.createElement("div", { className: "space-y-4" },
69
+ issues.map((issue) => {
70
+ var _a;
71
+ const project = issue.projectDetails && Array.isArray(issue.projectDetails) && issue.projectDetails.length > 0
72
+ ? `${(_a = issue.projectDetails[0]) === null || _a === void 0 ? void 0 : _a.projectName}${issue.projectDetails.length > 1 ? ` +${issue.projectDetails.length - 1} more` : ''} `
73
+ : '';
74
+ const docs = [issue.expertSupportingDocuments, issue.clientSupportingDocuments, issue.internalSupportingDocuments];
75
+ const processedDocs = docs
76
+ .filter(doc => doc !== null && doc !== undefined && doc !== '' && doc !== "NULL")
77
+ .flatMap(doc => doc.split(','))
78
+ .map(doc => doc.trim())
79
+ .filter(doc => doc !== '' || doc !== "NULL");
80
+ return (react_1.default.createElement("div", { key: issue.id, className: "border border-gray-200 rounded-lg bg-white p-4" },
81
+ react_1.default.createElement("div", { className: "flex items-center justify-between mb-3" },
82
+ react_1.default.createElement("div", { className: "flex-1 ml-2" },
83
+ react_1.default.createElement("div", { className: "flex flex-row justify-start gap-2" },
84
+ react_1.default.createElement("div", { className: "font-bold" }, issue.problem),
85
+ react_1.default.createElement(exports.CustomTag, { label: issue.severityLevel })),
86
+ react_1.default.createElement("div", { className: "text-xs text-gray-500 font-bold" },
87
+ project,
88
+ " \u2022 Case #",
89
+ issue.escalationNumber)),
90
+ react_1.default.createElement(exports.CustomTag, { label: issue.escalationType })),
91
+ react_1.default.createElement("div", { className: "bg-gray-50 rounded-md p-3 mb-4 border" },
92
+ react_1.default.createElement("div", { className: "flex items-center justify-between mb-2" },
93
+ react_1.default.createElement("div", { className: "text-sm text-gray-500" },
94
+ "Submitted by: ",
95
+ react_1.default.createElement("span", { className: "font-bold" }, issue.submittedByUser.firstName + " " + issue.submittedByUser.lastName),
96
+ issue.createdAt && react_1.default.createElement(react_1.default.Fragment, null,
97
+ " \u2022 Submitted on: ",
98
+ react_1.default.createElement("span", { className: "font-bold" }, (0, dayjs_1.default)(issue.createdAt).format("MM-DD-YYYY"))))),
99
+ react_1.default.createElement("div", { className: "text-sm text-gray-600 mb-3" }, issue.outcome),
100
+ processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2" },
101
+ react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
102
+ processedDocs.map((d, idx) => (react_1.default.createElement(exports.CustomTag, { key: idx, customColor: "success", label: d.split('%2F')[1], iconLeft: react_1.default.createElement(base_icons_1.IconDocumentDownload, { size: "xs" }), onClick: () => {
103
+ (0, ClientDisputeProjectCard_1.handleDownloadDocument)(issue.escalationId, d.split('%2F')[1], downloadDocumentUrl, bucketName);
104
+ } })))))),
105
+ react_1.default.createElement("div", { className: "flex flex-wrap gap-2" },
106
+ react_1.default.createElement(base_ui_1.Button, { onClick: () => openEscalationChat(issue), label: "Chat", color: "primary" }),
107
+ showRespondButton && setSelectedIssueId && (react_1.default.createElement(base_ui_1.Button, { label: "Respond to Escalation", onClick: () => setSelectedIssueId(issue.escalationNumber), color: 'primary' })),
108
+ showMarkResolvedButton && (react_1.default.createElement(base_ui_1.Button, { label: getResponseButtonText(issue), onClick: () => { setViewResponseModal(issue); }, color: 'primary', disabled: getResponseButtonText(issue) === 'Awaiting Response' })),
109
+ showMarkResolvedButton && !isExpert && (react_1.default.createElement(base_ui_1.Button, { onClick: () => { setMarkAsResolved(issue); }, label: "Mark as Resolved", color: "primary" })))));
110
+ }),
111
+ !!viewResponseModal && react_1.default.createElement(ViewResponseModal_1.default, { response: isExpert ? viewResponseModal.clientResponse : viewResponseModal.expertResponse, isExpert: isExpert, open: !!viewResponseModal, onClose: () => setViewResponseModal(null) }),
112
+ !!markAsResolved && react_1.default.createElement(MarkResolvedModal_1.default, { escalationId: markAsResolved.escalationId, expertName: (_b = (_a = markAsResolved === null || markAsResolved === void 0 ? void 0 : markAsResolved.freelancer) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'Expert', open: !!markAsResolved, onClose: () => setMarkAsResolved(false), updateProjectEscalation: updateProjectEscalation })));
88
113
  };
89
114
  exports.default = EscalationIssueCard;
@@ -46,6 +46,7 @@ exports.ACCEPTED_FILE_TYPES = [
46
46
  'image/jpeg',
47
47
  'image/png',
48
48
  'text/csv',
49
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
49
50
  ];
50
51
  const validateFileUpload = (file) => {
51
52
  if (!file) {
@@ -75,74 +76,70 @@ const responseTypes = [
75
76
  },
76
77
  ];
77
78
  const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downloadDocumentUrl, uploadExpertClientFiles, updateProjectEscalation, bucketName, goHome, isExpert, }) => {
79
+ var _a, _b;
78
80
  const [selectedType, setSelectedType] = (0, react_1.useState)(responseTypes[0].value);
79
81
  const [responseInput, setResponseInput] = (0, react_1.useState)('');
80
- const [uploadFiles, setUploadFiles] = (0, react_1.useState)([]);
82
+ const [uploadFiles, setUploadFiles] = (0, react_1.useState)(isExpert
83
+ ? (((_a = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.expertSupportingDocuments) === null || _a === void 0 ? void 0 : _a.split(",")) || [])
84
+ : (((_b = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.clientSupportingDocuments) === null || _b === void 0 ? void 0 : _b.split(",")) || []));
81
85
  const [uploadingFile, setUploadingFile] = (0, react_1.useState)(false);
82
86
  const [submitting, setSubmitting] = (0, react_1.useState)(false);
83
87
  const fileInputRef = (0, react_1.useRef)(null);
84
88
  const handleFileUpload = (event) => __awaiter(void 0, void 0, void 0, function* () {
85
- const selectedFiles = event.target.files;
86
- if (!selectedFiles)
87
- return;
88
89
  setUploadingFile(true);
89
- const validFileNames = Array.from(selectedFiles)
90
- .filter(file => (0, exports.validateFileUpload)(file))
91
- .map(file => file.name);
92
- if (validFileNames.length === 0)
93
- return;
94
- if (validFileNames && validFileNames.length > 0) {
95
- const uploadPromises = Array.from(selectedFiles).map((selectedFile) => {
96
- return new Promise((resolve, reject) => {
97
- const reader = new FileReader();
98
- reader.onloadend = () => __awaiter(void 0, void 0, void 0, function* () {
99
- var _a, _b, _c, _d, _e, _f, _g, _h;
100
- try {
101
- const res = yield (0, FileUploader_1.fileUploader)({
102
- file: selectedFile,
103
- documentName: selectedFile.name,
104
- escalationId: selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.escalationId,
105
- projectId: selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.projectDetails[0].projectId,
106
- documentUploadUrl: documentUploadUrl,
107
- bucketName: bucketName,
108
- previousFiles: (selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.isExpert) ? (_a = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.clientDocumentLinks) !== null && _a !== void 0 ? _a : [] : selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.expertDocumentlinks,
109
- isExpert: false,
110
- uploadExpertClientFiles: uploadExpertClientFiles,
111
- updateProjectEscalation: updateProjectEscalation,
112
- extraData: {
113
- clientId: selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.client.id,
114
- clientName: (_b = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.client.name) !== null && _b !== void 0 ? _b : '',
115
- email: isExpert ? (_d = (_c = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.freelancer) === null || _c === void 0 ? void 0 : _c.email) !== null && _d !== void 0 ? _d : '' : (_g = (_f = (_e = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.client) === null || _e === void 0 ? void 0 : _e.primaryContact) === null || _f === void 0 ? void 0 : _f.email) !== null && _g !== void 0 ? _g : '',
116
- freelancerId: selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.freelancer.id,
117
- freelancerName: (_h = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.freelancer.name) !== null && _h !== void 0 ? _h : '',
118
- projectName: selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.projectDetails[0].projectName,
119
- }
120
- });
121
- if (res) {
122
- setUploadFiles(prev => [...prev, ...res]);
123
- }
124
- }
125
- catch (error) {
126
- console.error("Failed to upload file", error);
127
- }
128
- finally {
129
- resolve();
130
- }
131
- });
132
- reader.readAsDataURL(selectedFile);
133
- });
134
- });
135
- try {
136
- yield Promise.all(uploadPromises);
137
- }
138
- catch (error) {
139
- console.error('Error uploading files:', error);
90
+ try {
91
+ const selectedFiles = event.target.files;
92
+ if (!selectedFiles) {
93
+ setUploadingFile(false);
94
+ return;
140
95
  }
141
- finally {
96
+ const validFiles = Array.from(selectedFiles).filter(file => (0, exports.validateFileUpload)(file));
97
+ if (validFiles.length === 0) {
142
98
  setUploadingFile(false);
99
+ return;
143
100
  }
101
+ const uploadPromises = validFiles.map((selectedFile) => {
102
+ return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
103
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
104
+ try {
105
+ const res = yield (0, FileUploader_1.fileUploader)({
106
+ file: selectedFile,
107
+ documentName: selectedFile.name,
108
+ escalationId: selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.escalationId,
109
+ projectId: (_b = (_a = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.projectDetails) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.projectId,
110
+ documentUploadUrl: documentUploadUrl,
111
+ bucketName: bucketName,
112
+ previousFiles: isExpert ? selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.clientDocumentLinks : selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.expertDocumentlinks,
113
+ isExpert: isExpert,
114
+ uploadExpertClientFiles: uploadExpertClientFiles,
115
+ updateProjectEscalation: updateProjectEscalation,
116
+ extraData: {
117
+ clientId: (_c = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.client) === null || _c === void 0 ? void 0 : _c.id,
118
+ clientName: (_e = (_d = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.client) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : '',
119
+ email: isExpert ? (_h = (_g = (_f = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.client) === null || _f === void 0 ? void 0 : _f.primaryContact) === null || _g === void 0 ? void 0 : _g.email) !== null && _h !== void 0 ? _h : '' : (_k = (_j = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.freelancer) === null || _j === void 0 ? void 0 : _j.email) !== null && _k !== void 0 ? _k : '',
120
+ freelancerId: (_l = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.freelancer) === null || _l === void 0 ? void 0 : _l.id,
121
+ freelancerName: (_o = (_m = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.freelancer) === null || _m === void 0 ? void 0 : _m.name) !== null && _o !== void 0 ? _o : '',
122
+ projectName: (_q = (_p = selectedIssue === null || selectedIssue === void 0 ? void 0 : selectedIssue.projectDetails) === null || _p === void 0 ? void 0 : _p[0]) === null || _q === void 0 ? void 0 : _q.projectName,
123
+ }
124
+ });
125
+ if (res) {
126
+ setUploadFiles(prev => [...prev, ...res]);
127
+ }
128
+ resolve();
129
+ }
130
+ catch (error) {
131
+ reject(error);
132
+ }
133
+ }));
134
+ });
135
+ yield Promise.all(uploadPromises);
136
+ }
137
+ catch (error) {
138
+ console.error('Error uploading files:', error);
139
+ }
140
+ finally {
141
+ setUploadingFile(false);
144
142
  }
145
- ;
146
143
  });
147
144
  const submitResponse = () => __awaiter(void 0, void 0, void 0, function* () {
148
145
  setSubmitting(true);
@@ -178,7 +175,9 @@ const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downl
178
175
  react_1.default.createElement(base_icons_1.IconChevronLeft, { size: "xs" }),
179
176
  " Back"),
180
177
  react_1.default.createElement("div", { className: "mb-6" },
181
- react_1.default.createElement("h2", { className: "text-xl font-bold" }, "Respond to Issue"),
178
+ react_1.default.createElement("h2", { className: "text-xl font-bold" },
179
+ "Respond to engagement #",
180
+ selectedIssue.escalationNumber),
182
181
  react_1.default.createElement("p", { className: "text-gray-600 mt-1" }, selectedIssue.problem)),
183
182
  react_1.default.createElement("div", { className: "border rounded-lg overflow-hidden mb-6" },
184
183
  react_1.default.createElement("div", { className: "bg-gray-50 p-3 border-b" },
@@ -204,11 +203,11 @@ const EscalationRespondForm = ({ goBack, selectedIssue, documentUploadUrl, downl
204
203
  react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" }, "Supporting Documents (Optional)"),
205
204
  react_1.default.createElement("div", { className: "border border-dashed border-gray-300 rounded-md p-6 text-center" },
206
205
  react_1.default.createElement("p", { className: "text-sm text-gray-600 mb-2" }, "Upload any supporting documentation"),
207
- react_1.default.createElement("input", { id: "upload-file", type: "file", multiple: true, accept: ".pdf,.doc,.docx,.jpeg,.png,.gif,.csv", style: { display: 'none' }, ref: fileInputRef, onChange: handleFileUpload }),
206
+ react_1.default.createElement("input", { id: "upload-file", type: "file", multiple: false, accept: ".pdf,.doc,.docx,.jpeg,.png,.gif,.csv,.xslx", style: { display: 'none' }, ref: fileInputRef, onChange: handleFileUpload }),
208
207
  react_1.default.createElement(base_ui_1.Button, { label: "Attach Files", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: "sm" }), onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, color: "info", className: "mx-2", isLoading: uploadingFile, size: "sm" }),
209
- processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2" },
208
+ processedDocs && processedDocs.length > 0 && (react_1.default.createElement("div", { className: "flex flex-wrap gap-2 mt-4" },
210
209
  react_1.default.createElement("span", { className: "text-sm font-bold text-gray-500 items-center" }, "Supporting Documents: "),
211
- processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1] }))))))),
210
+ processedDocs.map((d, idx) => (react_1.default.createElement(EscalationIssueCard_1.CustomTag, { key: idx, label: d.split('%2F')[1], customColor: "success" }))))))),
212
211
  react_1.default.createElement("div", { className: "bg-blue-50 border border-blue-200 rounded-md p-3" },
213
212
  react_1.default.createElement("div", { className: "flex items-center" },
214
213
  react_1.default.createElement(base_icons_1.IconInfoCircle, { size: "md" }),
@@ -100,66 +100,59 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
100
100
  }
101
101
  }, [projects, selectedUser]);
102
102
  const handleFileUpload = (event) => __awaiter(void 0, void 0, void 0, function* () {
103
- const selectedFiles = event.target.files;
104
- if (!selectedFiles)
105
- return;
106
103
  setUploadingFile(true);
107
- const validFileNames = Array.from(selectedFiles)
108
- .filter(file => (0, EscalationRespondForm_1.validateFileUpload)(file))
109
- .map(file => file.name);
110
- if (validFileNames.length === 0)
111
- return;
112
- if (validFileNames && validFileNames.length > 0) {
113
- const uploadPromises = Array.from(selectedFiles).map((selectedFile) => {
114
- return new Promise((resolve, reject) => {
115
- const reader = new FileReader();
116
- reader.onloadend = () => __awaiter(void 0, void 0, void 0, function* () {
117
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
118
- try {
119
- const res = yield (0, FileUploader_1.fileUploader)({
120
- file: selectedFile,
121
- documentName: selectedFile.name,
122
- escalationId: escalationId,
123
- projectId: selectedProjects.length > 0 ? selectedProjects[0].id : '',
124
- documentUploadUrl: documentUploadUrl,
125
- bucketName: bucketName,
126
- isExpert: false,
127
- uploadExpertClientFiles: uploadExpertClientFiles,
128
- createProjectEscalation: createProjectEscalation,
129
- extraData: {
130
- clientId: isExpert ? (_a = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.id) !== null && _a !== void 0 ? _a : 0 : clientId,
131
- clientName: isExpert ? (_b = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.name) !== null && _b !== void 0 ? _b : '' : (_c = user === null || user === void 0 ? void 0 : user.name) !== null && _c !== void 0 ? _c : '',
132
- email: isExpert ? (_e = (_d = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.primaryContact) === null || _d === void 0 ? void 0 : _d.email) !== null && _e !== void 0 ? _e : '' : (_f = user === null || user === void 0 ? void 0 : user.email) !== null && _f !== void 0 ? _f : '',
133
- freelancerId: isExpert ? (_g = user === null || user === void 0 ? void 0 : user.userId) !== null && _g !== void 0 ? _g : 0 : (_h = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.id) !== null && _h !== void 0 ? _h : 0,
134
- freelancerName: isExpert ? (_j = user === null || user === void 0 ? void 0 : user.name) !== null && _j !== void 0 ? _j : '' : (_k = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.name) !== null && _k !== void 0 ? _k : '',
135
- projectName: selectedProjects.length > 0 ? selectedProjects[0].name : '',
136
- }
137
- });
138
- if (res) {
139
- setUploadFiles(prev => [...prev, ...res]);
140
- }
141
- }
142
- catch (error) {
143
- reject(error);
144
- }
145
- finally {
146
- resolve();
147
- }
148
- });
149
- reader.readAsDataURL(selectedFile);
150
- });
151
- });
152
- try {
153
- const res = yield Promise.all(uploadPromises);
154
- }
155
- catch (error) {
156
- console.error('Error uploading files:', error);
104
+ try {
105
+ const selectedFiles = event.target.files;
106
+ if (!selectedFiles) {
107
+ setUploadingFile(false);
108
+ return;
157
109
  }
158
- finally {
110
+ const validFiles = Array.from(selectedFiles).filter(file => (0, EscalationRespondForm_1.validateFileUpload)(file));
111
+ if (validFiles.length === 0) {
159
112
  setUploadingFile(false);
113
+ return;
160
114
  }
115
+ const uploadPromises = validFiles.map((selectedFile) => {
116
+ return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
117
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
118
+ try {
119
+ const res = yield (0, FileUploader_1.fileUploader)({
120
+ file: selectedFile,
121
+ documentName: selectedFile.name,
122
+ escalationId: escalationId,
123
+ projectId: selectedProjects.length > 0 ? selectedProjects[0].id : '',
124
+ documentUploadUrl: documentUploadUrl,
125
+ bucketName: bucketName,
126
+ isExpert: isExpert,
127
+ uploadExpertClientFiles: uploadExpertClientFiles,
128
+ createProjectEscalation: createProjectEscalation,
129
+ extraData: {
130
+ clientId: isExpert ? (_a = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.id) !== null && _a !== void 0 ? _a : 0 : clientId,
131
+ clientName: isExpert ? (_b = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.name) !== null && _b !== void 0 ? _b : '' : (_c = user === null || user === void 0 ? void 0 : user.name) !== null && _c !== void 0 ? _c : '',
132
+ email: isExpert ? (_e = (_d = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.primaryContact) === null || _d === void 0 ? void 0 : _d.email) !== null && _e !== void 0 ? _e : '' : (_f = user === null || user === void 0 ? void 0 : user.email) !== null && _f !== void 0 ? _f : '',
133
+ freelancerId: isExpert ? (_g = user === null || user === void 0 ? void 0 : user.userId) !== null && _g !== void 0 ? _g : 0 : (_h = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.id) !== null && _h !== void 0 ? _h : 0,
134
+ freelancerName: isExpert ? (_j = user === null || user === void 0 ? void 0 : user.name) !== null && _j !== void 0 ? _j : '' : (_k = selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.name) !== null && _k !== void 0 ? _k : '',
135
+ projectName: selectedProjects.length > 0 ? selectedProjects[0].name : '',
136
+ }
137
+ });
138
+ if (res) {
139
+ setUploadFiles(prev => [...prev, ...res]);
140
+ }
141
+ resolve();
142
+ }
143
+ catch (error) {
144
+ reject(error);
145
+ }
146
+ }));
147
+ });
148
+ yield Promise.all(uploadPromises);
149
+ }
150
+ catch (error) {
151
+ console.error('Error uploading files:', error);
152
+ }
153
+ finally {
154
+ setUploadingFile(false);
161
155
  }
162
- ;
163
156
  });
164
157
  const isFormValid = () => {
165
158
  const requiredProjectSelection = isExpert || (!isExpert && selectedProjects.length > 0);
@@ -220,7 +213,9 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
220
213
  react_1.default.createElement(base_icons_1.IconChevronLeft, { size: "xs" }),
221
214
  " Back"),
222
215
  react_1.default.createElement("div", { className: "mb-6" },
223
- react_1.default.createElement("h2", { className: "text-xl font-bold" }, "Report Issue with Your Expert"),
216
+ react_1.default.createElement("h2", { className: "text-xl font-bold" },
217
+ "Report Issue with Your ",
218
+ isExpert ? 'Client' : 'Expert'),
224
219
  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")),
225
220
  react_1.default.createElement("div", { className: "bg-red-50 border border-red-200 rounded-lg p-4 mb-6" },
226
221
  react_1.default.createElement("div", { className: "flex items-start" },
@@ -265,9 +260,9 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
265
260
  .filter(opt => selected.includes(opt.value))
266
261
  .map(opt => opt.label)
267
262
  .join(', ');
268
- }, placeholder: `Select a Project(s)` },
263
+ }, placeholder: `Select Project(s)` },
269
264
  react_1.default.createElement(core_1.MenuItem, { disabled: true, value: "" },
270
- react_1.default.createElement("em", null, "Select a Project(s)...")),
265
+ react_1.default.createElement("em", null, "Select Project(s)...")),
271
266
  projectOptions.map(option => (react_1.default.createElement(core_1.MenuItem, { key: option.value.id, value: option.value }, option.label))))),
272
267
  react_1.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" },
273
268
  react_1.default.createElement("div", null,
@@ -278,7 +273,7 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
278
273
  issueTypeOptions
279
274
  .filter(option => {
280
275
  if (isExpert) {
281
- return option.label !== 'Billing Concern';
276
+ return option.label !== 'Billing Concern' && option.label !== 'Quality Of Work';
282
277
  }
283
278
  else {
284
279
  return option.label !== 'Scope Creep/Unauthorized Requests';
@@ -307,7 +302,7 @@ const EscalationSubmitForm = ({ goBack, goHome, expertsOrClients, projects, docu
307
302
  react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" }, "Supporting Documents (Optional)"),
308
303
  react_1.default.createElement("div", { className: "border border-dashed border-gray-300 rounded-md p-6 text-center" },
309
304
  react_1.default.createElement("p", { className: "text-sm text-gray-600 mb-2" }, "Upload screenshots, emails, or documents"),
310
- react_1.default.createElement("input", { ref: fileInputRef, type: "file", multiple: true, accept: ".pdf,.doc,.docx,.jpeg,.png,.gif,.csv", hidden: true, onChange: handleFileUpload }),
305
+ react_1.default.createElement("input", { ref: fileInputRef, type: "file", multiple: false, accept: ".pdf,.doc,.docx,.jpeg,.png,.gif,.csv, .xslx", hidden: true, onChange: handleFileUpload }),
311
306
  react_1.default.createElement(base_ui_1.Button, { label: "Attach Files", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: "sm" }), onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, color: "info", isLoading: uploadingFile, disabled: selectedUser === null, size: "sm" }),
312
307
  uploadFiles.length > 0 && (react_1.default.createElement("ul", { className: "mt-2 text-sm text-gray-600 list-disc list-inside" }, uploadFiles.map(f => react_1.default.createElement("li", { key: f.name }, f.split('%2F')[1])))))),
313
308
  react_1.default.createElement("div", { className: "bg-[#EFF6FF] p-3 rounded" },
@@ -29,6 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const react_1 = __importDefault(require("react"));
30
30
  const EscalationIssueCard_1 = __importStar(require("./EscalationIssueCard"));
31
31
  const base_ui_1 = require("@paro.io/base-ui");
32
+ const dayjs_1 = __importDefault(require("dayjs"));
32
33
  ;
33
34
  const EscalationTabsContent = ({ activeTab, openEscalationChat, setSelectedIssueId, activeIssues, inProgressIssues, resolvedIssues, isExpert, updateProjectEscalation, downloadDocumentUrl, bucketName, }) => {
34
35
  if (activeTab === 'action-required') {
@@ -48,35 +49,34 @@ const EscalationTabsContent = ({ activeTab, openEscalationChat, setSelectedIssue
48
49
  react_1.default.createElement("div", { className: "flex items-center justify-between mb-4" },
49
50
  react_1.default.createElement("h3", { className: "text-lg font-semibold text-gray-900" }, "Recently Resolved Issues")),
50
51
  resolvedIssues.length > 0 ? react_1.default.createElement("div", { className: "space-y-3" }, resolvedIssues.map((issue) => {
51
- const project = issue.projectName && Array.isArray(issue.projectName) && issue.projectName.length > 0
52
- ? `${issue.projectName[0]}${issue.projectName.length > 1 ? ` +${issue.projectName.length - 1} more` : ''} `
52
+ var _a;
53
+ const project = issue.projectDetails && Array.isArray(issue.projectDetails) && issue.projectDetails.length > 0
54
+ ? `${(_a = issue.projectDetails[0]) === null || _a === void 0 ? void 0 : _a.projectName}${issue.projectDetails.length > 1 ? ` +${issue.projectDetails.length - 1} more` : ''} `
53
55
  : '';
54
- return (react_1.default.createElement("div", { key: issue.id, className: "border border-green-200 rounded-lg bg-green-50 p-4" },
56
+ return (react_1.default.createElement("div", { key: issue.escalationNumber, className: "border border-green-200 rounded-lg bg-green-50 p-4" },
55
57
  react_1.default.createElement("div", { className: "flex items-start justify-between" },
56
58
  react_1.default.createElement("div", { className: "flex items-start" },
57
59
  react_1.default.createElement("div", null,
58
- react_1.default.createElement("div", { className: "flex flex-row justify-between" },
59
- react_1.default.createElement("h4", { className: "font-medium text-gray-900 mb-1" },
60
- issue.problem,
61
- " ",
62
- react_1.default.createElement(EscalationIssueCard_1.CustomTag, { label: issue.severityLevel }))),
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),
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.person),
64
+ react_1.default.createElement("span", null, issue.submittedByUser.firstName + " " + issue.submittedByUser.lastName),
65
65
  react_1.default.createElement("span", { className: "mx-2" }, "\u2022"),
66
66
  react_1.default.createElement("span", null, project),
67
67
  react_1.default.createElement("span", { className: "mx-2" }, "\u2022"),
68
68
  react_1.default.createElement("span", null,
69
69
  "Case #",
70
- issue.id)),
71
- react_1.default.createElement("p", { className: "text-sm text-gray-600 mb-3" }, issue.description),
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),
72
72
  react_1.default.createElement("div", { className: "flex items-center text-sm text-gray-600 mb-2" },
73
73
  react_1.default.createElement("span", { className: "text-xs text-gray-500" },
74
74
  "Resolved ",
75
- issue.resolvedDate),
75
+ (0, dayjs_1.default)(issue.updatedAt).format("MM-DD-YYYY")),
76
76
  react_1.default.createElement("span", { className: "mx-2" }, "\u2022"),
77
77
  react_1.default.createElement("span", { className: "text-xs text-gray-500" },
78
78
  "Resolved By ",
79
- issue.resolvedBy)))),
79
+ issue.statusChangedByUser.firstName + " " + issue.statusChangedByUser.lastName)))),
80
80
  react_1.default.createElement(base_ui_1.Button, { onClick: () => openEscalationChat(issue), label: "Chat", color: "primary" }))));
81
81
  }))
82
82
  :
@@ -56,11 +56,11 @@ const Escalations = ({ expertsOrClients, projects, isExpert = false, escalations
56
56
  const isRelevantEscalation = (isExpert
57
57
  ? (internalEscalationTo === 'expert' || internalEscalationTo === 'both')
58
58
  : (internalEscalationTo === 'client' || internalEscalationTo === 'both'));
59
- return ((userTypeId !== user.userTypeId ||
59
+ return (((userTypeId !== user.userTypeId && (isExpert ? issue.expertResponse === null : issue.clientResponse === null)) || //once responded will move to inProgress from active issues
60
60
  (userTypeId === 2 && isRelevantEscalation)) &&
61
61
  status === 'InProgress');
62
62
  });
63
- 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 && (issue === null || issue === void 0 ? void 0 : issue.status) === 'InProgress'; });
63
+ 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'; });
64
64
  const resolvedIssues = escalations.filter(issue => (issue === null || issue === void 0 ? void 0 : issue.status) === 'Resolved');
65
65
  const goBack = () => {
66
66
  if (selectedIssueId !== null) {
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ declare const MarkResolvedModal: ({ escalationId, expertName, open, onClose, updateProjectEscalation, }: {
3
+ escalationId: string;
4
+ expertName: string;
5
+ open: boolean;
6
+ onClose: () => void;
7
+ updateProjectEscalation: any;
8
+ }) => React.JSX.Element;
9
+ export default MarkResolvedModal;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ const react_1 = __importStar(require("react"));
36
+ const base_icons_1 = require("@paro.io/base-icons");
37
+ const base_ui_1 = require("@paro.io/base-ui");
38
+ const core_1 = require("@material-ui/core");
39
+ const utils_1 = require("../shared/utils");
40
+ const MarkResolvedModal = ({ escalationId, expertName, open, onClose, updateProjectEscalation, }) => {
41
+ const [resolutionText, setResolutionText] = (0, react_1.useState)(null);
42
+ const [submitting, setSubmitting] = (0, react_1.useState)(false);
43
+ const handleSubmit = () => __awaiter(void 0, void 0, void 0, function* () {
44
+ setSubmitting(true);
45
+ try {
46
+ yield updateProjectEscalation({
47
+ variables: {
48
+ input: {
49
+ escalationId: escalationId,
50
+ clientResolution: resolutionText,
51
+ status: 'Resolved'
52
+ }
53
+ }
54
+ });
55
+ (0, utils_1.showToast)("success", "Escalation marked as resolved!");
56
+ }
57
+ catch (error) {
58
+ console.error("Failed to update escalation!", error);
59
+ (0, utils_1.showToast)("warning", "Failed to update escalation!");
60
+ }
61
+ finally {
62
+ setSubmitting(false);
63
+ onClose();
64
+ }
65
+ });
66
+ return (react_1.default.createElement(core_1.Dialog, { open: open, onClose: onClose, maxWidth: 'sm' },
67
+ react_1.default.createElement(core_1.DialogTitle, null,
68
+ react_1.default.createElement("div", { className: "text-black mb-1 p-2 pl-4 absolute top-0 left-0 w-full flex flex-row justify-between items-center z-50" },
69
+ react_1.default.createElement("div", { className: "flex flex-col items-start" },
70
+ react_1.default.createElement("h1", { className: "text-md font-medium mr-2" },
71
+ "Engagement Issue with ",
72
+ expertName)),
73
+ react_1.default.createElement("div", { className: "flex items-center space-x-4" },
74
+ react_1.default.createElement(core_1.IconButton, { onClick: onClose },
75
+ react_1.default.createElement(base_icons_1.IconX, null))))),
76
+ react_1.default.createElement(core_1.DialogContent, null,
77
+ react_1.default.createElement("div", { className: "mt-6 mb-4" },
78
+ 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."),
79
+ react_1.default.createElement(base_ui_1.Input, { type: "text", value: resolutionText, placeholder: "Enter details here...", onChange: (e) => setResolutionText(e.target.value) })),
80
+ react_1.default.createElement("div", { className: "flex items-center justify-between" },
81
+ react_1.default.createElement("div", { className: "flex space-x-2" },
82
+ react_1.default.createElement(base_ui_1.Button, { label: "Cancel", onClick: onClose, disabled: submitting })),
83
+ react_1.default.createElement("div", { className: "flex space-x-2" },
84
+ react_1.default.createElement(base_ui_1.Button, { label: "Submit", color: "primary", onClick: handleSubmit, isLoading: submitting }))))));
85
+ };
86
+ exports.default = MarkResolvedModal;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ declare const ViewResponseModal: ({ response, open, onClose, isExpert }: {
3
+ response: string | null;
4
+ open: boolean;
5
+ onClose: () => void;
6
+ isExpert: boolean;
7
+ }) => React.JSX.Element;
8
+ export default ViewResponseModal;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = __importDefault(require("react"));
7
+ const base_icons_1 = require("@paro.io/base-icons");
8
+ const core_1 = require("@material-ui/core");
9
+ const ViewResponseModal = ({ response, open, onClose, isExpert }) => {
10
+ return (react_1.default.createElement(core_1.Dialog, { open: open, onClose: onClose, maxWidth: 'sm' },
11
+ react_1.default.createElement(core_1.DialogTitle, null,
12
+ react_1.default.createElement("div", { className: "text-black mb-1 p-2 pl-4 absolute top-0 left-0 w-full flex flex-row justify-between items-center z-50" },
13
+ react_1.default.createElement("div", { className: "flex flex-col items-start" },
14
+ react_1.default.createElement("h1", { className: "text-md font-bold mr-2" }, isExpert ? 'Client Response' : 'Expert Response')),
15
+ react_1.default.createElement("div", { className: "flex items-center space-x-4" },
16
+ react_1.default.createElement(core_1.IconButton, { onClick: onClose },
17
+ react_1.default.createElement(base_icons_1.IconX, null))))),
18
+ react_1.default.createElement(core_1.DialogContent, null,
19
+ react_1.default.createElement("div", { className: "bg-green-50 border-green-800 border border-l-4 rounded p-4 mt-4 mb-4" },
20
+ react_1.default.createElement("p", { className: "text-sm font-medium" },
21
+ "Status: ",
22
+ react_1.default.createElement("span", { className: "font-normal" }, "Responded")),
23
+ react_1.default.createElement("p", { className: "text-sm font-medium" },
24
+ "Response: ",
25
+ react_1.default.createElement("span", { className: "font-normal" }, response))))));
26
+ };
27
+ exports.default = ViewResponseModal;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ declare const ViewResponseModal: ({ response, open, onClose, isExpert }: {
3
+ response: string | null;
4
+ open: boolean;
5
+ onClose: () => void;
6
+ isExpert: boolean;
7
+ }) => React.JSX.Element;
8
+ export default ViewResponseModal;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = __importDefault(require("react"));
7
+ const base_icons_1 = require("@paro.io/base-icons");
8
+ const core_1 = require("@material-ui/core");
9
+ const ViewResponseModal = ({ response, open, onClose, isExpert }) => {
10
+ return (react_1.default.createElement(core_1.Dialog, { open: open, onClose: onClose, maxWidth: 'sm' },
11
+ react_1.default.createElement(core_1.DialogTitle, null,
12
+ react_1.default.createElement("div", { className: "text-black mb-1 p-2 pl-4 absolute top-0 left-0 w-full flex flex-row justify-between items-center z-50" },
13
+ react_1.default.createElement("div", { className: "flex flex-col items-start" },
14
+ react_1.default.createElement("h1", { className: "text-md font-bold mr-2" }, isExpert ? 'Client Response' : 'Expert Response')),
15
+ react_1.default.createElement("div", { className: "flex items-center space-x-4" },
16
+ react_1.default.createElement(core_1.IconButton, { onClick: onClose },
17
+ react_1.default.createElement(base_icons_1.IconX, null))))),
18
+ react_1.default.createElement(core_1.DialogContent, null,
19
+ react_1.default.createElement("div", { className: "bg-green-50 border-green-800 border border-l-4 rounded p-4 mt-4 mb-4" },
20
+ react_1.default.createElement("p", { className: "text-sm font-medium" },
21
+ "Status: ",
22
+ react_1.default.createElement("span", { className: "font-normal" }, "Responded")),
23
+ react_1.default.createElement("p", { className: "text-sm font-medium" },
24
+ "Response: ",
25
+ react_1.default.createElement("span", { className: "font-normal" }, response))))));
26
+ };
27
+ exports.default = ViewResponseModal;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paro.io/expert-shared-components",
3
- "version": "1.12.50",
3
+ "version": "1.12.52",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {