@myrjfa/ui 1.1.0 → 1.1.1

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 (131) hide show
  1. package/dist/chat/ChatMain.d.ts.map +1 -1
  2. package/dist/chat/ChatMain.js +173 -145
  3. package/dist/chat/ChatSidebar.js +7 -8
  4. package/dist/chat/ConversationList.d.ts.map +1 -1
  5. package/dist/chat/ConversationList.js +20 -18
  6. package/dist/chat/ExpensePanel.d.ts +4 -1
  7. package/dist/chat/ExpensePanel.d.ts.map +1 -1
  8. package/dist/chat/ExpensePanel.js +215 -195
  9. package/dist/chat/MessageBubble.d.ts +5 -3
  10. package/dist/chat/MessageBubble.d.ts.map +1 -1
  11. package/dist/chat/MessageBubble.js +185 -103
  12. package/dist/chat/MessageInput.d.ts +8 -1
  13. package/dist/chat/MessageInput.d.ts.map +1 -1
  14. package/dist/chat/MessageInput.js +182 -165
  15. package/dist/chat/MilestonePanel.d.ts +4 -1
  16. package/dist/chat/MilestonePanel.d.ts.map +1 -1
  17. package/dist/chat/MilestonePanel.js +150 -150
  18. package/dist/chat/components/ParticipantSelector.d.ts +11 -0
  19. package/dist/chat/components/ParticipantSelector.d.ts.map +1 -0
  20. package/dist/chat/components/ParticipantSelector.js +17 -0
  21. package/dist/chat/components/SplitInputs.d.ts +11 -0
  22. package/dist/chat/components/SplitInputs.d.ts.map +1 -0
  23. package/dist/chat/components/SplitInputs.js +83 -0
  24. package/dist/chat/components/SplitTypeSelector.d.ts +8 -0
  25. package/dist/chat/components/SplitTypeSelector.d.ts.map +1 -0
  26. package/dist/chat/components/SplitTypeSelector.js +13 -0
  27. package/dist/chat/dialogs/AddMemberDialog.js +30 -90
  28. package/dist/chat/dialogs/CameraDialog.js +38 -86
  29. package/dist/chat/dialogs/CreatePollDialog.d.ts +8 -0
  30. package/dist/chat/dialogs/CreatePollDialog.d.ts.map +1 -0
  31. package/dist/chat/dialogs/CreatePollDialog.js +38 -0
  32. package/dist/chat/dialogs/ExpenseAnalyticsDialog.d.ts +19 -0
  33. package/dist/chat/dialogs/ExpenseAnalyticsDialog.d.ts.map +1 -0
  34. package/dist/chat/dialogs/ExpenseAnalyticsDialog.js +52 -0
  35. package/dist/chat/dialogs/GroupInfoDialog.d.ts.map +1 -1
  36. package/dist/chat/dialogs/GroupInfoDialog.js +55 -92
  37. package/dist/chat/dialogs/GroupInfoViewDialog.js +5 -6
  38. package/dist/chat/dialogs/NewChatDialog.d.ts.map +1 -1
  39. package/dist/chat/dialogs/NewChatDialog.js +49 -113
  40. package/dist/chat/dialogs/NewGroupDialog.d.ts.map +1 -1
  41. package/dist/chat/dialogs/NewGroupDialog.js +49 -92
  42. package/dist/chat/dialogs/ParticipantsDialog.d.ts.map +1 -1
  43. package/dist/chat/dialogs/ParticipantsDialog.js +68 -118
  44. package/dist/chat/dialogs/UserProfileDialog.d.ts +10 -0
  45. package/dist/chat/dialogs/UserProfileDialog.d.ts.map +1 -0
  46. package/dist/chat/dialogs/UserProfileDialog.js +100 -0
  47. package/dist/dashboard/action-buttons.js +4 -5
  48. package/dist/dashboard/app-sidebar.js +46 -128
  49. package/dist/dashboard/card-header.js +1 -2
  50. package/dist/dashboard/dashboard-components.js +3 -5
  51. package/dist/dashboard/data-table.js +21 -33
  52. package/dist/dashboard/nav-main.js +4 -5
  53. package/dist/dashboard/nav-secondary.js +2 -25
  54. package/dist/dashboard/stats-card.js +1 -2
  55. package/dist/dashboard/table.js +8 -54
  56. package/dist/header/mobile-nav-item.js +1 -2
  57. package/dist/header/mobile-navbar.js +8 -9
  58. package/dist/header/nav-item.js +1 -2
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +1 -1
  62. package/dist/main/footer.js +5 -9
  63. package/dist/main/navbar.js +53 -136
  64. package/dist/main/paginationBar.js +12 -14
  65. package/dist/main/portfolio/portfolioItem.js +1 -2
  66. package/dist/main/portfolio/portfolioPopup.js +16 -17
  67. package/dist/main/review-page.d.ts.map +1 -1
  68. package/dist/main/review-page.js +131 -198
  69. package/dist/misc/accordion.js +8 -34
  70. package/dist/misc/alert-dialog.js +22 -55
  71. package/dist/misc/alert.js +7 -32
  72. package/dist/misc/alertdialogclaude.js +50 -125
  73. package/dist/misc/avatar.js +6 -31
  74. package/dist/misc/badge.js +4 -27
  75. package/dist/misc/button.js +4 -27
  76. package/dist/misc/card.js +12 -40
  77. package/dist/misc/carousel.js +37 -61
  78. package/dist/misc/checkbox.js +2 -25
  79. package/dist/misc/command.js +18 -49
  80. package/dist/misc/datepicker.js +66 -76
  81. package/dist/misc/dialog.js +20 -52
  82. package/dist/misc/dropdown-menu.js +30 -67
  83. package/dist/misc/faq.js +2 -3
  84. package/dist/misc/file-preview.js +43 -97
  85. package/dist/misc/filter.d.ts.map +1 -1
  86. package/dist/misc/filter.js +18 -21
  87. package/dist/misc/filterBar.js +136 -160
  88. package/dist/misc/form.js +39 -60
  89. package/dist/misc/image-cropper.d.ts +10 -0
  90. package/dist/misc/image-cropper.d.ts.map +1 -0
  91. package/dist/misc/image-cropper.js +44 -0
  92. package/dist/misc/input.js +2 -25
  93. package/dist/misc/label.js +2 -25
  94. package/dist/misc/line-carousel.js +3 -13
  95. package/dist/misc/multiImageUploader.js +2 -3
  96. package/dist/misc/newsLetter.js +18 -78
  97. package/dist/misc/notification.d.ts +1 -2
  98. package/dist/misc/notification.d.ts.map +1 -1
  99. package/dist/misc/notification.js +89 -125
  100. package/dist/misc/pagination.js +16 -45
  101. package/dist/misc/password-eye.js +2 -3
  102. package/dist/misc/popover.d.ts.map +1 -1
  103. package/dist/misc/popover.js +8 -34
  104. package/dist/misc/progress.js +2 -25
  105. package/dist/misc/scroll-area.js +5 -29
  106. package/dist/misc/searchBar.js +27 -31
  107. package/dist/misc/searchBox.js +18 -22
  108. package/dist/misc/select.d.ts.map +1 -1
  109. package/dist/misc/select.js +22 -54
  110. package/dist/misc/separator.js +2 -25
  111. package/dist/misc/share.js +48 -104
  112. package/dist/misc/sheet.js +21 -53
  113. package/dist/misc/sidebar.js +112 -153
  114. package/dist/misc/skeleton.js +2 -25
  115. package/dist/misc/slider.js +3 -26
  116. package/dist/misc/starRating.js +5 -15
  117. package/dist/misc/stateCard.js +7 -8
  118. package/dist/misc/switch.d.ts +5 -0
  119. package/dist/misc/switch.d.ts.map +1 -0
  120. package/dist/misc/switch.js +8 -0
  121. package/dist/misc/tabs.js +8 -34
  122. package/dist/misc/textarea.js +2 -25
  123. package/dist/misc/tile.js +31 -92
  124. package/dist/misc/tooltip.js +8 -34
  125. package/dist/profile/socialLink.d.ts +1 -1
  126. package/dist/profile/socialLink.d.ts.map +1 -1
  127. package/dist/profile/socialLink.js +53 -69
  128. package/dist/utils/permissions.d.ts +7 -0
  129. package/dist/utils/permissions.d.ts.map +1 -0
  130. package/dist/utils/permissions.js +38 -0
  131. package/package.json +3 -2
