@samparkchat/sampark-web-chat 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/sampark/sampark-chat/components/AttachmentFileSharing.js +5 -5
  3. package/sampark/sampark-chat/components/AttachmentGroupFileSharing.js +23 -13
  4. package/sampark/sampark-chat/components/AudioPlayerInline.js +5 -4
  5. package/sampark/sampark-chat/components/Headers/ChatHeader.js +3 -2
  6. package/sampark/sampark-chat/components/Headers/HeaderPanel/UserList.js +6 -2
  7. package/sampark/sampark-chat/components/InputModal.d.ts +17 -0
  8. package/sampark/sampark-chat/components/InputModal.js +110 -0
  9. package/sampark/sampark-chat/components/MentionList.js +10 -14
  10. package/sampark/sampark-chat/components/OnlineIndicator.d.ts +14 -0
  11. package/sampark/sampark-chat/components/OnlineIndicator.js +54 -0
  12. package/sampark/sampark-chat/components/ProfileModal.d.ts +3 -0
  13. package/sampark/sampark-chat/components/ProfileModal.js +47 -37
  14. package/sampark/sampark-chat/components/ThreadConversation.d.ts +13 -0
  15. package/sampark/sampark-chat/components/ThreadConversation.js +198 -18
  16. package/sampark/sampark-chat/components/bottomsheets/GroupOptionBottomSheet.d.ts +11 -0
  17. package/sampark/sampark-chat/components/bottomsheets/GroupOptionBottomSheet.js +30 -9
  18. package/sampark/sampark-chat/components/lists/CommonList.d.ts +1 -1
  19. package/sampark/sampark-chat/components/lists/CommonList.js +21 -3
  20. package/sampark/sampark-chat/components/lists/UserInfo.js +2 -1
  21. package/sampark/sampark-chat/components/lists/ViewParticipents.d.ts +2 -0
  22. package/sampark/sampark-chat/components/lists/ViewParticipents.js +49 -30
  23. package/sampark/sampark-chat/models/OwnershipTransferModal.d.ts +18 -0
  24. package/sampark/sampark-chat/models/OwnershipTransferModal.js +209 -0
  25. package/sampark/sampark-chat/screens/PeerChatScreen.js +47 -30
  26. package/sampark/sampark-chat/screens/SamparkChatsScreen.js +101 -77
  27. package/sampark/sampark-chat/screens/groupChatScreen.js +14 -21
  28. package/sampark/sampark-chat/theme/colors.d.ts +1 -0
  29. package/sampark/sampark-chat/theme/colors.js +2 -1
  30. package/sampark/sampark-chat/theme/icons.d.ts +10 -0
  31. package/sampark/sampark-chat/theme/icons.js +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@samparkchat/sampark-web-chat",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "main": "sampark/sampark-web-chat/index.js",
5
5
  "types": "sampark/sampark-web-chat/index.d.ts",
6
6
  "private": false,
@@ -134,35 +134,35 @@ var AttachmentFileSharing = function (_a) {
134
134
  position: 'absolute',
135
135
  bottom: '70px',
136
136
  left: '20px',
137
- backgroundColor: 'white',
137
+ backgroundColor: colors.white,
138
138
  borderRadius: '12px',
139
139
  boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
140
140
  padding: '8px',
141
141
  minWidth: '200px',
142
142
  zIndex: 1000
143
143
  } },
144
- React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
144
+ React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = colors.optionHover; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
145
145
  var _a;
146
146
  (_a = imageInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
147
147
  } },
148
148
  React.createElement("div", { style: styles.attachmentIcon },
149
149
  React.createElement(FontAwesomeIcon, { icon: CustomIcons.faImage.icon, style: { fontSize: CustomIcons.faImage.size, color: colors.white } })),
150
150
  React.createElement("span", { style: styles.attachmentText }, "Attach Image")),
151
- React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
151
+ React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = colors.optionHover; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
152
152
  var _a;
153
153
  (_a = videoInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
154
154
  } },
155
155
  React.createElement("div", { style: styles.attachmentIcon },
156
156
  React.createElement(FontAwesomeIcon, { icon: CustomIcons.faVideo.icon, style: { fontSize: CustomIcons.faVideo.size, color: colors.white } })),
157
157
  React.createElement("span", { style: styles.attachmentText }, "Attach Video")),
158
- React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
158
+ React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = colors.optionHover; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
159
159
  var _a;
160
160
  (_a = audioInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
161
161
  } },
162
162
  React.createElement("div", { style: styles.attachmentIcon },
163
163
  React.createElement(FontAwesomeIcon, { icon: CustomIcons.faHeadphones.icon, style: { fontSize: CustomIcons.faHeadphones.size, color: colors.white } })),
164
164
  React.createElement("span", { style: styles.attachmentText }, "Attach Audio")),
165
- React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
165
+ React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = colors.optionHover; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
166
166
  var _a;
167
167
  (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
168
168
  } },
@@ -1,3 +1,14 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
1
12
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
13
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
14
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -38,6 +49,7 @@ import React, { useRef } from 'react';
38
49
  import colors from '../theme/colors';
39
50
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
40
51
  import CustomIcons from '../theme/icons';
