@paro.io/expert-shared-components 1.11.1 → 1.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,6 @@ interface ChatMessages {
8
8
  firstName: string;
9
9
  lastName: string;
10
10
  userTypeId: number;
11
- avatar: string | null;
12
11
  };
13
12
  messageText: string;
14
13
  visibility: "ALL" | "INTERNAL_ONLY" | "CLIENT_INTERNAL_ONLY" | "EXPERT_INTERNAL_ONLY";
@@ -20,6 +19,7 @@ interface DiscussionThreadProps {
20
19
  currentUser: any;
21
20
  initialThreads: ChatMessages[] | [];
22
21
  createDisputeChatMessage: any;
22
+ disputeId: number;
23
23
  }
24
- export declare const DiscussionThread: ({ currentUser, initialThreads, createDisputeChatMessage, }: DiscussionThreadProps) => React.JSX.Element;
24
+ export declare const DiscussionThread: ({ currentUser, initialThreads, createDisputeChatMessage, disputeId, }: DiscussionThreadProps) => React.JSX.Element;
25
25
  export {};
@@ -22,52 +22,75 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
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
+ };
25
34
  Object.defineProperty(exports, "__esModule", { value: true });
26
35
  exports.DiscussionThread = void 0;
27
36
  const react_1 = __importStar(require("react"));
28
37
  const base_ui_1 = require("@paro.io/base-ui");