@@ -1,84 +1,72 @@
1
1
  "use client";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __generator = (this && this.__generator) || function (thisArg, body) {
12
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
- function verb(n) { return function (v) { return step([n, v]); }; }
15
- function step(op) {
16
- if (f) throw new TypeError("Generator is already executing.");
17
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
- if (y = 0, t) op = [op[0] & 2, t.value];
20
- switch (op[0]) {
21
- case 0: case 1: t = op; break;
22
- case 4: _.label++; return { value: op[1], done: false };
23
- case 5: _.label++; y = op[1]; op = [0]; continue;
24
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
- default:
26
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
- if (t[2]) _.ops.pop();
31
- _.trys.pop(); continue;
32
- }
33
- op = body.call(thisArg, _);
34
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
- }
37
- };
38
- var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
39
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
40
- if (ar || !(i in from)) {
41
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
42
- ar[i] = from[i];
43
- }
44
- }
45
- return to.concat(ar || Array.prototype.slice.call(from));
46
- };
47
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
48
3
  import { useState, useRef, useEffect } from "react";
49
- import { Send, Smile, Image as ImageIcon, FileText, Camera, MapPin, Mic, X, CircleStopIcon, VideoIcon, PlusCircleIcon, ListTodo, ReceiptText } from "lucide-react";
4
+ import { Send, Smile, Image as ImageIcon, FileText, Camera, MapPin, Mic, X, CircleStopIcon, VideoIcon, PlusCircleIcon, ListTodo, ReceiptText, ChartBar } from "lucide-react";
50
5
  import { Button } from "../misc/button";
51
6
  import { Textarea } from "../misc/textarea";
52
7
  import { Popover, PopoverContent, PopoverTrigger } from "../misc/popover";
8
+ import { Progress } from "../misc/progress";
53
9
  import { CameraDialog } from "./dialogs/CameraDialog";