52
+ import fonts from '../theme/fonts';
41
53
  var AttachmentGroupFileSharing = function (_a) {
42
54
  var isVisible = _a.isVisible, onClose = _a.onClose, onAttachImage = _a.onAttachImage, onAttachVideo = _a.onAttachVideo, onAttachAudio = _a.onAttachAudio, onAttachFile = _a.onAttachFile, client = _a.client, roomId = _a.roomId, userId = _a.userId, userName = _a.userName, _b = _a.uploadSource, uploadSource = _b === void 0 ? 'group_chat' : _b, onFileUpload = _a.onFileUpload;
43
55
  var imageInputRef = useRef(null);
@@ -65,7 +77,6 @@ var AttachmentGroupFileSharing = function (_a) {
65
77
  _a.label = 3;
66
78
  case 3:
67
79
  if (uploadResult) {
68
- // console.log('[AttachmentGroupFileSharing] file uploaded successfully:', uploadResult);
69
80
  onFileUpload === null || onFileUpload === void 0 ? void 0 : onFileUpload(uploadResult.fileId);
70
81
  onClose();
71
82
  }
@@ -116,53 +127,52 @@ var AttachmentGroupFileSharing = function (_a) {
116
127
  marginRight: '12px'
117
128
  },
118
129
  iconStyle: {
119
- color: 'white',
130
+ color: colors.white,
120
131
  fontSize: '16px'
121
132
  },
122
133
  attachmentText: {
123
- fontSize: '16px',
124
- color: '#333'
134
+ // fontSize: '16px',
125
135
  }
126
136
  };
127
137
  return (React.createElement("div", { className: "attachment-menu", style: {
128
138
  position: 'absolute',
129
139
  bottom: '70px',
130
140
  left: '20px',
131
- backgroundColor: 'white',
141
+ backgroundColor: colors.white,
132
142
  borderRadius: '12px',
133
143
  boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
134
144
  padding: '8px',
135
145
  minWidth: '200px',
136
146
  zIndex: 1000
137
147
  } },
138
- React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
148
+ React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = colors.optionHover; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
139
149
  var _a;
140
150
  (_a = imageInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
141
151
  } },
142
152
  React.createElement("div", { style: styles.attachmentIcon },
143
153
  React.createElement(FontAwesomeIcon, { icon: CustomIcons.faImage.icon, style: { fontSize: CustomIcons.faImage.size, color: colors.white } })),
144
- React.createElement("span", { style: styles.attachmentText }, "Attach Image")),
145
- React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
154
+ React.createElement("span", { style: __assign({}, fonts.content) }, "Attach Image")),
155
+ React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = colors.optionHover; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
146
156
  var _a;
147
157
  (_a = videoInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
148
158
  } },
149
159
  React.createElement("div", { style: styles.attachmentIcon },
150
160
  React.createElement(FontAwesomeIcon, { icon: CustomIcons.faVideo.icon, style: { fontSize: CustomIcons.faVideo.size, color: colors.white } })),
151
- React.createElement("span", { style: styles.attachmentText }, "Attach Video")),
152
- React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
161
+ React.createElement("span", { style: __assign({}, fonts.content) }, "Attach Video")),
162
+ React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = colors.optionHover; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
153
163
  var _a;
154
164
  (_a = audioInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
155
165
  } },
156
166
  React.createElement("div", { style: styles.attachmentIcon },
157
167
  React.createElement(FontAwesomeIcon, { icon: CustomIcons.faHeadphones.icon, style: { fontSize: CustomIcons.faHeadphones.size, color: colors.white } })),