29
- const DiscussionThread = ({ currentUser, initialThreads, createDisputeChatMessage, }) => {
38
+ const DiscussionThread = ({ currentUser, initialThreads, createDisputeChatMessage, disputeId, }) => {
30
39
  const [messages, setMessages] = (0, react_1.useState)(initialThreads);
40
+ const [sending, setSending] = (0, react_1.useState)(false);
31
41
  const [comment, setComment] = (0, react_1.useState)("");
32
42
  const threadsEndRef = (0, react_1.useRef)(null);
33
- const [invalid, setInvalid] = (0, react_1.useState)(false);
43
+ const didMountRef = (0, react_1.useRef)(false);
34
44
  // Auto scroll to bottom when messages change
35
45
  (0, react_1.useEffect)(() => {
36
- var _a;
37
- (_a = threadsEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
38
- }, [messages]);
39
- const handleSend = () => {
40
- setInvalid(false);
41
- if (comment) {
42
- createDisputeChatMessage();
43
- handleSendMessage();
44
- setComment("");
46
+ if (didMountRef.current) {
47
+ if (threadsEndRef.current) {
48
+ threadsEndRef.current.scrollIntoView({ behavior: "smooth" });
49
+ }
45
50
  }
46
51
  else {
47
- setInvalid(true);
52
+ didMountRef.current = true;
48
53
  }
49
- };
50
- const handleSendMessage = () => {
51
- const newMsg = {
52
- messageId: 0, // update required
53
- disputeId: messages[0].disputeId,
54
- sender: {
55
- id: currentUser.id,
56
- email: currentUser.email,
57
- firstName: currentUser.name.split(' ')[0] || '',
58
- lastName: currentUser.name.split(' ')[1] || '',
59
- userTypeId: currentUser.userTypeId,
60
- avatar: currentUser.avatar,
61
- },
62
- messageText: comment,
63
- visibility: "ALL",
64
- createdAt: new Date().toISOString(),
65
- updatedAt: new Date().toISOString(),
66
- isDeleted: false,
67
- };
68
- setMessages([...messages, newMsg]);
69
- setComment("");
70
- };
54
+ }, [messages]);
55
+ const handleSend = () => __awaiter(void 0, void 0, void 0, function* () {
56
+ setSending(true);
57
+ try {
58
+ if (comment) {
59
+ const chatInput = {
60
+ disputeId: disputeId,
61
+ messageText: comment,
62
+ senderId: currentUser === null || currentUser === void 0 ? void 0 : currentUser.userId,
63
+ visibility: "ALL"
64
+ };
65
+ yield createDisputeChatMessage({
66
+ variables: {
67
+ input: chatInput
68
+ }
69
+ }).then((res) => {
70
+ const newMsg = {
71
+ messageId: res.data.createDisputeChatMessage.messageId,
72
+ disputeId: res.data.createDisputeChatMessage.disputeId,
73
+ sender: res.data.createDisputeChatMessage.sender,
74
+ messageText: res.data.createDisputeChatMessage.messageText,
75
+ visibility: res.data.createDisputeChatMessage.visibility,
76
+ createdAt: res.data.createDisputeChatMessage.createdAt,
77
+ updatedAt: res.data.createDisputeChatMessage.updatedAt,
78
+ isDeleted: res.data.createDisputeChatMessage.isDeleted,
79
+ };
80
+ setMessages([...messages, newMsg]);
81
+ setComment("");
82
+ }).catch((error) => {
83
+ console.error("Error creating dispute chat message:", error);
84
+ });
85
+ }
86
+ }
87
+ catch (error) {
88
+ console.error("Error sending message:", error);
89
+ }
90
+ finally {
91
+ setSending(false);
92
+ }
93
+ });
71
94
  const handleKeyPress = (e) => {
72
95
  if (e.key === "Enter" && !e.shiftKey) {
73
96
  e.preventDefault();
@@ -87,29 +110,28 @@ const DiscussionThread = ({ currentUser, initialThreads, createDisputeChatMessag
87
110
  .toUpperCase()
88
111
  .substring(0, 2);
89
112
  };
90
- return (react_1.default.createElement("div", { className: "flex flex-col w-full rounded-lg bg-white px-4 h-auto" },
113
+ return (react_1.default.createElement("div", { className: "flex flex-col w-full rounded-lg bg-white h-auto" },
91
114
  react_1.default.createElement("div", { className: `py-3 flex items-center` },
92
115
  react_1.default.createElement("div", { className: "font-semibold text-gray-800 capitalize" }, "Discussion Thread")),
93
- react_1.default.createElement("div", { className: "flex-1 max-h-[30vh] overflow-y-auto border rounded-md p-2" },
116
+ messages.length ? react_1.default.createElement("div", { className: "flex-1 max-h-[30vh] overflow-y-auto border rounded-md p-2" },
94
117
  messages.map((message) => {
95
- var _a;
96
- const isCurrentUser = currentUser.id === message.sender.id;
118
+ const isCurrentUser = currentUser.userId === message.sender.id;
97
119
  const userName = message.sender.firstName + message.sender.lastName;
98
120
  const timestamp = message.updatedAt ? message.updatedAt : message.createdAt;
99
121
  return (react_1.default.createElement("div", { key: message.messageId, className: `flex mb-4 ${isCurrentUser ? 'justify-end' : 'justify-start'}` },
100
- !isCurrentUser && (react_1.default.createElement("div", { className: "flex-shrink-0 mr-2" }, ((_a = message.sender) === null || _a === void 0 ? void 0 : _a.avatar) ? (react_1.default.createElement("img", { src: message.sender.avatar, alt: userName, className: "h-8 w-8 rounded-full" })) : (react_1.default.createElement("div", { className: `h-8 w-8 rounded-full bg-gray-400 flex items-center justify-center text-white text-xs font-medium ${isCurrentUser ? 'bg-[#255b5c]' : 'bg-[#5f4508]'}` }, getInitials(userName || 'User'))))),
101
- react_1.default.createElement("div", { className: `${isCurrentUser ? 'order-1' : 'order-2'} ml-1 min-w-min max-w-[75%] break-words` },
122
+ !isCurrentUser && (react_1.default.createElement("div", { className: "flex-shrink-0 mr-2" },
123
+ react_1.default.createElement("div", { className: "h-8 w-8 rounded-full bg-gray-400 flex items-center justify-center text-white text-xs font-medium bg-[#5f4508]" }, getInitials(userName || 'User')))),
124
+ react_1.default.createElement("div", { className: `ml-1 min-w-min max-w-[75%] break-words` },
102
125
  !isCurrentUser && (react_1.default.createElement("div", { className: "text-xs text-gray-500 font-medium mb-1" }, userName || 'Unknown User')),
103
126
  react_1.default.createElement("div", { className: `px-4 py-2 rounded-lg ${isCurrentUser
104
127
  ? 'bg-[#dbefef] rounded-br-none'
105
128
  : 'bg-[#f9d8a7] border rounded-bl-none'}` }, message.messageText),
106
- react_1.default.createElement("div", { className: "text-xs text-gray-500 mt-1" }, formatTime(timestamp))),
107
- isCurrentUser && (react_1.default.createElement("div", { className: "flex-shrink-0 ml-2" }, (currentUser === null || currentUser === void 0 ? void 0 : currentUser.avatar) ? (react_1.default.createElement("img", { src: currentUser.avatar, alt: currentUser.name, className: "h-8 w-8 rounded-full" })) : (react_1.default.createElement("div", { className: "h-8 w-8 rounded-full bg-blue-400 flex items-center justify-center text-white text-xs font-medium" }, getInitials((currentUser === null || currentUser === void 0 ? void 0 : currentUser.name) || 'You')))))));
129
+ react_1.default.createElement("div", { className: "text-xs text-gray-500 mt-1" }, formatTime(timestamp)))));
108
130
  }),
109
- react_1.default.createElement("div", { ref: threadsEndRef })),
131
+ react_1.default.createElement("div", { ref: threadsEndRef })) : react_1.default.createElement(react_1.default.Fragment, null),
110
132
  react_1.default.createElement("div", { className: "py-3" },
111
133
  react_1.default.createElement("div", { className: "flex items-center" },
112
134
  react_1.default.createElement("textarea", { value: comment, onChange: (e) => setComment(e.target.value), onKeyDown: handleKeyPress, placeholder: "Type your message here...", className: "flex-1 border rounded-lg px-3 py-2 resize-none focus:outline-none focus:ring-2 focus:ring-blue-500", rows: 1 }),
113
- react_1.default.createElement(base_ui_1.Button, { label: "Send", onClick: handleSend, disabled: !comment.trim(), color: "primary", className: "ml-2 px-4 py-2" })))));
135
+ react_1.default.createElement(base_ui_1.Button, { label: "Send", onClick: handleSend, disabled: !comment.trim(), isLoading: sending, color: "primary", className: "ml-2 px-4 py-2" })))));
114
136
  };