10
+ import { CreatePollDialog } from "./dialogs/CreatePollDialog";
54
11
  import { showAlert } from "../misc/alertdialogclaude";
12
+ import { isCompressibleImage, compressImage } from "@myrjfa/state/dist/lib/utils/fileCompression";
55
13
  import EmojiPicker from 'emoji-picker-react';
56
- export function MessageInput(_a) {
57
- var _this = this;
58
- var _b;
59
- var onSend = _a.onSend, onTypingStart = _a.onTypingStart, onTypingStop = _a.onTypingStop, disabled = _a.disabled, replyTo = _a.replyTo, onCancelReply = _a.onCancelReply, onAddMilestone = _a.onAddMilestone, onAddExpense = _a.onAddExpense, _c = _a.activePanel, activePanel = _c === void 0 ? "chat" : _c;
60
- var _d = useState(""), text = _d[0], setText = _d[1];
61
- var _e = useState([]), selectedFiles = _e[0], setSelectedFiles = _e[1];
62
- var textareaRef = useRef(null);
63
- var fileInputRef = useRef(null);
64
- var _f = useState(""), fileAcceptType = _f[0], setFileAcceptType = _f[1];
65
- var typingTimeoutRef = useRef(null);
66
- var isTypingRef = useRef(false);
67
- var _g = useState(false), showEmojiPicker = _g[0], setShowEmojiPicker = _g[1];
68
- var _h = useState(false), isCameraOpen = _h[0], setIsCameraOpen = _h[1];
69
- var _j = useState(false), isRecording = _j[0], setIsRecording = _j[1];
70
- var mediaRecorderRef = useRef(null);
71
- var audioChunksRef = useRef([]);
14
+ export function MessageInput({ onSend, onTypingStart, onTypingStop, disabled, replyTo, editMessage, onEdit, onCancelEdit, onCancelReply, onAddMilestone, onAddExpense, onCreatePoll, participants = [], // Added
15
+ activePanel = "chat" }) {
16
+ var _a, _b, _c;
17
+ const [text, setText] = useState(editMessage ? (_b = (_a = editMessage === null || editMessage === void 0 ? void 0 : editMessage.content) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : "" : "");
18
+ const [mentionSearch, setMentionSearch] = useState(null);
19
+ const [mentionIndex, setMentionIndex] = useState(-1);
20
+ const [selectedFiles, setSelectedFiles] = useState([]);
21
+ const [uploadProgress, setUploadProgress] = useState(null);
22
+ const [isSending, setIsSending] = useState(false);
23
+ const textareaRef = useRef(null);
24
+ const fileInputRef = useRef(null);
25
+ const [fileAcceptType, setFileAcceptType] = useState("");
26
+ const typingTimeoutRef = useRef(null);
27
+ const isTypingRef = useRef(false);
28
+ const [showEmojiPicker, setShowEmojiPicker] = useState(false);
29
+ const [isCameraOpen, setIsCameraOpen] = useState(false);
30
+ const [isPollOpen, setIsPollOpen] = useState(false);
31
+ const [isRecording, setIsRecording] = useState(false);
32
+ const mediaRecorderRef = useRef(null);
33
+ const audioChunksRef = useRef([]);
34
+ const [mentionCoords, setMentionCoords] = useState({ top: 0, left: 0 }); // Added
72
35
  // Auto-resize textarea
73
- useEffect(function () {
74
- var el = textareaRef.current;
36
+ useEffect(() => {
37
+ const el = textareaRef.current;
75
38
  if (el) {
76
39
  el.style.height = "auto";
77
40
  el.style.height = Math.min(el.scrollHeight, 120) + "px";
78
41
  }
79
42
  }, [text]);
80
- function handleChange(e) {
81
- setText(e.target.value);
43
+ // Focus input when replyTo message is set
44
+ useEffect(() => {
45
+ var _a;
46
+ if (replyTo) {
47
+ (_a = textareaRef.current) === null || _a === void 0 ? void 0 : _a.focus();
48
+ }
49
+ }, [replyTo]);
50
+ const handleTextChange = (e) => {
51
+ const value = e.target.value;
52
+ const cursorPosition = e.target.selectionStart;
53
+ setText(value);
54
+ // Mention detection
55
+ const textBeforeCursor = value.substring(0, cursorPosition);
56
+ const lastAtChar = textBeforeCursor.lastIndexOf("@");
57
+ if (lastAtChar !== -1 && (lastAtChar === 0 || textBeforeCursor[lastAtChar - 1] === " ")) {
58
+ const search = textBeforeCursor.substring(lastAtChar + 1);
59
+ if (!search.includes(" ")) {
60
+ setMentionSearch(search);
61
+ setMentionIndex(lastAtChar);
62
+ }
63
+ else {
64
+ setMentionSearch(null);
65
+ }
66
+ }
67
+ else {
68
+ setMentionSearch(null);
69
+ }
82
70
  // Typing indicator
83
71
  if (!isTypingRef.current && e.target.value.length > 0) {
84
72
  isTypingRef.current = true;
@@ -87,26 +75,82 @@ export function MessageInput(_a) {
87
75
  // Reset typing timeout
88
76
  if (typingTimeoutRef.current)
89
77
  clearTimeout(typingTimeoutRef.current);
90
- typingTimeoutRef.current = setTimeout(function () {
78
+ typingTimeoutRef.current = setTimeout(() => {
91
79
  isTypingRef.current = false;
92
80
  onTypingStop === null || onTypingStop === void 0 ? void 0 : onTypingStop();
93
81
  }, 2000);
94
- }
95
- function handleSend() {
82
+ };
83
+ const insertMention = (username) => {
84
+ var _a;
85
+ if (mentionIndex === -1)
86
+ return;
87
+ const before = text.substring(0, mentionIndex);
88
+ const after = text.substring(((_a = textareaRef.current) === null || _a === void 0 ? void 0 : _a.selectionStart) || text.length);
89
+ const newText = `${before}@${username} ${after}`;
90
+ setText(newText);
91
+ setMentionSearch(null);
92
+ // Set cursor after the inserted mention
93
+ setTimeout(() => {
94
+ if (textareaRef.current) {
95
+ const newCursorPos = before.length + `@${username} `.length;
96
+ textareaRef.current.selectionStart = newCursorPos;
97
+ textareaRef.current.selectionEnd = newCursorPos;
98
+ textareaRef.current.focus();
99
+ }
100
+ }, 0);
101
+ };
102
+ async function handleSend() {
96
103
  var _a;
97
- var trimmed = text.trim();
104
+ const trimmed = text.trim();
98
105
  if ((!trimmed && selectedFiles.length === 0) || disabled)
99
106
  return;
100
- onSend(trimmed, selectedFiles);
101
- setText("");
102
- setSelectedFiles([]);
103
- // Clear typing
104
- if (typingTimeoutRef.current)
105
- clearTimeout(typingTimeoutRef.current);
106
- isTypingRef.current = false;
107
- onTypingStop === null || onTypingStop === void 0 ? void 0 : onTypingStop();
108
- // Refocus
109
- (_a = textareaRef.current) === null || _a === void 0 ? void 0 : _a.focus();
107
+ setIsSending(true);
108
+ setUploadProgress(0);
109
+ try {
110
+ let filesToSend = [...selectedFiles];
111
+ // Compress images
112
+ setUploadProgress(10); // Start progress for compression
113
+ const compressed = await Promise.all(filesToSend.map(async (file) => {
114
+ if (isCompressibleImage(file)) {
115
+ try {
116
+ return await compressImage(file);
117
+ }
118
+ catch (e) {
119
+ console.error("Compression failed for", file.name, e);
120
+ return file;
121
+ }
122
+ }
123
+ return file;
124
+ }));
125
+ setUploadProgress(30); // Compression done, starting upload
126
+ // Note: sendMessage doesn't currently support progress callback.
127
+ // We'll simulate progress or update it if chatApi supports it.
128
+ // For now, call sendMessage.
129
+ if (editMessage) {
130
+ await (onEdit === null || onEdit === void 0 ? void 0 : onEdit(editMessage._id, trimmed));
131
+ }
132
+ else {
133
+ await onSend(trimmed, compressed);
134
+ }
135
+ setUploadProgress(100);
136
+ setText("");
137
+ setSelectedFiles([]);
138
+ // Clear typing
139
+ if (typingTimeoutRef.current)
140
+ clearTimeout(typingTimeoutRef.current);
141
+ isTypingRef.current = false;
142
+ onTypingStop === null || onTypingStop === void 0 ? void 0 : onTypingStop();
143
+ // Refocus
144
+ (_a = textareaRef.current) === null || _a === void 0 ? void 0 : _a.focus();
145
+ }
146
+ catch (error) {
147
+ console.error(error);
148
+ showAlert("Failed to send message", "Error");
149
+ }
150
+ finally {
151
+ setIsSending(false);
152
+ setUploadProgress(null);
153
+ }
110
154
  }
111
155
  function handleKeyDown(e) {
112
156
  if (e.key === "Enter" && !e.shiftKey) {
@@ -114,21 +158,21 @@ export function MessageInput(_a) {
114
158
  handleSend();
115
159
  }
116
160
  }
117
- var handleFileChange = function (e) {
161
+ const handleFileChange = (e) => {
118
162
  if (e.target.files) {
119
- setSelectedFiles(function (prev) { return __spreadArray(__spreadArray([], prev, true), Array.from(e.target.files), true); });
163
+ setSelectedFiles(prev => [...prev, ...Array.from(e.target.files)]);
120
164
  }
121
165
  };
122
- var removeFile = function (index) {
123
- setSelectedFiles(function (prev) { return prev.filter(function (_, i) { return i !== index; }); });
166
+ const removeFile = (index) => {
167
+ setSelectedFiles(prev => prev.filter((_, i) => i !== index));
124
168
  };
125
- var handleLocation = function () {
169
+ const handleLocation = () => {
126
170
  if ("geolocation" in navigator) {
127
- navigator.geolocation.getCurrentPosition(function (position) {
128
- var _a = position.coords, latitude = _a.latitude, longitude = _a.longitude;
129
- var mapLink = "https://www.google.com/maps?q=".concat(latitude, ",").concat(longitude);
171
+ navigator.geolocation.getCurrentPosition((position) => {
172
+ const { latitude, longitude } = position.coords;
173
+ const mapLink = `https://www.google.com/maps?q=${latitude},${longitude}`;
130
174
  onSend(mapLink);
131
- }, function (error) {
175
+ }, (error) => {
132
176
  console.error("Error getting location:", error);
133
177
  showAlert("Could not get location.");
134
178
  });
@@ -137,99 +181,72 @@ export function MessageInput(_a) {
137
181
  showAlert("Geolocation is not supported by this browser.");
138
182
  }
139
183
  };
140
- var handleCameraCapture = function (file) {
141
- setSelectedFiles(function (prev) { return __spreadArray(__spreadArray([], prev, true), [file], false); });
184
+ const handleCameraCapture = (file) => {
185
+ setSelectedFiles(prev => [...prev, file]);
142
186
  };
143
- var startRecording = function () { return __awaiter(_this, void 0, void 0, function () {
144
- var stream_1, mediaRecorder, err_1;
145
- return __generator(this, function (_a) {
146
- switch (_a.label) {
147
- case 0:
148
- _a.trys.push([0, 2, , 3]);
149
- return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ audio: true })];
150
- case 1:
151
- stream_1 = _a.sent();
152
- mediaRecorder = new MediaRecorder(stream_1);
153
- mediaRecorderRef.current = mediaRecorder;
154
- audioChunksRef.current = [];
155
- mediaRecorder.ondataavailable = function (event) {
156
- if (event.data.size > 0) {
157
- audioChunksRef.current.push(event.data);
158
- }
159
- };
160
- mediaRecorder.onstop = function () {
161
- var audioBlob = new Blob(audioChunksRef.current, { type: "audio/webm" });
162
- var audioFile = new File([audioBlob], "voice_".concat(Date.now(), ".webm"), { type: "audio/webm" });
163
- setSelectedFiles(function (prev) { return __spreadArray(__spreadArray([], prev, true), [audioFile], false); });
164
- stream_1.getTracks().forEach(function (track) { return track.stop(); });
165
- };
166
- mediaRecorder.start();
167
- setIsRecording(true);
168
- return [3 /*break*/, 3];
169
- case 2:
170
- err_1 = _a.sent();
171
- console.error("Error accessing microphone:", err_1);
172
- alert("Could not access microphone");
173
- return [3 /*break*/, 3];
174
- case 3: return [2 /*return*/];
175
- }
176
- });
177
- }); };
178
- var stopRecording = function () {
187
+ const startRecording = async () => {
188
+ try {
189
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
190
+ const mediaRecorder = new MediaRecorder(stream);
191
+ mediaRecorderRef.current = mediaRecorder;
192
+ audioChunksRef.current = [];
193
+ mediaRecorder.ondataavailable = (event) => {
194
+ if (event.data.size > 0) {
195
+ audioChunksRef.current.push(event.data);
196
+ }
197
+ };
198
+ mediaRecorder.onstop = () => {
199
+ const audioBlob = new Blob(audioChunksRef.current, { type: "audio/webm" });
200
+ const audioFile = new File([audioBlob], `voice_${Date.now()}.webm`, { type: "audio/webm" });
201
+ setSelectedFiles(prev => [...prev, audioFile]);
202
+ stream.getTracks().forEach(track => track.stop());
203
+ };
204
+ mediaRecorder.start();
205
+ setIsRecording(true);
206
+ }
207
+ catch (err) {
208
+ console.error("Error accessing microphone:", err);
209
+ alert("Could not access microphone");
210
+ }
211
+ };
212
+ const stopRecording = () => {
179
213
  if (mediaRecorderRef.current && isRecording) {
180
214
  mediaRecorderRef.current.stop();
181
215
  setIsRecording(false);
182
216
  }
183
217
  };
184
- var handleEmojiSelect = function (emojiObject) {
218
+ const handleEmojiSelect = (emojiObject) => {
185
219
  if (textareaRef.current) {
186
- var cursorPos = textareaRef.current.selectionStart;
187
- var newText = text.slice(0, cursorPos) + emojiObject.emoji + text.slice(cursorPos);
220
+ const cursorPos = textareaRef.current.selectionStart;
221
+ const newText = text.slice(0, cursorPos) + emojiObject.emoji + text.slice(cursorPos);
188
222
  setText(newText);
189
223
  setShowEmojiPicker(false);
190
224
  textareaRef.current.focus();
191
225
  }
192
226
  };
193
227
  // Only show message input for chat panel
194
- var showMessageInput = activePanel === "chat";
195
- return (_jsxs("div", { className: "border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 p-3", children: [_jsx(CameraDialog, { open: isCameraOpen, onOpenChange: setIsCameraOpen, onCapture: handleCameraCapture }), selectedFiles.length > 0 && (_jsx("div", { className: "max-w-4xl mx-auto mb-2 flex flex-wrap gap-2", children: selectedFiles.map(function (file, i) { return (_jsxs("div", { className: "flex items-center bg-gray-100 dark:bg-gray-800 rounded-lg px-2 py-1 text-xs text-gray-600 dark:text-gray-300", children: [_jsx("span", { className: "truncate max-w-[150px]", children: file.name }), _jsx("button", { onClick: function () { return removeFile(i); }, className: "ml-2 text-red-500 hover:text-red-700 font-bold", children: "\u00D7" })] }, i)); }) })), replyTo && (_jsxs("div", { className: "max-w-4xl mx-auto mb-2 flex items-center gap-2 bg-gray-100 dark:bg-gray-800 px-3 py-2 rounded-lg border-l-2 border-teal-500", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "text-xs font-semibold text-teal-600 dark:text-teal-400", children: ["Replying to ", replyTo.senderId] }), _jsx("div", { className: "text-xs text-gray-600 dark:text-gray-400 truncate", children: (_b = replyTo.content.text) === null || _b === void 0 ? void 0 : _b.substring(0, 60) })] }), _jsx("button", { onClick: onCancelReply, className: "text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 flex-shrink-0", children: _jsx(X, { className: "w-4 h-4" }) })] })), _jsxs("div", { className: "".concat(showMessageInput ? "flex" : "hidden md:flex", " items-end gap-2 max-w-4xl mx-auto"), children: [_jsx("input", { type: "file", ref: fileInputRef, onChange: handleFileChange, accept: fileAcceptType, multiple: true, className: "hidden" }), _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full h-10 w-10 shrink-0", children: _jsx(PlusCircleIcon, { className: "w-5 h-5" }) }) }), _jsxs(PopoverContent, { side: "top", align: "start", className: "w-48 p-2 flex flex-col gap-1", children: [_jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full", onClick: function () { return __awaiter(_this, void 0, void 0, function () {
228
+ const showMessageInput = activePanel === "chat";
229
+ return (_jsxs("div", { className: "border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 p-3 relative", children: [_jsx(CameraDialog, { open: isCameraOpen, onOpenChange: setIsCameraOpen, onCapture: handleCameraCapture }), _jsx(CreatePollDialog, { open: isPollOpen, onOpenChange: setIsPollOpen, onCreate: (q, opts, multi) => {
230
+ onCreatePoll === null || onCreatePoll === void 0 ? void 0 : onCreatePoll(q, opts, multi);
231
+ } }), mentionSearch !== null && participants.length > 0 && (_jsxs("div", { className: "absolute bottom-full left-4 mb-2 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-xl w-48 py-1 z-50 overflow-y-auto max-h-48", children: [participants
232
+ .filter(p => !mentionSearch || p.userId.toLowerCase().includes(mentionSearch.toLowerCase()))
233
+ .map(p => (_jsx("button", { onClick: () => insertMention(p.userId), className: "w-full text-left px-3 py-2 text-sm hover:bg-indigo-50 dark:hover:bg-indigo-900/40 flex items-center gap-2", children: _jsxs("span", { className: "truncate", children: ["@", p.userId] }) }, p.userId))), participants.filter(p => !mentionSearch || p.userId.toLowerCase().includes(mentionSearch.toLowerCase())).length === 0 && (_jsx("div", { className: "px-3 py-2 text-xs text-gray-500 italic", children: "No members found" }))] })), selectedFiles.length > 0 && !editMessage && (_jsx("div", { className: "max-w-4xl mx-auto mb-2 flex flex-wrap gap-2", children: selectedFiles.map((file, i) => (_jsxs("div", { className: "flex items-center bg-gray-100 dark:bg-gray-800 rounded-lg px-2 py-1 text-xs text-gray-600 dark:text-gray-300", children: [_jsx("span", { className: "truncate max-w-[150px]", children: file.name }), _jsx("button", { onClick: () => removeFile(i), className: "ml-2 text-red-500 hover:text-red-700 font-bold", children: "\u00D7" })] }, i))) })), replyTo && (_jsxs("div", { className: "max-w-4xl mx-auto mb-2 flex items-center gap-2 bg-gray-100 dark:bg-gray-800 px-3 py-2 rounded-lg border-l-2 border-teal-500", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "text-xs font-semibold text-teal-600 dark:text-teal-400", children: editMessage ? "Editing" : ("Replying to" + replyTo.senderId) }), _jsx("div", { className: "text-xs text-gray-600 dark:text-gray-400 truncate", children: (_c = replyTo.content.text) === null || _c === void 0 ? void 0 : _c.substring(0, 60) })] }), _jsx("button", { onClick: onCancelReply, className: "text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 flex-shrink-0", children: _jsx(X, { className: "w-4 h-4" }) })] })), _jsxs("div", { className: `${showMessageInput ? "flex" : "hidden md:flex"} items-end gap-2 max-w-4xl mx-auto`, children: [_jsx("input", { type: "file", ref: fileInputRef, onChange: handleFileChange, accept: fileAcceptType, multiple: true, className: "hidden" }), !editMessage && _jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", className: "text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full h-10 w-10 shrink-0", children: _jsx(PlusCircleIcon, { className: "w-5 h-5" }) }) }), _jsxs(PopoverContent, { side: "top", align: "start", className: "w-48 p-2 flex flex-col gap-1", children: [_jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full", onClick: async () => {
196
234
  var _a;
197
- return __generator(this, function (_b) {
198
- switch (_b.label) {
199
- case 0: return [4 /*yield*/, setFileAcceptType(".pdf,.doc,.docx,.txt,.xlsx,.pptx")];
200
- case 1:
201
- _b.sent();
202
- (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
203
- return [2 /*return*/];
204
- }
205
- });
206
- }); }, children: [_jsx(FileText, { className: "w-4 h-4 text-purple-500" }), "Document"] }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full", onClick: function () { return __awaiter(_this, void 0, void 0, function () {
235
+ await setFileAcceptType(".pdf,.doc,.docx,.txt,.xlsx,.pptx");
236
+ (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
237
+ }, children: [_jsx(FileText, { className: "w-4 h-4 text-purple-500" }), "Document"] }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full", onClick: async () => {
207
238
  var _a;
208
- return __generator(this, function (_b) {
209
- switch (_b.label) {
210
- case 0: return [4 /*yield*/, setFileAcceptType("image/*")];
211
- case 1:
212
- _b.sent();
213
- (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
214
- return [2 /*return*/];
215
- }
216
- });
217
- }); }, children: [_jsx(ImageIcon, { className: "w-4 h-4 text-blue-500" }), "Photos"] }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full", onClick: function () { return __awaiter(_this, void 0, void 0, function () {
239
+ await setFileAcceptType("image/*");
240
+ (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
241
+ }, children: [_jsx(ImageIcon, { className: "w-4 h-4 text-blue-500" }), "Photos"] }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full", onClick: async () => {
218
242
  var _a;
219
- return __generator(this, function (_b) {
220
- switch (_b.label) {
221
- case 0: return [4 /*yield*/, setFileAcceptType("video/*")];
222
- case 1:
223
- _b.sent();
224
- (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
225
- return [2 /*return*/];
226
- }
227
- });
228
- }); }, children: [_jsx(VideoIcon, { className: "w-4 h-4 text-rose-500" }), "Videos"] }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full", onClick: handleLocation, children: [_jsx(MapPin, { className: "w-4 h-4 text-green-500" }), "Location"] }), _jsx("div", { className: "border-t border-gray-200 dark:border-gray-700 my-1" }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full text-teal-600 dark:text-teal-400", onClick: function () {
243
+ await setFileAcceptType("video/*");
244
+ (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
245
+ }, children: [_jsx(VideoIcon, { className: "w-4 h-4 text-rose-500" }), "Videos"] }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full", onClick: handleLocation, children: [_jsx(MapPin, { className: "w-4 h-4 text-green-500" }), "Location"] }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full", onClick: () => setIsPollOpen(true), children: [_jsx(ChartBar, { className: "w-4 h-4 text-orange-500" }), "Poll"] }), _jsx("div", { className: "border-t border-gray-200 dark:border-gray-700 my-1" }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full text-teal-600 dark:text-teal-400", onClick: () => {
229
246
  onAddMilestone === null || onAddMilestone === void 0 ? void 0 : onAddMilestone();
230
- }, children: [_jsx(ListTodo, { className: "w-4 h-4" }), "Add Milestone"] }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full text-teal-600 dark:text-teal-400", onClick: function () {
247
+ }, children: [_jsx(ListTodo, { className: "w-4 h-4" }), "Add Milestone"] }), _jsxs(Button, { variant: "ghost", className: "justify-start gap-2 w-full text-teal-600 dark:text-teal-400", onClick: () => {
231
248
  onAddExpense === null || onAddExpense === void 0 ? void 0 : onAddExpense();
232
- }, children: [_jsx(ReceiptText, { className: "w-4 h-4" }), "Add Expense"] })] })] }), _jsxs("div", { className: "flex-1 bg-gray-100 dark:bg-gray-800 rounded-2xl flex items-end", children: [_jsx(Textarea, { ref: textareaRef, value: text, onChange: handleChange, onKeyDown: handleKeyDown, placeholder: "Type a message...", disabled: disabled, rows: 1, className: "flex-1 bg-transparent border-none focus-visible:ring-0 px-4 py-3 text-[15px] resize-none text-gray-900 dark:text-white placeholder-gray-400 max-h-[120px] min-h-[48px]" }), _jsx(Button, { variant: "ghost", size: "icon", className: "mr-1 mb-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hidden sm:inline-flex", onClick: function () { return setShowEmojiPicker(!showEmojiPicker); }, children: _jsx(Smile, { className: "w-5 h-5" }) }), _jsx(Button, { variant: "ghost", size: "icon", className: "mr-1 mb-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full", onClick: function () { return setIsCameraOpen(true); }, children: _jsx(Camera, { className: "w-5 h-5" }) })] }), text.trim() || selectedFiles.length > 0 ? (_jsx(Button, { onClick: handleSend, disabled: disabled, className: "rounded-full h-11 w-11 p-0 bg-gradient-to-r from-teal-500 to-cyan-600 hover:from-teal-600 hover:to-cyan-700 shadow-lg shadow-teal-500/25 shrink-0", children: _jsx(Send, { className: "w-5 h-5" }) })) : (_jsx(Button, { variant: "ghost", size: "icon", className: "rounded-full h-11 w-11 shrink-0 transition-all ".concat(isRecording
249
+ }, children: [_jsx(ReceiptText, { className: "w-4 h-4" }), "Add Expense"] })] })] }), _jsxs("div", { className: "flex-1 bg-gray-100 dark:bg-gray-800 rounded-2xl flex items-end relative", children: [_jsx(Textarea, { ref: textareaRef, value: text, onChange: handleTextChange, onKeyDown: handleKeyDown, placeholder: "Type a message...", disabled: disabled || isSending, rows: 1, className: "flex-1 bg-transparent border-none focus-visible:ring-0 px-4 py-3 text-[15px] resize-none text-gray-900 dark:text-white placeholder-gray-400 max-h-[120px] min-h-[48px]" }), uploadProgress !== null && (_jsx("div", { className: "absolute left-0 bottom-full w-full px-4 mb-2", children: _jsxs("div", { className: "bg-white dark:bg-gray-800 p-2 rounded-lg shadow-lg border border-gray-100 dark:border-gray-700", children: [_jsxs("div", { className: "flex justify-between items-center mb-1", children: [_jsx("span", { className: "text-[10px] text-gray-500 font-medium", children: "Uploading..." }), _jsxs("span", { className: "text-[10px] text-indigo-500 font-bold", children: [uploadProgress, "%"] })] }), _jsx(Progress, { value: uploadProgress, className: "h-1" })] }) })), _jsx(Button, { variant: "ghost", size: "icon", className: "mr-1 mb-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hidden sm:inline-flex", onClick: () => setShowEmojiPicker(!showEmojiPicker), children: _jsx(Smile, { className: "w-5 h-5" }) }), !editMessage && _jsx(Button, { variant: "ghost", size: "icon", className: "mr-1 mb-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full", onClick: () => setIsCameraOpen(true), children: _jsx(Camera, { className: "w-5 h-5" }) })] }), text.trim() || selectedFiles.length > 0 || editMessage ? (_jsx(Button, { onClick: handleSend, disabled: disabled, className: "rounded-full h-11 w-11 p-0 bg-gradient-to-r from-teal-500 to-cyan-600 hover:from-teal-600 hover:to-cyan-700 shadow-lg shadow-teal-500/25 shrink-0", children: _jsx(Send, { className: "w-5 h-5" }) })) : (_jsx(Button, { variant: "ghost", size: "icon", className: `rounded-full h-11 w-11 shrink-0 transition-all ${isRecording
233
250
  ? "bg-red-500 hover:bg-red-600 animate-pulse text-white"
234
- : "text-teal-400 hover:bg-teal-100 dark:hover:bg-teal-800"), onClick: function () { return isRecording ? stopRecording() : startRecording(); }, children: isRecording ? _jsx(CircleStopIcon, { className: "w-6 h-6" }) : _jsx(Mic, { className: "w-6 h-6" }) })), showEmojiPicker && _jsx(EmojiPicker, { onEmojiClick: handleEmojiSelect })] })] }));
251
+ : "text-teal-400 hover:bg-teal-100 dark:hover:bg-teal-800"}`, onClick: () => isRecording ? stopRecording() : startRecording(), children: isRecording ? _jsx(CircleStopIcon, { className: "w-6 h-6" }) : _jsx(Mic, { className: "w-6 h-6" }) })), editMessage && _jsx(Button, { variant: "ghost", size: "icon", className: "rounded-full h-11 w-11 shrink-0", onClick: onCancelEdit, children: _jsx(X, { className: "w-5 h-5" }) }), showEmojiPicker && _jsx(EmojiPicker, { onEmojiClick: handleEmojiSelect })] })] }));
235
252
  }