158
- React.createElement("span", { style: styles.attachmentText }, "Attach Audio")),
159
- React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = '#f5f5f5'; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
168
+ React.createElement("span", { style: __assign({}, fonts.content) }, "Attach Audio")),
169
+ React.createElement("div", { style: styles.attachmentMenuItem, onMouseEnter: function (e) { return e.currentTarget.style.backgroundColor = colors.optionHover; }, onMouseLeave: function (e) { return e.currentTarget.style.backgroundColor = 'transparent'; }, onClick: function () {
160
170
  var _a;
161
171
  (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
162
172
  } },
163
173
  React.createElement("div", { style: styles.attachmentIcon },
164
174
  React.createElement(FontAwesomeIcon, { icon: CustomIcons.faFile.icon, style: { fontSize: CustomIcons.faFile.size, color: colors.white } })),
165
- React.createElement("span", { style: styles.attachmentText }, "Attach File")),
175
+ React.createElement("span", { style: __assign({}, fonts.content) }, "Attach File")),
166
176
  React.createElement("input", { type: "file", ref: imageInputRef, accept: "image/*", style: { display: 'none' }, onChange: function (e) {
167
177
  var files = e.target.files;
168
178
  if (onAttachImage) {
@@ -1,6 +1,7 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
2
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
3
  import CustomIcons from '../theme/icons';
4
+ import colors from '../theme/colors';
4
5
  var formatTime = function (s) {
5
6
  if (!isFinite(s))
6
7
  return '0:00';
@@ -64,19 +65,19 @@ var AudioPlayerInline = function (_a) {
64
65
  justifyContent: 'center'
65
66
  } },
66
67
  React.createElement(FontAwesomeIcon, { icon: playing ? CustomIcons.faCirclePause.icon : CustomIcons.faPlay.icon, style: {
67
- color: (playing ? CustomIcons.faCirclePause.color : CustomIcons.faPlay.color) || 'white',
68
+ color: (playing ? CustomIcons.faCirclePause.color : CustomIcons.faPlay.color),
68
69
  fontSize: (playing ? CustomIcons.faCirclePause.size : CustomIcons.faPlay.size) || 18
69
70
  } })),
70
71
  React.createElement("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', gap: 6 } },
71
72
  React.createElement("div", { style: { height: 18, display: 'flex', alignItems: 'center', gap: 8 } },
72
73
  React.createElement("div", { style: { flex: 1, height: 6, background: 'rgba(255,255,255,0.12)', borderRadius: 6, position: 'relative' } },
73
74
  React.createElement("div", { style: { position: 'absolute', left: 0, top: 0, bottom: 0, width: "".concat((duration ? (current / duration) * 100 : 0), "%"), background: 'rgba(255,255,255,0.28)', borderRadius: 6 } }))),
74
- React.createElement("div", { style: { display: 'flex', justifyContent: 'flex-end', fontSize: 12, color: 'rgba(255,255,255,0.95)' } },
75
+ React.createElement("div", { style: { display: 'flex', justifyContent: 'flex-end', fontSize: 12, color: colors.white } },
75
76
  React.createElement("div", null,
76
77
  formatTime(current),
77
78
  " / ",
78
79
  formatTime(duration)))),
79
- React.createElement("a", { href: url, download: fileName, style: { color: CustomIcons.faArrowDown.color || 'white', textDecoration: 'none', fontSize: CustomIcons.faArrowDown.size || 18 }, "aria-label": "Download audio" },
80
- React.createElement(FontAwesomeIcon, { icon: CustomIcons.faArrowDown.icon, style: { color: CustomIcons.faArrowDown.color || 'white', fontSize: CustomIcons.faArrowDown.size || 18 } }))));
80
+ React.createElement("a", { href: url, download: fileName, style: { color: CustomIcons.faArrowDown.color, textDecoration: 'none', fontSize: CustomIcons.faArrowDown.size || 18 }, "aria-label": "Download audio" },
81
+ React.createElement(FontAwesomeIcon, { icon: CustomIcons.faArrowDown.icon, style: { color: CustomIcons.faArrowDown.color, fontSize: CustomIcons.faArrowDown.size || 18 } }))));
81
82
  };
82
83
  export default AudioPlayerInline;
@@ -15,6 +15,7 @@ import { getInitials } from "../../services/Common";
15
15
  import CustomIcons from "../../theme/icons";
16
16
  import colors from "../../theme/colors";
17
17
  import fonts from "../../theme/fonts";
18
+ import OnlineIndicator from "../OnlineIndicator";
18
19
  var PeerChatHeader = function (_a) {
19
20
  var userProfilePic = _a.userProfilePic, onclick = _a.onclick, _b = _a.showBackButton, showBackButton = _b === void 0 ? true : _b, mainHeading = _a.mainHeading, _c = _a.headingStyle, headingStyle = _c === void 0 ? {} : _c, isPeerOnline = _a.isPeerOnline, _d = _a.showActionButtons, showActionButtons = _d === void 0 ? true : _d, onVideoCall = _a.onVideoCall, onAudioCall = _a.onAudioCall, onUserClick = _a.onUserClick, _e = _a.showVideoCall, showVideoCall = _e === void 0 ? false : _e, onSearch = _a.onSearch, _f = _a.showOptions, showOptions = _f === void 0 ? false : _f, onOptionsClick = _a.onOptionsClick, primaryColor = _a.primaryColor, secondaryColor = _a.secondaryColor, busyCallusersList = _a.busyCallusersList, peerUserId = _a.peerUserId;
20
21
  var getHeaderGradient = function () {
@@ -38,10 +39,10 @@ var PeerChatHeader = function (_a) {
38
39
  // console.debug('[PeerChatHeader] error setting fallback image', err);
39
40
  }
40
41
  } }),
