@serhii.olishevskyi/docs 1.0.3 → 1.0.5

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.
package/dist/index.mjs CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  TranslateText,
14
14
  TranslationDialog,
15
15
  TranslationEditProvider,
16
+ UserPopoverComponent_default,
16
17
  UserRoleChipComponent,
17
18
  UserStatusChipComponent,
18
19
  translationService,
@@ -25,7 +26,7 @@ import {
25
26
  useToast,
26
27
  useTranslationEdit,
27
28
  useTranslationNamespace
28
- } from "./chunk-CT3G3YSD.mjs";
29
+ } from "./chunk-R2QQMMHL.mjs";
29
30
 
30
31
  // src/UI/components/inputs/TextFieldComponent.tsx
31
32
  import { useState } from "react";
@@ -723,7 +724,7 @@ var EmailInputComponent = ({
723
724
  import { useState as useState5, useEffect as useEffect2, lazy, Suspense } from "react";
724
725
  import { Avatar, Tooltip as Tooltip3, Typography as Typography2 } from "@mui/material";
725
726
  import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
726
- var LazyUserPopover = lazy(() => import("./UserPopoverComponent-BNJWFSLT.mjs"));
727
+ var LazyUserPopover = lazy(() => import("./UserPopoverComponent-JBJBONYL.mjs"));
727
728
  var getInitials = (name) => {
728
729
  if (!name) return "?";
729
730
  const parts = name.trim().split(" ");
@@ -851,6 +852,7 @@ var UI = {
851
852
  DataDisplay: {
852
853
  TranslatableTooltip: TranslatableTooltipComponent,
853
854
  UserAvatar: UserAvatarComponent,
855
+ UserPopover: UserPopoverComponent_default,
854
856
  UserRoleChip: UserRoleChipComponent,
855
857
  UserStatusChip: UserStatusChipComponent
856
858
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serhii.olishevskyi/docs",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "DOCS.UA react packages",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -24,9 +24,10 @@
24
24
  "@mui/material": "^9.3.1",
25
25
  "@mui/x-data-grid-premium": "^9.12.0",
26
26
  "@mui/x-license": "^9.12.0",
27
+ "i18next": "^26.3.6",
27
28
  "react": "^18.0.0 || ^19.0.0",
28
29
  "react-dom": "^18.0.0 || ^19.0.0",
29
- "react-i18next": "^13.0.0"
30
+ "react-i18next": "^17.0.11"
30
31
  },
31
32
  "devDependencies": {
32
33
  "tsup": "^8.5.1",
@@ -1,399 +0,0 @@
1
- import {
2
- CopyClipboardButtonComponent,
3
- TranslatableTooltipComponent,
4
- TranslateText,
5
- UserRoleChipComponent,
6
- UserStatusChipComponent,
7
- getUserLastSeenAt,
8
- useAuth,
9
- useLocalization,
10
- useSupabase
11
- } from "./chunk-CT3G3YSD.mjs";
12
-
13
- // src/UI/components/data.display/UserPopoverComponent.tsx
14
- import { useEffect as useEffect2, useState as useState2 } from "react";
15
- import {
16
- Popover,
17
- Box,
18
- Avatar,
19
- Typography,
20
- Divider,
21
- IconButton,
22
- CircularProgress,
23
- Stack,
24
- Badge
25
- } from "@mui/material";
26
- import {
27
- NotificationsNone as NotificationIcon,
28
- AssignmentOutlined as TaskIcon,
29
- ChatBubble as ChatIcon,
30
- Work as WorkIcon,
31
- CalendarToday as CalendarIcon,
32
- Phone as PhoneIcon,
33
- Close as CloseIcon,
34
- Email as EmailIcon,
35
- AccessTime as AccessTimeIcon,
36
- Cake as CakeIcon
37
- } from "@mui/icons-material";
38
-
39
- // src/context/UserSettingsProvider.tsx
40
- import { createContext, useContext, useEffect, useState, useCallback } from "react";
41
- import { jsx } from "react/jsx-runtime";
42
- var UserSettingsContext = createContext(void 0);
43
- var useUserSettings = () => {
44
- const context = useContext(UserSettingsContext);
45
- if (!context) {
46
- throw new Error("useUserSettings should be used within the UserSettingsProvider");
47
- }
48
- return context;
49
- };
50
-
51
- // src/UI/components/data.display/UserPopoverComponent.tsx
52
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
53
- var useUserStatus = (supabase, userId, open) => {
54
- const [lastSeenAt, setLastSeenAt] = useState2(null);
55
- const [loading, setLoading] = useState2(true);
56
- useEffect2(() => {
57
- if (!userId || !open) {
58
- setLastSeenAt(null);
59
- setLoading(false);
60
- return;
61
- }
62
- let isMounted = true;
63
- const loadStatus = async () => {
64
- setLoading(true);
65
- const date = await getUserLastSeenAt(supabase, userId);
66
- if (isMounted) {
67
- setLastSeenAt(date);
68
- setLoading(false);
69
- }
70
- };
71
- loadStatus();
72
- const channel = supabase.channel(`user_status_popover_${userId}`).on(
73
- "postgres_changes",
74
- {
75
- event: "*",
76
- schema: "public",
77
- table: "user_sessions",
78
- filter: `user_id=eq.${userId}`
79
- },
80
- () => {
81
- loadStatus();
82
- }
83
- ).subscribe();
84
- return () => {
85
- isMounted = false;
86
- supabase.removeChannel(channel);
87
- };
88
- }, [userId, open]);
89
- const isOnline = Boolean(
90
- lastSeenAt && (/* @__PURE__ */ new Date()).getTime() - new Date(lastSeenAt).getTime() < 3 * 60 * 1e3
91
- );
92
- return { lastSeenAt, isOnline, loading };
93
- };
94
- var UserPopoverComponent = ({
95
- overrideNamespace,
96
- userId,
97
- anchorEl,
98
- open,
99
- onClose
100
- }) => {
101
- const supabase = useSupabase();
102
- const { activeCompanyId, membership: currentMembership } = useAuth();
103
- const { openChatWithUser } = useUserSettings();
104
- const { formatDate, formatRelativeTime } = useLocalization();
105
- const [profileData, setProfileData] = useState2(null);
106
- const [membershipData, setMembershipData] = useState2(null);
107
- const [avatarUrl, setAvatarUrl] = useState2(null);
108
- const [coverUrl, setCoverUrl] = useState2(null);
109
- const [loading, setLoading] = useState2(true);
110
- const { lastSeenAt, isOnline } = useUserStatus(supabase, userId, open);
111
- useEffect2(() => {
112
- if (!open || !userId || !activeCompanyId) return;
113
- let isMounted = true;
114
- setLoading(true);
115
- const fetchUserData = async () => {
116
- try {
117
- const { data, error } = await supabase.rpc("get_user_avatar_and_profile", {
118
- p_company_id: activeCompanyId,
119
- //currentMembership?.id || null,
120
- p_user_id: userId
121
- }).maybeSingle();
122
- if (error) throw error;
123
- if (isMounted && data) {
124
- const rpcData = data;
125
- const profile = rpcData.profile;
126
- const membership = rpcData.membership;
127
- setProfileData(profile);
128
- setMembershipData(membership);
129
- const avatarPath = profile?.avatar_path || profile?.avatar_url;
130
- if (avatarPath && !avatarPath.startsWith("http")) {
131
- const { data: avatarSigned } = await supabase.storage.from("user-media").createSignedUrl(avatarPath, 3600);
132
- if (isMounted) setAvatarUrl(avatarSigned?.signedUrl || null);
133
- } else {
134
- if (isMounted) setAvatarUrl(avatarPath || null);
135
- }
136
- const coverPath = profile?.cover_image_path || profile?.cover_image_url;
137
- if (coverPath && !coverPath.startsWith("http")) {
138
- const { data: coverSigned } = await supabase.storage.from("user-media").createSignedUrl(coverPath, 3600);
139
- if (isMounted) setCoverUrl(coverSigned?.signedUrl || null);
140
- } else {
141
- if (isMounted) setCoverUrl(coverPath || null);
142
- }
143
- }
144
- } catch (err) {
145
- console.error("Error loading user popover data:", err);
146
- } finally {
147
- if (isMounted) setLoading(false);
148
- }
149
- };
150
- fetchUserData();
151
- return () => {
152
- isMounted = false;
153
- };
154
- }, [open, userId, currentMembership?.id, activeCompanyId]);
155
- const getStatusChip = () => {
156
- if (!profileData) return null;
157
- return /* @__PURE__ */ jsx2(UserStatusChipComponent, { state: { profile_archived: profileData.archived, profile_locked: profileData.locked, excluded: membershipData?.excluded || false, locked: membershipData?.locked || false, locked_reason: membershipData?.locked_reason || "" } });
158
- };
159
- const getStatusTypographyColor = (isOnline2, lastSeenAt2) => {
160
- if (isOnline2) return "success";
161
- if (!lastSeenAt2) return "textSecondary";
162
- const diffInMinutes = (Date.now() - new Date(lastSeenAt2).getTime()) / (1e3 * 60);
163
- if (diffInMinutes <= 15) {
164
- return "warning";
165
- }
166
- return "textSecondary";
167
- };
168
- const getStatusIconColor = (isOnline2, lastSeenAt2) => {
169
- if (isOnline2) return "success";
170
- if (!lastSeenAt2) return "inherit";
171
- const diffInMinutes = (Date.now() - new Date(lastSeenAt2).getTime()) / (1e3 * 60);
172
- if (diffInMinutes <= 15) {
173
- return "warning";
174
- }
175
- return "inherit";
176
- };
177
- const canChat = currentMembership && membershipData && currentMembership.id !== membershipData.id;
178
- return /* @__PURE__ */ jsx2(
179
- Popover,
180
- {
181
- open,
182
- anchorEl,
183
- onClose,
184
- anchorOrigin: { vertical: "bottom", horizontal: "left" },
185
- transformOrigin: { vertical: "top", horizontal: "left" },
186
- slotProps: {
187
- paper: {
188
- sx: {
189
- width: 350,
190
- p: 0,
191
- overflow: "hidden",
192
- borderRadius: 0,
193
- boxShadow: 4
194
- }
195
- }
196
- },
197
- children: loading ? /* @__PURE__ */ jsx2(Box, { sx: { display: "flex", justifyContent: "center", py: 4 }, children: /* @__PURE__ */ jsx2(CircularProgress, { size: 28 }) }) : profileData ? /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column" }, children: [
198
- /* @__PURE__ */ jsxs(
199
- Box,
200
- {
201
- sx: {
202
- position: "relative",
203
- width: "100%",
204
- height: 96,
205
- bgcolor: "action.selected"
206
- },
207
- children: [
208
- coverUrl && /* @__PURE__ */ jsx2(
209
- Box,
210
- {
211
- component: "img",
212
- src: coverUrl,
213
- alt: "Profile background",
214
- sx: {
215
- width: "100%",
216
- height: "100%",
217
- objectFit: "cover",
218
- display: "block",
219
- m: 0,
220
- p: 0
221
- }
222
- }
223
- ),
224
- /* @__PURE__ */ jsx2(
225
- IconButton,
226
- {
227
- size: "small",
228
- onClick: onClose,
229
- sx: {
230
- position: "absolute",
231
- top: 8,
232
- right: 8,
233
- color: "common.white",
234
- bgcolor: "rgba(0, 0, 0, 0.4)",
235
- backdropFilter: "blur(4px)",
236
- transition: "all 0.2s ease",
237
- "&:hover": {
238
- bgcolor: "rgba(0, 0, 0, 0.8)",
239
- transform: "scale(1.1)"
240
- }
241
- },
242
- children: /* @__PURE__ */ jsx2(CloseIcon, { fontSize: "small" })
243
- }
244
- )
245
- ]
246
- }
247
- ),
248
- /* @__PURE__ */ jsxs(Box, { sx: { p: 2, pt: 0 }, children: [
249
- /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1.5, sx: { alignItems: "flex-end", mt: "-18px", mb: 1 }, children: [
250
- /* @__PURE__ */ jsx2(
251
- Badge,
252
- {
253
- overlap: "circular",
254
- anchorOrigin: { vertical: "bottom", horizontal: "right" },
255
- variant: "dot",
256
- sx: {
257
- "& .MuiBadge-badge": {
258
- backgroundColor: isOnline ? "#44b700" : "#bdbdbd",
259
- color: isOnline ? "#44b700" : "#bdbdbd",
260
- boxShadow: `0 0 0 2px #fff`,
261
- width: 12,
262
- height: 12,
263
- borderRadius: "50%",
264
- "&::after": isOnline ? {
265
- position: "absolute",
266
- top: 0,
267
- left: 0,
268
- width: "100%",
269
- height: "100%",
270
- borderRadius: "50%",
271
- animation: "ripple 1.2s infinite ease-in-out",
272
- border: "1px solid currentColor",
273
- content: '""'
274
- } : {}
275
- },
276
- "@keyframes ripple": {
277
- "0%": {
278
- transform: "scale(.8)",
279
- opacity: 1
280
- },
281
- "100%": {
282
- transform: "scale(2.4)",
283
- opacity: 0
284
- }
285
- }
286
- },
287
- children: /* @__PURE__ */ jsx2(
288
- Avatar,
289
- {
290
- src: avatarUrl || coverUrl || void 0,
291
- sx: {
292
- width: 65,
293
- height: 65,
294
- border: "3px solid",
295
- borderColor: "background.paper",
296
- boxShadow: 2,
297
- bgcolor: "primary.main",
298
- fontSize: 22,
299
- fontWeight: 600
300
- },
301
- children: profileData.display_name?.[0]?.toUpperCase() || "?"
302
- }
303
- )
304
- }
305
- ),
306
- /* @__PURE__ */ jsxs(Box, { sx: { overflow: "hidden", pb: 0.5 }, children: [
307
- /* @__PURE__ */ jsx2(Typography, { variant: "subtitle1", sx: { fontWeight: 600, lineHeight: 1.2 }, noWrap: true, children: profileData.display_name || `${profileData.first_name || ""} ${profileData.last_name || ""}` }),
308
- membershipData?.employee_post && /* @__PURE__ */ jsx2(Typography, { variant: "body2", color: "text.secondary", noWrap: true, children: membershipData.employee_post })
309
- ] })
310
- ] }),
311
- /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { my: 1, flexWrap: "wrap", gap: 0.5 }, children: [
312
- getStatusChip(),
313
- /* @__PURE__ */ jsx2(UserRoleChipComponent, { role: membershipData?.role || "user" })
314
- ] }),
315
- /* @__PURE__ */ jsx2(Divider, { sx: { my: 1.5 } }),
316
- /* @__PURE__ */ jsxs(Stack, { spacing: 1, sx: { fontSize: "0.875rem", mb: 1.5 }, children: [
317
- /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
318
- /* @__PURE__ */ jsx2(AccessTimeIcon, { fontSize: "small", color: getStatusIconColor(isOnline, lastSeenAt) }),
319
- /* @__PURE__ */ jsx2(Typography, { variant: "body2", color: getStatusTypographyColor(isOnline, lastSeenAt), children: isOnline ? /* @__PURE__ */ jsx2(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Online" }) : lastSeenAt ? /* @__PURE__ */ jsxs(Fragment, { children: [
320
- /* @__PURE__ */ jsx2(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Last seen" }),
321
- ":",
322
- " ",
323
- /* @__PURE__ */ jsx2("strong", { children: formatRelativeTime(lastSeenAt) })
324
- ] }) : /* @__PURE__ */ jsx2(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Offline" }) })
325
- ] }),
326
- profileData.email && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
327
- /* @__PURE__ */ jsx2(EmailIcon, { fontSize: "small" }),
328
- /* @__PURE__ */ jsx2(Typography, { variant: "body2", color: "text.primary", noWrap: true, sx: { flexGrow: 1 }, children: profileData.email }),
329
- /* @__PURE__ */ jsx2(CopyClipboardButtonComponent, { textToCopy: profileData.email })
330
- ] }),
331
- membershipData?.employee_post && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
332
- /* @__PURE__ */ jsx2(WorkIcon, { fontSize: "small" }),
333
- /* @__PURE__ */ jsx2(Typography, { variant: "body2", color: "text.primary", noWrap: true, sx: { flexGrow: 1 }, children: membershipData.employee_post }),
334
- /* @__PURE__ */ jsx2(CopyClipboardButtonComponent, { textToCopy: membershipData.employee_post })
335
- ] }),
336
- profileData.phone && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
337
- /* @__PURE__ */ jsx2(PhoneIcon, { fontSize: "small" }),
338
- /* @__PURE__ */ jsx2(Typography, { variant: "body2", color: "text.primary", children: profileData.phone })
339
- ] }),
340
- profileData.birthday && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
341
- /* @__PURE__ */ jsx2(CakeIcon, { fontSize: "small" }),
342
- /* @__PURE__ */ jsx2(Typography, { variant: "body2", color: "text.primary", children: formatDate(profileData.birthday) })
343
- ] }),
344
- membershipData?.created_at && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
345
- /* @__PURE__ */ jsx2(CalendarIcon, { fontSize: "small" }),
346
- /* @__PURE__ */ jsxs(Typography, { variant: "body2", color: "text.primary", children: [
347
- /* @__PURE__ */ jsx2(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "In company from" }),
348
- ": ",
349
- formatDate(membershipData.created_at)
350
- ] })
351
- ] }),
352
- profileData.description && /* @__PURE__ */ jsx2(
353
- Typography,
354
- {
355
- variant: "caption",
356
- color: "text.secondary",
357
- sx: {
358
- display: "-webkit-box",
359
- WebkitLineClamp: 2,
360
- WebkitBoxOrient: "vertical",
361
- overflow: "hidden",
362
- mt: 0.5
363
- },
364
- children: profileData.description
365
- }
366
- )
367
- ] }),
368
- /* @__PURE__ */ jsx2(Divider, { sx: { my: 1 } }),
369
- /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { justifyContent: "space-around", pt: 0.5 }, children: [
370
- /* @__PURE__ */ jsx2(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx2(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Send a notification" }), children: /* @__PURE__ */ jsx2(IconButton, { size: "small", color: "primary", children: /* @__PURE__ */ jsx2(NotificationIcon, { fontSize: "small" }) }) }),
371
- /* @__PURE__ */ jsx2(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx2(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Set a task" }), children: /* @__PURE__ */ jsx2(IconButton, { size: "small", color: "primary", children: /* @__PURE__ */ jsx2(TaskIcon, { fontSize: "small" }) }) }),
372
- /* @__PURE__ */ jsx2(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx2(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Start a chat" }), children: /* @__PURE__ */ jsx2(
373
- IconButton,
374
- {
375
- size: "small",
376
- color: "primary",
377
- disabled: !canChat,
378
- onClick: () => membershipData && openChatWithUser(membershipData.id),
379
- children: /* @__PURE__ */ jsx2(ChatIcon, { fontSize: "small" })
380
- }
381
- ) })
382
- ] })
383
- ] })
384
- ] }) : /* @__PURE__ */ jsx2(Box, { sx: { p: 2 }, children: /* @__PURE__ */ jsx2(
385
- Typography,
386
- {
387
- color: "error",
388
- variant: "body2",
389
- children: /* @__PURE__ */ jsx2(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Failed to load user data" })
390
- }
391
- ) })
392
- }
393
- );
394
- };
395
- var UserPopoverComponent_default = UserPopoverComponent;
396
- export {
397
- UserPopoverComponent,
398
- UserPopoverComponent_default as default
399
- };