@@ -2,7 +2,10 @@ interface MilestonePanelProps {
2
2
  conversationId: string;
3
3
  currentUserId: string;
4
4
  isFullScreen?: boolean;
5
+ isFeatureEnabled?: boolean;
6
+ isAdmin?: boolean;
7
+ onEnableFeature?: () => void;
5
8
  }
6
- export declare function MilestonePanel({ conversationId, currentUserId, isFullScreen }: MilestonePanelProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function MilestonePanel({ conversationId, currentUserId, isFullScreen, isFeatureEnabled, isAdmin, onEnableFeature }: MilestonePanelProps): import("react/jsx-runtime").JSX.Element;
7
10
  export {};
8
11
  //# sourceMappingURL=MilestonePanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MilestonePanel.d.ts","sourceRoot":"","sources":["../../src/chat/MilestonePanel.tsx"],"names":[],"mappings":"AASA,UAAU,mBAAmB;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAAC,EAAE,cAAc,EAAE,aAAa,EAAE,YAAoB,EAAE,EAAE,mBAAmB,2CAgL1G"}
1
+ {"version":3,"file":"MilestonePanel.d.ts","sourceRoot":"","sources":["../../src/chat/MilestonePanel.tsx"],"names":[],"mappings":"AAYA,UAAU,mBAAmB;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;CAChC;AAED,wBAAgB,cAAc,CAAC,EAC3B,cAAc,EACd,aAAa,EACb,YAAoB,EACpB,gBAAuB,EACvB,OAAe,EACf,eAAe,EAClB,EAAE,mBAAmB,2CA6brB"}