41
- React.createElement("div", { style: __assign(__assign({}, styles.statusDot), { backgroundColor: isPeerOnline ? ((busyCallusersList === null || busyCallusersList === void 0 ? void 0 : busyCallusersList.includes(peerUserId || "")) ? '#f44336' : colors.onlineColor) : colors.disabledColor }) }))) : (React.createElement("div", { style: styles.profileWrapper },
42
+ React.createElement(OnlineIndicator, { isOnline: isPeerOnline || false, isBusy: busyCallusersList === null || busyCallusersList === void 0 ? void 0 : busyCallusersList.includes(peerUserId || ""), variant: "avatar" }))) : (React.createElement("div", { style: styles.profileWrapper },
42
43
  React.createElement("div", { style: styles.profilePlaceholder },
43
44
  React.createElement("span", { style: styles.initials }, getInitials(mainHeading || ''))),
44
- React.createElement("div", { style: __assign(__assign({}, styles.statusDot), { backgroundColor: isPeerOnline ? colors.onlineColor : colors.disabledColor }) })))),
45
+ React.createElement(OnlineIndicator, { isOnline: isPeerOnline || false, variant: "avatar" })))),
45
46
  React.createElement("div", { style: styles.userDetails },
46
47
  React.createElement("h2", { style: styles.userName, onClick: onUserClick },
47
48
  " ",
@@ -12,6 +12,7 @@ var __assign = (this && this.__assign) || function () {
12
12
  import React, { useMemo, useState, useEffect } from "react";
13
13
  import colors from "../../../theme/colors";
14
14
  import fonts from "../../../theme/fonts";
15
+ import OnlineIndicator from "../../OnlineIndicator";
15
16
  var getInitials = function (name) {
16
17
  if (!name)
17
18
  return "";
@@ -55,7 +56,7 @@ var UserList = function (_a) {
55
56
  _b["--ul-border"] = colors.borderLight,
56
57
  _b);
57
58
  return (React.createElement("div", { className: "ul-root", style: __assign({ padding: "6px 0" }, rootVars) },
58
- React.createElement("style", null, "\n .ul-root { font-family: ".concat(fonts.listsStyle.fontFamily, "; color: ").concat(colors.muted, "; }\n\n /* alphabet letter - centered horizontally */\n .ul-letter {\n color: ").concat(colors.blue, ";\n margin: 8px 0 8px 0;\n font-size:13px;\n display:flex;\n justify-content:center;\n align-items:center;\n width:100%;\n }\n .ul-group { display:flex; flex-direction:column; gap: 8px; }\n .user-item {\n display:flex;\n align-items:center;\n gap:14px;\n padding: 12px 18px; \n border-radius: 10px; \n cursor: pointer;\n background: transparent;\n border: 0;\n width: calc(100% - 32px); \n margin: 0 16px; \n box-sizing: border-box;\n transition: transform 180ms ease, box-shadow 180ms ease, background 180ms ease;\n }\n\n .user-item + .user-item { /* if you want subtle separator, keep a faint line */\n }\n\n .user-item:hover {\n transform: translateY(-6px); /* lift up */\n box-shadow: 0 18px 36px rgba(16,24,40,0.12); /* elevated shadow */\n background: rgba(16,24,40,0.03); /* light background on hover */\n }\n\n /* selected row */\n .user-item.selected {\n background: rgba(16,24,40,0.03);\n }\n\n /* avatar */\n .user-avatar {\n width:40px;\n height:40px;\n border-radius:50%;\n overflow: visible;\n display:flex;\n align-items:center;\n justify-content:center;\n font-weight:700;\n flex-shrink:0;\n box-shadow: 0 6px 14px rgba(16,24,40,0.06);\n border: 3px solid rgba(255,255,255,0.9);\n position: relative;\n }\n .user-avatar.online::after {\n content: '';\n position: absolute;\n left: -6px;\n top: -6px;\n right: -6px;\n bottom: -6px;\n border-radius: 50%;\n border: 3px solid #4CAF50;\n box-shadow: 0 6px 18px rgba(76,175,80,0.12);\n pointer-events: none;\n }\n .user-avatar img {\n width:100%;\n height:100%;\n object-fit:cover;\n display:block;\n border-radius:50%;\n }\n .user-initials {\n width:100%;\n height:100%;\n display:flex;\n align-items:center;\n justify-content:center;\n font-size:14px;\n color: white;\n text-transform:uppercase;\n letter-spacing:0.6px;\n }\n\n /* subtle name style */\n .user-meta { display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }\n .user-name {\n color: ").concat((_c = colors.muted) !== null && _c !== void 0 ? _c : "#0b243d", ";\n font-size: 16px;\n font-weight: 600;\n white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\n }\n .user-last {\n color: rgba(16,24,40,0.45);\n font-size: 13px;\n overflow:hidden;\n white-space:nowrap;\n text-overflow:ellipsis;\n }\n\n /* spacing tweaks for top of list (no extra gap) */\n .ul-root > .ul-section:first-child { margin-top: 0; }\n\n @media (max-width:640px) {\n .ul-root { padding: 6px 6px; }\n .user-item { width: calc(100% - 24px); margin: 0 12px; padding: 10px 12px; border-radius:8px; }\n .user-avatar { width:36px; height:36px; }\n .user-name { font-size:15px; }\n }\n ")),
59
+ React.createElement("style", null, "\n .ul-root { font-family: ".concat(fonts.listsStyle.fontFamily, "; color: ").concat(colors.muted, "; }\n\n /* alphabet letter - centered horizontally */\n .ul-letter {\n color: ").concat(colors.blue, ";\n margin: 8px 0 8px 0;\n font-size:13px;\n display:flex;\n justify-content:center;\n align-items:center;\n width:100%;\n }\n .ul-group { display:flex; flex-direction:column; gap: 8px; }\n .user-item {\n display:flex;\n align-items:center;\n gap:14px;\n padding: 12px 18px; \n border-radius: 10px; \n cursor: pointer;\n background: transparent;\n border: 0;\n width: calc(100% - 32px); \n margin: 0 16px; \n box-sizing: border-box;\n transition: transform 180ms ease, box-shadow 180ms ease, background 180ms ease;\n }\n\n .user-item + .user-item { /* if you want subtle separator, keep a faint line */\n }\n\n .user-item:hover {\n transform: translateY(-6px); /* lift up */\n box-shadow: 0 18px 36px rgba(16,24,40,0.12); /* elevated shadow */\n background: rgba(16,24,40,0.03); /* light background on hover */\n }\n\n /* selected row */\n .user-item.selected {\n background: rgba(16,24,40,0.03);\n }\n\n /* avatar */\n .user-avatar {\n width:40px;\n height:40px;\n border-radius:50%;\n overflow: visible;\n display:flex;\n align-items:center;\n justify-content:center;\n font-weight:700;\n flex-shrink:0;\n box-shadow: 0 6px 14px rgba(16,24,40,0.06);\n border: 3px solid rgba(255,255,255,0.9);\n position: relative;\n }\n .user-avatar img {\n width:100%;\n height:100%;\n object-fit:cover;\n display:block;\n border-radius:50%;\n }\n .user-initials {\n width:100%;\n height:100%;\n display:flex;\n align-items:center;\n justify-content:center;\n font-size:14px;\n color: white;\n text-transform:uppercase;\n letter-spacing:0.6px;\n }\n\n /* subtle name style */\n .user-meta { display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }\n .user-name {\n color: ").concat((_c = colors.muted) !== null && _c !== void 0 ? _c : "#0b243d", ";\n font-size: 16px;\n font-weight: 600;\n white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\n }\n .user-last {\n color: rgba(16,24,40,0.45);\n font-size: 13px;\n overflow:hidden;\n white-space:nowrap;\n text-overflow:ellipsis;\n }\n\n /* spacing tweaks for top of list (no extra gap) */\n .ul-root > .ul-section:first-child { margin-top: 0; }\n\n @media (max-width:640px) {\n .ul-root { padding: 6px 6px; }\n .user-item { width: calc(100% - 24px); margin: 0 12px; padding: 10px 12px; border-radius:8px; }\n .user-avatar { width:36px; height:36px; }\n .user-name { font-size:15px; }\n }\n ")),
59
60
  keys.map(function (k) { return (React.createElement("div", { key: k, className: "ul-section", "aria-labelledby": "ul-".concat(k) },
60
61
  React.createElement("div", { id: "ul-".concat(k), className: "ul-letter" }, k),
61
62
  React.createElement("div", { className: "ul-group", role: "list" }, grouped[k].map(function (u) {
@@ -64,9 +65,12 @@ var UserList = function (_a) {
64
65
  var isSelected = showUserList && selectedPeerUserId === u.user_id;
65
66
  var cls = ["user-item", isSelected ? "selected" : ""].join(" ").trim();
66
67
  var grad = colors.headerGradient;
68
+ var isUserOnline = (onlineUsers || []).includes(u.user_id) || (onlineUsers || []).includes(u.userId) || (onlineUsers || []).includes(u.id);
67
69
  return (React.createElement("div", { key: u.user_id, role: "listitem", className: cls, onClick: function () { if (onItemClick)
68
70
  onItemClick(u); }, "aria-selected": isSelected },
69
- React.createElement("div", { className: "user-avatar" + (((onlineUsers || []).includes(u.user_id) || (onlineUsers || []).includes(u.userId) || (onlineUsers || []).includes(u.id)) ? ' online' : ''), style: { background: u.profile_pic ? undefined : grad } }, u.profile_pic ? (React.createElement("img", { src: u.profile_pic, alt: u.user_name })) : (React.createElement("div", { className: "user-initials" }, getInitials(u.user_name)))),
71
+ React.createElement("div", { className: "user-avatar", style: { background: u.profile_pic ? undefined : grad, position: 'relative' } },
72
+ u.profile_pic ? (React.createElement("img", { src: u.profile_pic, alt: u.user_name })) : (React.createElement("div", { className: "user-initials" }, getInitials(u.user_name))),
73
+ React.createElement(OnlineIndicator, { isOnline: isUserOnline, variant: "avatar" })),
70
74
  React.createElement("div", { className: "user-meta" },
71
75
  React.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 } },
72
76
  React.createElement("div", { className: "user-name", style: fonts.listsStyle }, u.user_name),
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ interface InputModalProps {
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ onSave: (value: string) => void;
6
+ title: string;
7
+ placeholder: string;
8
+ initialValue: string;
9
+ maxLength?: number;
10
+ isTextarea?: boolean;
11
+ apiColors: {
12
+ primaryColor?: string;
13
+ secondaryColor?: string;
14
+ };
15
+ }
16
+ declare const InputModal: React.FC<InputModalProps>;
17
+ export default InputModal;
@@ -0,0 +1,110 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import React, { useState, useEffect, useRef } from 'react';
13
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
14
+ import colors from '../theme/colors';
15
+ import fonts from '../theme/fonts';
16
+ import { AppIcons } from '../theme/icons';
17
+ var InputModal = function (_a) {
18
+ var isOpen = _a.isOpen, onClose = _a.onClose, onSave = _a.onSave, title = _a.title, placeholder = _a.placeholder, initialValue = _a.initialValue, _b = _a.maxLength, maxLength = _b === void 0 ? 100 : _b, _c = _a.isTextarea, isTextarea = _c === void 0 ? false : _c, apiColors = _a.apiColors;
19
+ var _d = useState(initialValue), value = _d[0], setValue = _d[1];
20
+ var inputRef = useRef(null);
21
+ // helper to convert hex color to rgba for subtle focus rings
22
+ var hexToRgba = function (hex, alpha) {
23
+ if (alpha === void 0) { alpha = 1; }
24
+ var h = hex.replace('#', '');
25
+ var bigint = parseInt(h.length === 3 ? h.split('').map(function (c) { return c + c; }).join('') : h, 16);
26
+ var r = (bigint >> 16) & 255;
27
+ var g = (bigint >> 8) & 255;
28
+ var b = bigint & 255;
29
+ return "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(alpha, ")");
30
+ };
31
+ var primary = apiColors.primaryColor || colors.blue;
32
+ var secondary = apiColors.secondaryColor || colors.blueLight;
33
+ var primaryRing = hexToRgba(primary, 0.12);
34
+ useEffect(function () {
35
+ if (isOpen) {
36
+ setValue(initialValue);
37
+ // Focus input after modal animation
38
+ setTimeout(function () {
39
+ var _a, _b;
40
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
41
+ (_b = inputRef.current) === null || _b === void 0 ? void 0 : _b.select();
42
+ }, 100);
43
+ }
44
+ }, [isOpen, initialValue]);
45
+ var handleSave = function () {
46
+ onSave(value.trim());
47
+ onClose();
48
+ };
49
+ var handleKeyDown = function (e) {
50
+ if (e.key === 'Enter' && !isTextarea) {
51
+ handleSave();
52
+ }
53
+ else if (e.key === 'Escape') {
54
+ onClose();
55
+ }
56
+ };
57
+ if (!isOpen)
58
+ return null;
59
+ return (React.createElement("div", { style: {
60
+ position: 'fixed',
61
+ top: 0,
62
+ left: 0,
63
+ width: '100vw',
64
+ height: '100vh',
65
+ background: 'rgba(0,0,0,0.4)',
66
+ backdropFilter: 'blur(2px)',
67
+ zIndex: 10000,
68
+ display: 'flex',
69
+ alignItems: 'center',
70
+ justifyContent: 'center',
71
+ animation: 'fadeIn 0.2s ease-out'
72
+ }, onClick: onClose },
73
+ React.createElement("style", null, "\n @keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes slideIn {\n from {\n opacity: 0;\n transform: translateY(-20px) scale(0.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n .input-modal-content {\n animation: slideIn 0.28s cubic-bezier(.2,.9,.2,1);\n border-radius: 12px;\n overflow: hidden;\n box-sizing: border-box;\n }\n .input-modal-header {\n border-top-left-radius: 12px;\n border-top-right-radius: 12px;\n padding: 18px 22px 18px 22px;\n position: relative;\n min-height: 58px;\n box-shadow: 0 6px 18px rgba(11,34,54,0.06);\n }\n .input-modal-close{\n position: absolute;\n right: 18px;\n top: 12px;\n width: 34px;\n height: 34px;\n border-radius: 50%;\n background: rgba(255,255,255,0.98);\n display:flex; align-items:center; justify-content:center;\n box-shadow: 0 8px 20px rgba(11,34,54,0.08);\n border: none;\n cursor: pointer;\n }\n .input-modal-close svg{ color: ".concat(primary, "; }\n .input-modal-body {\n padding: 22px 24px 20px 24px;\n background: ").concat(colors.white, ";\n }\n .input-wrapper{\n width:100%;\n border-radius:12px;\n padding:12px;\n background: ").concat(colors.white, ";\n box-shadow: 0 14px 30px rgba(11,34,54,0.04);\n border: 1px solid rgba(15,23,42,0.04);\n transition: box-shadow 0.18s, border-color 0.18s, transform 0.08s;\n box-sizing: border-box;\n min-height: 140px; /* ensure equal usable area for single-line and textarea */\n display: flex;\n align-items: stretch;\n }\n .input-wrapper:focus-within{\n box-shadow: 0 18px 36px ").concat(hexToRgba(primary, 0.08), ";\n border-color: ").concat(hexToRgba(primary, 0.16), ";\n transform: translateY(-1px);\n }\n .input-modal-input, .input-modal-textarea {\n width: 100%;\n padding: 12px 14px;\n border-radius: 8px;\n border: none;\n background: transparent;\n font-size: 15px;\n transition: box-shadow 0.18s, transform 0.08s;\n color: #0b2236;\n outline: none;\n box-sizing:border-box;\n }\n .input-modal-textarea { min-height: 140px; resize: vertical; width:100%; box-sizing:border-box; }\n .input-modal-input::placeholder, .input-modal-textarea::placeholder {\n color: rgba(11,34,54,0.36);\n }\n .input-modal-input:focus, .input-modal-textarea:focus {\n /* input itself stays transparent; wrapper handles glow */\n }\n .input-modal-actions { display:flex; gap:12px; justify-content:flex-end; align-items:center; }\n .input-modal-cancel{\n padding:10px 20px; border-radius:8px; border:1px solid rgba(15,23,42,0.06); background:").concat(colors.white, "; cursor:pointer;\n }\n .input-modal-save{\n padding:10px 20px; border-radius:8px; color:").concat(colors.white, "; cursor:pointer; border:none;\n background: linear-gradient(135deg, ").concat(primary, ", ").concat(secondary, ");\n }\n .input-modal-save.disabled{ background: ").concat(colors.disabledColor, "; cursor: not-allowed; opacity: 0.75 }\n ")),
74
+ React.createElement("div", { className: "input-modal-content", style: {
75
+ background: colors.white,
76
+ boxShadow: '0 18px 48px rgba(8,20,40,0.18)',
77
+ minWidth: '520px',
78
+ maxWidth: '94vw',
79
+ padding: 0,
80
+ borderRadius: 12,
81
+ minHeight: 260
82
+ }, onClick: function (e) { return e.stopPropagation(); } },
83
+ React.createElement("div", { className: "input-modal-header", style: {
84
+ background: "linear-gradient(135deg, ".concat(primary, ", ").concat(secondary, ")"),
85
+ color: colors.white,
86
+ display: 'flex',
87
+ alignItems: 'center',
88
+ justifyContent: 'space-between'
89
+ } },
90
+ React.createElement("h3", { style: __assign({ margin: 0, fontSize: '18px', fontWeight: '600' }, fonts.content) }, title),
91
+ React.createElement("button", { className: "input-modal-close", onClick: onClose, "aria-label": "Close" },
92
+ React.createElement(FontAwesomeIcon, { icon: AppIcons.Cancel.icon, style: { fontSize: '14px' } }))),
93
+ React.createElement("div", { className: "input-modal-body" },
94
+ React.createElement("div", { style: { marginBottom: '12px' } }, isTextarea ? (React.createElement("div", { className: "input-wrapper" },
95
+ React.createElement("textarea", { className: "input-modal-textarea", ref: inputRef, value: value, onChange: function (e) { return setValue(e.target.value); }, onKeyDown: handleKeyDown, placeholder: placeholder, maxLength: maxLength, style: __assign({}, fonts.content) }))) : (React.createElement("div", { className: "input-wrapper" },
96
+ React.createElement("input", { className: "input-modal-input", ref: inputRef, type: "text", value: value, onChange: function (e) { return setValue(e.target.value); }, onKeyDown: handleKeyDown, placeholder: placeholder, maxLength: maxLength, style: __assign({}, fonts.content) })))),
97
+ maxLength && (React.createElement("div", { style: {
98
+ textAlign: 'right',
99
+ fontSize: '12px',
100
+ color: value.length > maxLength * 0.9 ? colors.errorBorder : colors.disabledColor,
101
+ marginBottom: '16px'
102
+ } },
103
+ value.length,
104
+ "/",
105
+ maxLength)),
106
+ React.createElement("div", { className: "input-modal-actions" },
107
+ React.createElement("button", { className: "input-modal-cancel", onClick: onClose }, "Cancel"),
108
+ React.createElement("button", { onClick: handleSave, className: "input-modal-save ".concat(!value.trim() ? 'disabled' : ''), disabled: !value.trim() }, "Save"))))));
109
+ };
110
+ export default InputModal;
@@ -11,8 +11,10 @@ var __assign = (this && this.__assign) || function () {
11
11
  };
12
12
  import React from 'react';
13
13
  import { getInitials } from '../services/Common';
14
+ import colors from '../theme/colors';
15
+ import fonts from '../theme/fonts';
16
+ import OnlineIndicator from './OnlineIndicator';
14
17
  var MentionList = function (_a) {
15
- // console.log('MentionList props:', { users, visible, searchTerm, position });
16
18
  var users = _a.users, onUserSelect = _a.onUserSelect, position = _a.position, searchTerm = _a.searchTerm, visible = _a.visible, _b = _a.onlineUsers, onlineUsers = _b === void 0 ? [] : _b, onMouseDown = _a.onMouseDown, currentUserId = _a.currentUserId;
17
19
  if (!visible)
18
20
  return null;
@@ -20,13 +22,12 @@ var MentionList = function (_a) {
20
22
  return user.user_name.toLowerCase().includes(searchTerm.toLowerCase()) &&
21
23
  user.user_id !== currentUserId;
22
24
  });
23
- // console.log('Filtered users:', filteredUsers);
24
25
  if (filteredUsers.length === 0)
25
26
  return null;
26
27
  return (React.createElement("div", { style: __assign(__assign({}, styles.container), { top: position.top, left: position.left }), onMouseDown: onMouseDown }, filteredUsers.slice(0, 5).map(function (user) {
27
28
  var isUserOnline = onlineUsers.includes(user.user_id);
28
29
  return (React.createElement("div", { key: user.user_id, style: styles.userItem, onClick: function () { return onUserSelect(user); }, onMouseEnter: function (e) {
29
- e.currentTarget.style.backgroundColor = '#f0f8ff';
30
+ e.currentTarget.style.backgroundColor = colors.optionHover;
30
31
  }, onMouseLeave: function (e) {
31
32
  e.currentTarget.style.backgroundColor = 'transparent';
32
33
  } },
@@ -39,15 +40,15 @@ var MentionList = function (_a) {
39
40
  placeholder.style.display = 'flex';
40
41
  } })) : null,
41
42
  React.createElement("div", { style: __assign(__assign({}, styles.avatarPlaceholder), { display: user.profile_pic ? 'none' : 'flex' }) }, getInitials(user.user_name)),
42
- React.createElement("div", { style: __assign(__assign({}, styles.statusIndicator), { backgroundColor: isUserOnline ? '#4CAF50' : '#9CA3AF' }) }))),
43
- React.createElement("span", { style: styles.userName }, user.user_name)));
43
+ React.createElement(OnlineIndicator, { isOnline: isUserOnline, variant: "avatar", size: "small" }))),
44
+ React.createElement("span", { style: __assign({}, fonts.content) }, user.user_name)));
44
45
  })));
45
46
  };
46
47
  var styles = {
47
48
  container: {
48
49
  position: 'fixed',
49
- backgroundColor: 'white',
50
- border: '1px solid #e0e0e0',
50
+ backgroundColor: colors.white,
51
+ border: "1px solid ".concat(colors.borderLight),
51
52
  borderRadius: '12px',
52
53
  boxShadow: '0 8px 24px rgba(0,0,0,0.15)',
53
54
  maxHeight: '250px',
@@ -82,8 +83,8 @@ var styles = {
82
83
  width: '40px',
83
84
  height: '40px',
84
85
  borderRadius: '50%',
85
- backgroundColor: '#007bff',
86
- color: 'white',
86
+ backgroundColor: colors.blue,
87
+ color: colors.white,
87
88
  display: 'flex',
88
89
  alignItems: 'center',
89
90
  justifyContent: 'center',
@@ -99,10 +100,5 @@ var styles = {
99
100
  borderRadius: '50%',
100
101
  border: '2px solid white'
101
102
  },
102
- userName: {
103
- fontSize: '15px',
104
- color: '#333',
105
- fontWeight: '500'
106
- }
107
103
  };
108
104
  export default MentionList;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ export interface OnlineIndicatorProps {
3
+ isOnline?: boolean;
4
+ userId?: string;
5
+ onlineUsers?: string[];
6
+ busyUsers?: string[];
7
+ isBusy?: boolean;
8
+ variant?: 'avatar' | 'dot' | 'badge';
9
+ size?: 'small' | 'medium' | 'large';
10
+ style?: React.CSSProperties;
11
+ className?: string;
12
+ }
13
+ declare const OnlineIndicator: React.FC<OnlineIndicatorProps>;
14
+ export default OnlineIndicator;
@@ -0,0 +1,54 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import React from 'react';
13
+ import colors from '../theme/colors';
14
+ var OnlineIndicator = function (_a) {
15
+ var isOnline = _a.isOnline, userId = _a.userId, _b = _a.onlineUsers, onlineUsers = _b === void 0 ? [] : _b, _c = _a.busyUsers, busyUsers = _c === void 0 ? [] : _c, isBusy = _a.isBusy, _d = _a.variant, variant = _d === void 0 ? 'avatar' : _d, _e = _a.size, size = _e === void 0 ? 'medium' : _e, _f = _a.style, style = _f === void 0 ? {} : _f, _g = _a.className, className = _g === void 0 ? '' : _g;
16
+ var actualIsOnline = isOnline !== undefined
17
+ ? isOnline
18
+ : userId ? onlineUsers.includes(userId) || onlineUsers.includes(userId) : false;
19
+ var actualIsBusy = isBusy !== undefined
20
+ ? isBusy
21
+ : userId ? busyUsers.includes(userId) : false;
22
+ if (!actualIsOnline)
23
+ return null;
24
+ var getIndicatorColor = function () {
25
+ if (actualIsBusy)
26
+ return colors.errorBorder || '#f44336';
27
+ return colors.onlineColor || '#4CAF50';
28
+ };
29
+ var getSizeStyles = function () {
30
+ var sizes = {
31
+ small: { width: 8, height: 8, borderWidth: 1 },
32
+ medium: { width: 10, height: 10, borderWidth: 2 },
33
+ large: { width: 12, height: 12, borderWidth: 2 },
34
+ };
35
+ return sizes[size];
36
+ };
37
+ var getVariantStyles = function () {
38
+ var sizeStyles = getSizeStyles();
39
+ var indicatorColor = getIndicatorColor();
40
+ switch (variant) {
41
+ case 'avatar':
42
+ return __assign({ position: 'absolute', left: -6, top: -6, right: -6, bottom: -6, borderRadius: '50%', border: "3px solid ".concat(indicatorColor), boxShadow: "0 6px 18px ".concat(indicatorColor, "20"), pointerEvents: 'none', content: '""' }, style);
43
+ case 'dot':
44
+ return __assign({ position: 'absolute', right: -2, bottom: 0, width: sizeStyles.width, height: sizeStyles.height, borderRadius: '50%', backgroundColor: indicatorColor, border: "".concat(sizeStyles.borderWidth, "px solid white"), boxShadow: '0 1px 2px rgba(0,0,0,0.22)' }, style);
45
+ case 'badge':
46
+ return __assign({ display: 'inline-block', width: sizeStyles.width, height: sizeStyles.height, borderRadius: '50%', backgroundColor: indicatorColor }, style);
47
+ default:
48
+ return style;
49
+ }
50
+ };
51
+ var finalStyles = getVariantStyles();
52
+ return (React.createElement("span", { className: "online-indicator ".concat(variant === 'avatar' ? 'online-indicator-avatar' : '', " ").concat(className).trim(), style: finalStyles, "aria-label": actualIsBusy ? 'Busy' : 'Online' }));
53
+ };
54
+ export default OnlineIndicator;
@@ -16,6 +16,9 @@ interface ProfileModalProps {
16
16
  setWorkLocation: (location: string) => void;
17
17
  statusMessage: string;
18
18
  setStatusMessage: (message: string) => void;
19
+ isOnline?: boolean;
20
+ isInCall?: boolean;
21
+ userId: string;
19
22
  }
20
23
  declare const ProfileModal: React.FC<ProfileModalProps>;
21
24
  export default ProfileModal;