115
137
  exports.DiscussionThread = DiscussionThread;
@@ -1,5 +1,9 @@
1
- export declare const InvoiceCard: ({ clientInvoice, createDisputeChatMessage, user }: {
2
- clientInvoice: any;
1
+ interface InvoiceCardProps {
2
+ clientInvoice?: any;
3
3
  createDisputeChatMessage: any;
4
4
  user: any;
5
- }) => JSX.Element;
5
+ chatMessages: any[];
6
+ updateClientInvoiceMutation: any;
7
+ }
8
+ export declare const InvoiceCard: ({ clientInvoice, createDisputeChatMessage, user, chatMessages, updateClientInvoiceMutation }: InvoiceCardProps) => JSX.Element;
9
+ export {};
@@ -22,6 +22,18 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
25
37
  Object.defineProperty(exports, "__esModule", { value: true });
26
38
  exports.InvoiceCard = void 0;
27
39
  const react_1 = __importStar(require("react"));
@@ -30,6 +42,8 @@ const base_ui_2 = require("@paro.io/base-ui");
30
42
  const core_1 = require("@material-ui/core");
31
43
  const base_icons_1 = require("@paro.io/base-icons");
32
44
  const DiscussionThread_1 = require("../DiscussionThread");
45
+ const dayjs_1 = __importDefault(require("dayjs"));
46
+ const utils_1 = require("../shared/utils");
33
47
  const useStyles = (0, core_1.makeStyles)((theme) => ({
34
48
  root: {
35
49
  width: "100%",
@@ -80,6 +94,9 @@ const ACCEPTED_FILE_TYPES = [
80
94
  'application/pdf',
81
95
  'application/msword',
82
96
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
97
+ 'image/jpeg',
98
+ 'image/png',
99
+ 'text/csv',
83
100
  ];
84
101
  const validateFileUpload = (file) => {
85
102
  if (!file) {
@@ -88,18 +105,22 @@ const validateFileUpload = (file) => {
88
105
  if (!ACCEPTED_FILE_TYPES.includes(file.type)) {
89
106
  return false;
90
107
  }
91
- if (file.size > 5242880) { //5MB size
92
- return false;
93
- }
94
108
  return true;
95
109
  };
96
- const InvoiceCard = ({ clientInvoice, createDisputeChatMessage, user }) => {
110
+ const InvoiceCard = ({ clientInvoice, createDisputeChatMessage, user, chatMessages, updateClientInvoiceMutation }) => {
111
+ var _a, _b, _c, _d, _e, _f;
97
112
  const [expandRow, setExpandRow] = (0, react_1.useState)(null);
98
113
  const classes = useStyles();
99
- const [projects, setProjects] = (0, react_1.useState)(clientInvoice.disputeProjects);
114
+ const [projects, setProjects] = (0, react_1.useState)(clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.disputeProjects);
100
115
  const [editingRowId, setEditingRowId] = (0, react_1.useState)(null);
101
116
  const [editedExplanation, setEditedExplanation] = (0, react_1.useState)('');
102
- const [discussion, setDiscussion] = (0, react_1.useState)('');
117
+ const [updatedDispute, setUpdateDispute] = (0, react_1.useState)(false);
118
+ const [updatingDispute, setUpdatingDispute] = (0, react_1.useState)(false);
119
+ (0, react_1.useEffect)(() => {
120
+ if (JSON.stringify(clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.disputeProjects) !== JSON.stringify(projects)) {
121
+ setUpdateDispute(true);
122
+ }
123
+ }, [projects]);
103
124
  const fileInputRef = (0, react_1.useRef)(null);
104
125
  const handleChange = (e, field) => {
105
126
  const updatedProject = field === "clientDocumentLinks" ? projects.map((project) => {
@@ -127,107 +148,116 @@ const InvoiceCard = ({ clientInvoice, createDisputeChatMessage, user }) => {
127
148
  fileInputRef.current.value = '';
128
149
  }
129
150
  };
130
- return (react_1.default.createElement(base_ui_1.Card, { className: `mx-2 my-4 md:mx-8 flex md:flex items-center justify-between rounded flex-col` },
131
- react_1.default.createElement("div", { key: clientInvoice.invoice.id, className: "bg-[#0F172A] text-white mb-1 p-4 relative top-0 left-0 w-full rounded flex flex-row justify-evenly" },
151
+ const handleEditExplanation = (projectId) => __awaiter(void 0, void 0, void 0, function* () {
152
+ setProjects((prev) => prev.map((p) => p.projectId === projectId
153
+ ? Object.assign(Object.assign({}, p), { clientExplanation: editedExplanation }) : p));
154
+ setEditingRowId(null);
155
+ });
156
+ const handleSubmitDispute = () => __awaiter(void 0, void 0, void 0, function* () {
157
+ setUpdatingDispute(true);
158
+ try {
159
+ yield updateClientInvoiceMutation({
160
+ variables: {
161
+ input: {
162
+ disputeId: projects[0].id,
163
+ projectDisputes: projects.map((project) => ({
164
+ projectId: project.projectId,
165
+ disputeReasonCode: project.disputeReasonCode,
166
+ disputeType: project.disputeType,
167
+ disputeHours: project.disputeHours,
168
+ disputeAmount: project.disputeAmount,
169
+ clientExplanation: project.clientExplanation,
170
+ clientDocumentLinks: project.clientDocumentLinks,
171
+ })),
172
+ }
173
+ }
174
+ }).then(() => {
175
+ (0, utils_1.showToast)('success', 'Dispute updation successfull!');
176
+ });
177
+ }
178
+ catch (error) {
179
+ console.error("Failed to update dispute", error);
180
+ (0, utils_1.showToast)('warning', 'Failed to update dispute');
181
+ }
182
+ finally {
183
+ setUpdatingDispute(false);
184
+ setUpdateDispute(false);
185
+ }
186
+ });
187
+ return (react_1.default.createElement(base_ui_1.Card, { className: `mx-1 my-4 md:mx-8 flex md:flex items-center justify-between rounded flex-col` },
188
+ react_1.default.createElement("div", { key: (_a = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.invoice) === null || _a === void 0 ? void 0 : _a.id, className: "bg-[#0F172A] text-white mb-1 p-4 relative top-0 left-0 w-full rounded flex flex-row justify-between" },
132
189
  react_1.default.createElement("b", null,
133
- "Dispute Invoice #",
134
- clientInvoice.invoice.id),
190
+ "Dispute Invoice #", (_b = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.invoice) === null || _b === void 0 ? void 0 :
191
+ _b.id),
135
192
  react_1.default.createElement("p", null,
136
- "Disputed: ",
193
+ "Dispute Date: ", clientInvoice === null || clientInvoice === void 0 ? void 0 :
137
194
  clientInvoice.disputeDate),
138
195
  react_1.default.createElement("p", null,
139
- "Invoice Date: ",
140
- clientInvoice.invoice.dateGenerated)),
141
- react_1.default.createElement("div", { className: "flex flex-row justify-start items-center gap-2" },
142
- clientInvoice && // for in progress
143
- react_1.default.createElement(base_ui_1.Tag, { color: "warning", label: "In Progress", variant: "subtle" }),
144
- clientInvoice && // for resolved
145
- react_1.default.createElement(base_ui_1.Tag, { color: "success", label: "Resolved", variant: "subtle" }),
146
- clientInvoice && // for submitted
147
- react_1.default.createElement(base_ui_1.Tag, { color: "danger", label: "Submitted", variant: "subtle" }),
148
- clientInvoice && // for acion taken
149
- react_1.default.createElement(base_ui_1.Tag, { color: "success", label: "Invoice reduced", variant: "subtle" }),
150
- clientInvoice && // for editable upto
151
- react_1.default.createElement(base_ui_1.Tag, { color: "warning", label: "Editable until May 30", variant: "subtle" }),
152
- clientInvoice && // for under review
153
- react_1.default.createElement(base_ui_1.Tag, { color: "info", label: "Under Review", variant: "subtle" }),
154
- react_1.default.createElement("div", { className: "flex ml-2 items-center" }, "Last updated: date")),
196
+ "Invoice Date: ", (_c = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.invoice) === null || _c === void 0 ? void 0 :
197
+ _c.dateGenerated),
198
+ react_1.default.createElement("p", null,
199
+ "Expert Name: ",
200
+ ((_d = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.freelancer) === null || _d === void 0 ? void 0 : _d.firstName) + " " + ((_e = clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.freelancer) === null || _e === void 0 ? void 0 : _e.lastName))),
155
201
  react_1.default.createElement("div", { className: "w-[95%] m-2" },
202
+ react_1.default.createElement("div", { className: "flex flex-row justify-start items-center gap-4 mr-auto mb-2" },
203
+ react_1.default.createElement("div", null,
204
+ (clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.status) === 'InProgress' &&
205
+ react_1.default.createElement(base_ui_1.Tag, { color: "warning", label: "In Progress", variant: "subtle" }),
206
+ (clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.status) === 'Resolved' &&
207
+ react_1.default.createElement(base_ui_1.Tag, { color: "success", label: "Resolved", variant: "subtle" }),
208
+ (clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.status) === 'UnderReview' &&
209
+ react_1.default.createElement(base_ui_1.Tag, { color: "info", label: "Under Review", variant: "subtle" })),
210
+ react_1.default.createElement("div", { className: "flex items-center" },
211
+ "Last updated: ",
212
+ (0, dayjs_1.default)(clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.disputeUpdatedDate).format("YYYY-MM-DD"))),
156
213
  react_1.default.createElement(core_1.Table, { className: classes.table, "aria-labelledby": "tableTitle", size: 'medium', "aria-label": "enhanced table" },
157
214
  react_1.default.createElement(core_1.TableHead, { className: classes.tableHead },
158
215
  react_1.default.createElement(core_1.TableRow, null,
159
216
  headCells.map((headcell) => {
160
217
  return react_1.default.createElement(core_1.TableCell, { key: headcell.id, className: classes.tableCell }, headcell.label);
161
218
  }),
162
- react_1.default.createElement(core_1.TableCell, { className: classes.tableCell }))),
163
- projects.map((row) => (react_1.default.createElement(react_1.default.Fragment, null,
164
- react_1.default.createElement(core_1.TableRow, { key: row.projectId },
165
- react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, row.project.name),
166
- react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, row.disputeType),
167
- react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, row.hours),
168
- react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, row.disputeAmount),
169
- react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, row.disputeReasonCode),
170
- react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell },
171
- react_1.default.createElement(core_1.IconButton, { onClick: () => { setExpandRow(expandRow === row.projectId ? null : row.projectId); } }, expandRow === row.projectId ? react_1.default.createElement(base_icons_1.IconChevronUp, null) : react_1.default.createElement(base_icons_1.IconChevronDown, null)))),
172
- expandRow &&
219
+ react_1.default.createElement(core_1.TableCell, { className: classes.tableCell }))), projects === null || projects === void 0 ? void 0 :
220
+ projects.map((row) => {
221
+ var _a;
222
+ return (react_1.default.createElement(react_1.default.Fragment, { key: row.projectId },
173
223
  react_1.default.createElement(core_1.TableRow, null,
224
+ react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, ((_a = row.project) === null || _a === void 0 ? void 0 : _a.name) || "N/A"),
225
+ react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, row.disputeType),
226
+ react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, row.disputeHours),
227
+ react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, row.disputeAmount),
228
+ react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell }, row.disputeReasonCode),
229
+ react_1.default.createElement(core_1.TableCell, { align: "left", className: classes.tableCell },
230
+ react_1.default.createElement(core_1.IconButton, { onClick: () => setExpandRow(expandRow === row.projectId ? null : row.projectId) }, expandRow === row.projectId ? react_1.default.createElement(base_icons_1.IconChevronUp, null) : react_1.default.createElement(base_icons_1.IconChevronDown, null)))),
231
+ expandRow === row.projectId && (react_1.default.createElement(core_1.TableRow, { key: `expanded-${row.projectId}` },
174
232
  react_1.default.createElement(core_1.TableCell, { colSpan: headCells.length + 1, style: { paddingBottom: 0, paddingTop: 0 } },
175
- react_1.default.createElement(core_1.Collapse, { in: expandRow === row.projectId, timeout: "auto", unmountOnExit: true },
233
+ react_1.default.createElement(core_1.Collapse, { in: true, timeout: "auto", unmountOnExit: true },
176
234
  react_1.default.createElement(react_1.default.Fragment, null,
177
- react_1.default.createElement(base_ui_1.Card, { className: `bg-[#F8F9FA] m-2 md:mx-8 flex md:flex items-start justify-between rounded flex-col w-[95%] p-6` },
235
+ react_1.default.createElement(base_ui_1.Card, { className: "bg-[#F8F9FA] m-2 flex items-start justify-between rounded flex-col w-full p-6" },
178
236
  react_1.default.createElement("b", { className: "mb-2 flex flex-row justify-start items-center" },
179
237
  "Explanation:",
180
238
  editingRowId === row.projectId ? (react_1.default.createElement(react_1.default.Fragment, null,
181
239
  react_1.default.createElement(base_ui_2.Input, { label: "", type: "text", className: "w-96 mx-4 overflow-ellipsis", value: editedExplanation, onChange: (e) => setEditedExplanation(e.target.value), placeholder: "Please provide an explanation", isInvalid: !editedExplanation, isInvalidText: "Please provide an explanation" }),
182
- react_1.default.createElement(base_ui_2.Button, { label: "Save", size: "md", color: "success", className: "ml-2 mt-1", onClick: () => {
183
- setProjects((prev) => prev.map((p) => p.projectId === row.projectId
184
- ? Object.assign(Object.assign({}, p), { clientExplanation: editedExplanation }) : p));
185
- setEditingRowId(null);
186
- } }))) : (react_1.default.createElement(base_ui_2.Button, { label: "Edit", iconLeft: react_1.default.createElement(base_icons_1.IconPencil, { size: 'sm' }), onClick: () => {
240
+ react_1.default.createElement(base_ui_2.Button, { label: "Save", size: "md", color: "success", className: "ml-2 mt-1", onClick: () => { handleEditExplanation(row.projectId); } }))) : (react_1.default.createElement(base_ui_2.Button, { label: "Edit", iconLeft: react_1.default.createElement(base_icons_1.IconPencil, { size: "sm" }), onClick: () => {
187
241
  setEditedExplanation(row.clientExplanation);
188
242
  setEditingRowId(row.projectId);
189
243
  }, size: "sm", color: "info", className: "ml-6" }))),
190
244
  react_1.default.createElement("p", null, row.clientExplanation),
191
245
  react_1.default.createElement("b", { className: "flex flex-row flex-wrap justify-start items-center mt-2" },
192
246
  "Supporting Documents:",
193
- react_1.default.createElement("input", { id: "upload-file", type: "file", multiple: true, accept: ".pdf,.doc,.docx", style: { display: 'none' }, ref: fileInputRef, onChange: handleUpload }),
194
- react_1.default.createElement(base_ui_2.Button, { label: "Add File", iconLeft: react_1.default.createElement(base_icons_1.IconPlus, { size: 'sm' }), onClick: () => { fileInputRef.current && fileInputRef.current.click(); }, size: 'sm', color: "info", className: "mx-2" }),
195
- row.clientDocumentLinks.map((f) => {
196
- return react_1.default.createElement("div", { className: "mx-2" },
197
- react_1.default.createElement(base_ui_1.Tag, { variant: "subtle", color: "success", label: f, iconRight: react_1.default.createElement(base_icons_1.IconXCircle, null), onClick: () => {
198
- const updatedFiles = projects.map((p) => {
199
- const updatedFiles = p.files.filter((file) => file !== f);
200
- return Object.assign(Object.assign({}, p), { files: updatedFiles });
201
- });
202
- setProjects(updatedFiles);
203
- } }));
204
- }))),
205
- react_1.default.createElement("b", { className: "ml-8 mt-4 mr-auto" }, "Discussion: "),
206
- react_1.default.createElement(base_ui_1.Card, { className: `bg-[#EFF6FF] m-2 md:mx-8 flex md:flex justify-start rounded flex-col w-[95%] p-4` }, row.discussion.map((obj) => {
207
- return obj.paroSupport ?
208
- react_1.default.createElement("div", { className: "flex flex-row w-[80%] justify-start" },
209
- react_1.default.createElement("div", { className: "flex justify-center items-center bg-[#26A69A] h-12 w-12 rounded-full text-2xl text-white" }, "PS"),
210
- react_1.default.createElement("div", { className: "flex flex-col items-start ml-4" },
211
- react_1.default.createElement("b", null,
212
- "Paro Support: ",
213
- react_1.default.createElement("span", null, "Apr 3, 2025")),
214
- " ",
215
- react_1.default.createElement("p", null, "We've received your dispute and are reviewing the timesheet discrepancies."),
216
- react_1.default.createElement("p", null, "We'll follow up with the expert and update you by Apr 5."),
217
- react_1.default.createElement("p", null, obj.paroSupport)))
218
- :
219
- react_1.default.createElement("div", { className: "flex flex-row-reverse w-[85%] justify-items-end items-center ml-auto my-1" },
220
- react_1.default.createElement("div", { className: "flex justify-center items-center bg-[#4cbaff] h-12 w-12 rounded-full text-2xl text-white ml-4" }, "A"),
221
- react_1.default.createElement("p", null, obj.you));
222
- })),
223
- react_1.default.createElement("div", { className: "flex flex-row w-[95%] m-2 ml-4 justify-start" },
224
- react_1.default.createElement(DiscussionThread_1.DiscussionThread, { currentUser: user, initialThreads: clientInvoice.chatMessages, createDisputeChatMessage: createDisputeChatMessage }),
225
- react_1.default.createElement(base_ui_2.Input, { label: "", type: "text", className: "w-[60vw] mx-4 overflow-ellipsis", value: discussion, onChange: (e) => setDiscussion(e.target.value), placeholder: "Type your reply here..." }),
226
- react_1.default.createElement(base_ui_2.Button, { label: "Save", size: "md", color: "success", className: "ml-2 mt-1 w-full", disabled: !discussion, onClick: () => {
227
- setProjects((prev) => prev.map((p) => p.projectId === row.projectId
228
- ? Object.assign(Object.assign({}, p), { discussion: [...p.discussion, { you: discussion }] }) : p));
229
- setEditingRowId(null);
230
- setDiscussion('');
231
- } })))))))))))));
247
+ 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: handleUpload }),
248
+ react_1.default.createElement(base_ui_2.Button, { label: "Add File", 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(); }, size: "sm", color: "info", className: "mx-2" }),
249
+ (Array.isArray(row.clientDocumentLinks)
250
+ ? row.clientDocumentLinks
251
+ : []).map((f, index) => (react_1.default.createElement("div", { key: index, className: "mx-2" },
252
+ react_1.default.createElement(base_ui_1.Tag, { variant: "subtle", color: "success", label: f, iconRight: react_1.default.createElement(base_icons_1.IconXCircle, null), onClick: () => {
253
+ const updatedProjects = projects.map((p) => p.projectId === row.projectId
254
+ ? Object.assign(Object.assign({}, p), { clientDocumentLinks: p.clientDocumentLinks.filter((file) => file !== f) }) : p);
255
+ setProjects(updatedProjects);
256
+ } })))))))))))));
257
+ })),
258
+ updatedDispute && react_1.default.createElement("div", { className: "flex justify-end ml-auto mt-2" },
259
+ react_1.default.createElement(base_ui_2.Button, { label: "Update Dispute", color: "primary", isLoading: updatingDispute, onClick: () => handleSubmitDispute() })),
260
+ (clientInvoice === null || clientInvoice === void 0 ? void 0 : clientInvoice.chatEnabled) && react_1.default.createElement("div", { className: "flex flex-row w-full my-2 justify-start" },
261
+ react_1.default.createElement(DiscussionThread_1.DiscussionThread, { disputeId: (_f = projects[0]) === null || _f === void 0 ? void 0 : _f.id, currentUser: user, initialThreads: chatMessages, createDisputeChatMessage: createDisputeChatMessage })))));
232
262
  };
233
263
  exports.InvoiceCard = InvoiceCard;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paro.io/expert-shared-components",
3
- "version": "1.11.1",
3
+ "version": "1.11.3",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {