@serhii.olishevskyi/docs 1.0.5 → 1.0.7

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.
@@ -1,5 +1,5 @@
1
1
  // src/UI/components/data.display/UserPopoverComponent.tsx
2
- import { useEffect as useEffect8, useState as useState12 } from "react";
2
+ import { useEffect as useEffect9, useState as useState13 } from "react";
3
3
  import {
4
4
  Popover,
5
5
  Box as Box4,
@@ -189,7 +189,54 @@ var config_default = i18n;
189
189
  // src/context/AuthProvider.tsx
190
190
  import { createContext as createContext3, useContext as useContext3, useEffect, useState, useCallback, useRef } from "react";
191
191
 
192
+ // src/utils/deviceId.ts
193
+ var getDeviceId = () => {
194
+ let deviceId = localStorage.getItem("app_device_id");
195
+ if (!deviceId) {
196
+ deviceId = crypto.randomUUID();
197
+ localStorage.setItem("app_device_id", deviceId);
198
+ }
199
+ return deviceId;
200
+ };
201
+
192
202
  // src/services/session.service.ts
203
+ var trackUserSession = async (supabase, userId) => {
204
+ const deviceId = getDeviceId();
205
+ let ip = "";
206
+ try {
207
+ const ipRes = await fetch("https://api.ipify.org?format=json");
208
+ const ipData = await ipRes.json();
209
+ ip = ipData.ip;
210
+ } catch (e) {
211
+ console.warn("Failed to fetch IP address", e);
212
+ }
213
+ await supabase.from("user_sessions").upsert(
214
+ {
215
+ user_id: userId,
216
+ device_id: deviceId,
217
+ user_agent: navigator.userAgent,
218
+ ip_address: ip,
219
+ url: window.location.href,
220
+ last_seen_at: (/* @__PURE__ */ new Date()).toISOString()
221
+ },
222
+ { onConflict: "user_id, device_id" }
223
+ );
224
+ };
225
+ var isCurrentSessionValid = async (supabase, userId) => {
226
+ try {
227
+ const currentDeviceId = getDeviceId();
228
+ const { data, error } = await supabase.from("user_sessions").select("id").eq("user_id", userId).eq("device_id", currentDeviceId).maybeSingle();
229
+ if (error) {
230
+ console.warn("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0438 \u0441\u0435\u0441\u0456\u0457:", error.message);
231
+ return true;
232
+ }
233
+ if (!data) return false;
234
+ return true;
235
+ } catch (err) {
236
+ console.error("\u041D\u0435\u0441\u043F\u043E\u0434\u0456\u0432\u0430\u043D\u0430 \u043F\u043E\u043C\u0438\u043B\u043A\u0430 \u043F\u0440\u0438 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u0446\u0456 \u0441\u0435\u0441\u0456\u0457:", err);
237
+ return true;
238
+ }
239
+ };
193
240
  var getUserLastSeenAt = async (supabase, userId) => {
194
241
  const { data, error } = await supabase.from("user_sessions").select("last_seen_at").eq("user_id", userId).order("last_seen_at", { ascending: false }).limit(1).maybeSingle();
195
242
  if (error || !data) return null;
@@ -199,6 +246,179 @@ var getUserLastSeenAt = async (supabase, userId) => {
199
246
  // src/context/AuthProvider.tsx
200
247
  import { jsx as jsx3 } from "react/jsx-runtime";
201
248
  var AuthContext = createContext3(void 0);
249
+ var AuthProvider = ({ children }) => {
250
+ const supabase = useSupabase();
251
+ const [user, setUser] = useState(null);
252
+ const [profile, setProfile] = useState(null);
253
+ const [membership, setMembership] = useState(null);
254
+ const [session, setSession] = useState(null);
255
+ const [loading, setLoading] = useState(true);
256
+ const currentUserIdRef = useRef(null);
257
+ const fetchProfileAndMembership = useCallback(async (userId) => {
258
+ try {
259
+ const { data, error } = await supabase.rpc("get_user_avatar_and_profile", {
260
+ p_user_id: userId
261
+ });
262
+ if (error || !data) {
263
+ console.error("Error fetching user context via RPC:", error?.message);
264
+ setProfile(null);
265
+ setMembership(null);
266
+ return;
267
+ }
268
+ const response = data;
269
+ if (response?.profile) {
270
+ const profileData = response.profile;
271
+ if (profileData.avatar_path && !profileData.avatar_path.startsWith("http")) {
272
+ const cleanPath = profileData.avatar_path.replace(/^user-media\//, "");
273
+ const { data: avatarSignedData } = await supabase.storage.from("user-media").createSignedUrl(cleanPath, 3600);
274
+ if (avatarSignedData?.signedUrl) {
275
+ profileData.avatar_url = avatarSignedData.signedUrl;
276
+ }
277
+ }
278
+ if (profileData.cover_image_path && !profileData.cover_image_path.startsWith("http")) {
279
+ const cleanPath = profileData.cover_image_path.replace(/^user-media\//, "");
280
+ const { data: coverSignedData } = await supabase.storage.from("user-media").createSignedUrl(cleanPath, 3600);
281
+ if (coverSignedData?.signedUrl) {
282
+ profileData.cover_image_url = coverSignedData.signedUrl;
283
+ }
284
+ }
285
+ let updatedMembership = response.membership;
286
+ if (updatedMembership) {
287
+ const now = (/* @__PURE__ */ new Date()).toISOString();
288
+ const isFirstLogin = !updatedMembership.first_login_at;
289
+ const updateData = {
290
+ last_login_at: now,
291
+ ...isFirstLogin && { first_login_at: now }
292
+ };
293
+ const { error: updateError } = await supabase.from("memberships").update(updateData).eq("id", updatedMembership.id);
294
+ if (updateError) {
295
+ console.error("Error updating membership login timestamps:", updateError.message);
296
+ } else {
297
+ updatedMembership = {
298
+ ...updatedMembership,
299
+ ...updateData
300
+ };
301
+ }
302
+ }
303
+ setProfile(profileData);
304
+ setMembership(updatedMembership);
305
+ }
306
+ } catch (err) {
307
+ console.error("Unexpected error fetching user context:", err);
308
+ setProfile(null);
309
+ setMembership(null);
310
+ }
311
+ }, []);
312
+ const refreshProfile = async () => {
313
+ if (currentUserIdRef.current) {
314
+ await fetchProfileAndMembership(currentUserIdRef.current);
315
+ }
316
+ };
317
+ const signOut = useCallback(async () => {
318
+ await supabase.auth.signOut();
319
+ currentUserIdRef.current = null;
320
+ setUser(null);
321
+ setProfile(null);
322
+ setMembership(null);
323
+ setSession(null);
324
+ }, []);
325
+ const setActiveCompany = async (companyId) => {
326
+ if (!user) {
327
+ throw new Error("\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u043D\u0435 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u043E\u0432\u0430\u043D");
328
+ }
329
+ const { error: profileError } = await supabase.from("profiles").update({ active_company_id: companyId }).eq("id", user.id);
330
+ if (profileError) {
331
+ console.error("Error updating active company:", profileError);
332
+ throw new Error(profileError.message);
333
+ }
334
+ await refreshProfile();
335
+ };
336
+ const updateProfile = (newProfileData) => {
337
+ setProfile((prev) => prev ? { ...prev, ...newProfileData } : null);
338
+ };
339
+ useEffect(() => {
340
+ const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, currentSession) => {
341
+ if (event === "TOKEN_REFRESHED" && currentUserIdRef.current === currentSession?.user?.id) {
342
+ setSession(currentSession);
343
+ return;
344
+ }
345
+ const currentUser = currentSession?.user ?? null;
346
+ const newUserId = currentUser?.id ?? null;
347
+ if (newUserId !== currentUserIdRef.current) {
348
+ currentUserIdRef.current = newUserId;
349
+ setUser(currentUser);
350
+ if (newUserId) {
351
+ await trackUserSession(supabase, newUserId).catch(console.error);
352
+ const isAuthLinkEvent = event === "SIGNED_IN" || event === "INITIAL_SESSION" || event === "PASSWORD_RECOVERY";
353
+ if (!isAuthLinkEvent) {
354
+ const isValid = await isCurrentSessionValid(supabase, newUserId);
355
+ if (!isValid) {
356
+ await supabase.auth.signOut();
357
+ currentUserIdRef.current = null;
358
+ setUser(null);
359
+ setProfile(null);
360
+ setMembership(null);
361
+ setLoading(false);
362
+ return;
363
+ }
364
+ }
365
+ await fetchProfileAndMembership(newUserId);
366
+ setSession(currentSession);
367
+ } else {
368
+ setProfile(null);
369
+ setMembership(null);
370
+ }
371
+ }
372
+ setLoading(false);
373
+ });
374
+ return () => {
375
+ subscription.unsubscribe();
376
+ };
377
+ }, [fetchProfileAndMembership]);
378
+ useEffect(() => {
379
+ if (!user) return;
380
+ const checkSession = async () => {
381
+ try {
382
+ const valid = await isCurrentSessionValid(supabase, user.id);
383
+ if (!valid) {
384
+ console.warn("\u0421\u0435\u0441\u0456\u044E \u0432\u0456\u0434\u043A\u043B\u0438\u043A\u0430\u043D\u043E \u0437 \u0456\u043D\u0448\u043E\u0433\u043E \u043F\u0440\u0438\u0441\u0442\u0440\u043E\u044E.");
385
+ await signOut();
386
+ }
387
+ } catch (err) {
388
+ console.error("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u043F\u0440\u0438 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u0446\u0456 \u0441\u0435\u0441\u0456\u0457:", err);
389
+ }
390
+ };
391
+ const interval = setInterval(checkSession, 6e4);
392
+ const handleFocus = () => checkSession();
393
+ window.addEventListener("focus", handleFocus);
394
+ return () => {
395
+ clearInterval(interval);
396
+ window.removeEventListener("focus", handleFocus);
397
+ };
398
+ }, [user, signOut]);
399
+ const activeCompanyId = profile?.active_company_id ?? null;
400
+ const userRole = membership?.role ?? null;
401
+ return /* @__PURE__ */ jsx3(
402
+ AuthContext.Provider,
403
+ {
404
+ value: {
405
+ user,
406
+ profile,
407
+ membership,
408
+ userRole,
409
+ activeCompanyId,
410
+ session,
411
+ isAuthenticated: !!user,
412
+ loading,
413
+ signOut,
414
+ updateProfile,
415
+ refreshProfile,
416
+ setActiveCompany
417
+ },
418
+ children
419
+ }
420
+ );
421
+ };
202
422
  var useAuth = () => {
203
423
  const context = useContext3(AuthContext);
204
424
  if (!context) {
@@ -1389,9 +1609,73 @@ var useConfirmation = () => {
1389
1609
  return context.confirm;
1390
1610
  };
1391
1611
 
1612
+ // src/context/AppSettingsProvider.tsx
1613
+ import { createContext as createContext11, useContext as useContext11, useEffect as useEffect7, useState as useState10, useCallback as useCallback5 } from "react";
1614
+ import { jsx as jsx13 } from "react/jsx-runtime";
1615
+ var DEFAULT_SETTINGS = {
1616
+ max_group_members: 100
1617
+ };
1618
+ var AppSettingsContext = createContext11(void 0);
1619
+ var AppSettingsProvider = ({ children }) => {
1620
+ const supabase = useSupabase();
1621
+ const [settings, setSettings] = useState10(DEFAULT_SETTINGS);
1622
+ const [loading, setLoading] = useState10(true);
1623
+ const [error, setError] = useState10(null);
1624
+ const fetchSettings = useCallback5(async () => {
1625
+ try {
1626
+ setLoading(true);
1627
+ setError(null);
1628
+ const { data, error: supabaseError } = await supabase.from("app_settings").select("key, value");
1629
+ if (supabaseError) throw supabaseError;
1630
+ if (data) {
1631
+ const parsedSettings = data.reduce((acc, item) => {
1632
+ acc[item.key] = item.value;
1633
+ return acc;
1634
+ }, { ...DEFAULT_SETTINGS });
1635
+ setSettings(parsedSettings);
1636
+ }
1637
+ } catch (err) {
1638
+ console.error("\u041E\u0448\u0438\u0431\u043A\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u044B\u0445 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043A:", err.message || err);
1639
+ setError(err.message || "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F");
1640
+ } finally {
1641
+ setLoading(false);
1642
+ }
1643
+ }, []);
1644
+ useEffect7(() => {
1645
+ fetchSettings();
1646
+ }, [fetchSettings]);
1647
+ const getSetting = useCallback5((key, defaultValue) => {
1648
+ if (key in settings && settings[key] !== null && settings[key] !== void 0) {
1649
+ return settings[key];
1650
+ }
1651
+ return defaultValue;
1652
+ }, [settings]);
1653
+ return /* @__PURE__ */ jsx13(
1654
+ AppSettingsContext.Provider,
1655
+ {
1656
+ value: {
1657
+ settings,
1658
+ loading,
1659
+ error,
1660
+ getSetting,
1661
+ refetchSettings: fetchSettings
1662
+ },
1663
+ children
1664
+ }
1665
+ );
1666
+ };
1667
+ var useAppSettings = () => {
1668
+ const context = useContext11(AppSettingsContext);
1669
+ if (!context) {
1670
+ throw new Error("useAppSettings should be used within the AppSettingsProvider");
1671
+ }
1672
+ return context;
1673
+ };
1674
+
1392
1675
  // src/context/index.ts
1393
1676
  var Providers = {
1394
1677
  Supabase: SupabaseProvider,
1678
+ AppSettings: AppSettingsProvider,
1395
1679
  Translate: TranslateProvider,
1396
1680
  TranslationEdit: TranslationEditProvider,
1397
1681
  Localization: LocalizationProvider,
@@ -1403,26 +1687,26 @@ var Providers = {
1403
1687
  };
1404
1688
 
1405
1689
  // src/UI/components/data.display/UserStatusChipComponent.tsx
1406
- import { jsx as jsx13 } from "react/jsx-runtime";
1690
+ import { jsx as jsx14 } from "react/jsx-runtime";
1407
1691
  var UserStatusChipComponent = ({ overrideNamespace, state }) => {
1408
1692
  const confirm = useConfirmation();
1409
1693
  const handleShowReason = async (e) => {
1410
1694
  e.stopPropagation();
1411
1695
  if (!state.locked_reason) return;
1412
1696
  await confirm({
1413
- title: /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Lock Reason" }),
1697
+ title: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Lock Reason" }),
1414
1698
  message: state.locked_reason,
1415
1699
  type: "info",
1416
- confirmText: /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "OK" }),
1700
+ confirmText: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "OK" }),
1417
1701
  showNoButton: false,
1418
1702
  showCancelButton: false
1419
1703
  });
1420
1704
  };
1421
1705
  if (state.profile_archived) {
1422
- return /* @__PURE__ */ jsx13(
1706
+ return /* @__PURE__ */ jsx14(
1423
1707
  Chip,
1424
1708
  {
1425
- label: /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Archived" }),
1709
+ label: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Archived" }),
1426
1710
  color: "default",
1427
1711
  size: "small",
1428
1712
  variant: "filled"
@@ -1430,10 +1714,10 @@ var UserStatusChipComponent = ({ overrideNamespace, state }) => {
1430
1714
  );
1431
1715
  }
1432
1716
  if (state.profile_locked) {
1433
- return /* @__PURE__ */ jsx13(
1717
+ return /* @__PURE__ */ jsx14(
1434
1718
  Chip,
1435
1719
  {
1436
- label: /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "System Locked" }),
1720
+ label: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "System Locked" }),
1437
1721
  color: "error",
1438
1722
  size: "small",
1439
1723
  variant: "filled"
@@ -1441,30 +1725,30 @@ var UserStatusChipComponent = ({ overrideNamespace, state }) => {
1441
1725
  );
1442
1726
  }
1443
1727
  if (state.excluded) {
1444
- return /* @__PURE__ */ jsx13(
1728
+ return /* @__PURE__ */ jsx14(
1445
1729
  Chip,
1446
1730
  {
1447
- label: /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Excluded" }),
1731
+ label: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Excluded" }),
1448
1732
  size: "small"
1449
1733
  }
1450
1734
  );
1451
1735
  }
1452
1736
  if (state.locked) {
1453
- return /* @__PURE__ */ jsx13(
1737
+ return /* @__PURE__ */ jsx14(
1454
1738
  Chip,
1455
1739
  {
1456
- label: /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Locked" }),
1740
+ label: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Locked" }),
1457
1741
  color: "error",
1458
1742
  size: "small",
1459
1743
  onDelete: state.locked_reason ? handleShowReason : void 0,
1460
- deleteIcon: state.locked_reason ? /* @__PURE__ */ jsx13(IconButton2, { size: "small", component: "span", sx: { p: 0.2 }, children: /* @__PURE__ */ jsx13(InfoOutlinedIcon, { fontSize: "small" }) }) : void 0
1744
+ deleteIcon: state.locked_reason ? /* @__PURE__ */ jsx14(IconButton2, { size: "small", component: "span", sx: { p: 0.2 }, children: /* @__PURE__ */ jsx14(InfoOutlinedIcon, { fontSize: "small" }) }) : void 0
1461
1745
  }
1462
1746
  );
1463
1747
  }
1464
- return /* @__PURE__ */ jsx13(
1748
+ return /* @__PURE__ */ jsx14(
1465
1749
  Chip,
1466
1750
  {
1467
- label: /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Active" }),
1751
+ label: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Active" }),
1468
1752
  color: "success",
1469
1753
  size: "small",
1470
1754
  variant: "outlined"
@@ -1474,32 +1758,32 @@ var UserStatusChipComponent = ({ overrideNamespace, state }) => {
1474
1758
 
1475
1759
  // src/UI/components/data.display/UserRoleChipComponent.tsx
1476
1760
  import { Chip as Chip2 } from "@mui/material";
1477
- import { jsx as jsx14 } from "react/jsx-runtime";
1761
+ import { jsx as jsx15 } from "react/jsx-runtime";
1478
1762
  var UserRoleChipComponent = ({ overrideNamespace, role }) => {
1479
1763
  switch (role) {
1480
1764
  case "superadmin":
1481
- return /* @__PURE__ */ jsx14(
1765
+ return /* @__PURE__ */ jsx15(
1482
1766
  Chip2,
1483
1767
  {
1484
- label: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Superadministrator" }),
1768
+ label: /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Superadministrator" }),
1485
1769
  color: "error",
1486
1770
  size: "small"
1487
1771
  }
1488
1772
  );
1489
1773
  case "admin":
1490
- return /* @__PURE__ */ jsx14(
1774
+ return /* @__PURE__ */ jsx15(
1491
1775
  Chip2,
1492
1776
  {
1493
- label: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Administrator" }),
1777
+ label: /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "Administrator" }),
1494
1778
  color: "primary",
1495
1779
  size: "small"
1496
1780
  }
1497
1781
  );
1498
1782
  default:
1499
- return /* @__PURE__ */ jsx14(
1783
+ return /* @__PURE__ */ jsx15(
1500
1784
  Chip2,
1501
1785
  {
1502
- label: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "User" }),
1786
+ label: /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace: overrideNamespace || "system_widgets", children: "User" }),
1503
1787
  variant: "outlined",
1504
1788
  size: "small"
1505
1789
  }
@@ -1508,14 +1792,14 @@ var UserRoleChipComponent = ({ overrideNamespace, role }) => {
1508
1792
  };
1509
1793
 
1510
1794
  // src/UI/components/buttons/CopyClipboardButtonComponent.tsx
1511
- import { useState as useState10 } from "react";
1795
+ import { useState as useState11 } from "react";
1512
1796
  import { IconButton as IconButton3 } from "@mui/material";
1513
1797
  import CheckIcon from "@mui/icons-material/Check";
1514
1798
  import CopyIcon from "@mui/icons-material/ContentCopy";
1515
1799
 
1516
1800
  // src/UI/components/data.display/TranslatableTooltipComponent.tsx
1517
1801
  import { Tooltip as Tooltip2 } from "@mui/material";
1518
- import { jsx as jsx15 } from "react/jsx-runtime";
1802
+ import { jsx as jsx16 } from "react/jsx-runtime";
1519
1803
  var TranslatableTooltipComponent = ({
1520
1804
  overrideNamespace,
1521
1805
  title,
@@ -1524,10 +1808,10 @@ var TranslatableTooltipComponent = ({
1524
1808
  ...props
1525
1809
  }) => {
1526
1810
  const { isTranslationMode } = useTranslationEdit();
1527
- return /* @__PURE__ */ jsx15(
1811
+ return /* @__PURE__ */ jsx16(
1528
1812
  Tooltip2,
1529
1813
  {
1530
- title: typeof title === "string" ? /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace, children: title }) : title,
1814
+ title: typeof title === "string" ? /* @__PURE__ */ jsx16(TranslateText, { overrideNamespace, children: title }) : title,
1531
1815
  slotProps: {
1532
1816
  popper: {
1533
1817
  sx: isTranslationMode ? {
@@ -1541,13 +1825,13 @@ var TranslatableTooltipComponent = ({
1541
1825
  },
1542
1826
  leaveDelay: isTranslationMode ? 1e3 : 100,
1543
1827
  ...props,
1544
- children: disableSpan ? children : /* @__PURE__ */ jsx15("span", { children })
1828
+ children: disableSpan ? children : /* @__PURE__ */ jsx16("span", { children })
1545
1829
  }
1546
1830
  );
1547
1831
  };
1548
1832
 
1549
1833
  // src/UI/components/buttons/CopyClipboardButtonComponent.tsx
1550
- import { jsx as jsx16 } from "react/jsx-runtime";
1834
+ import { jsx as jsx17 } from "react/jsx-runtime";
1551
1835
  var CopyClipboardButtonComponent = ({
1552
1836
  overrideNamespace,
1553
1837
  textToCopy,
@@ -1560,7 +1844,7 @@ var CopyClipboardButtonComponent = ({
1560
1844
  sx,
1561
1845
  ...iconButtonProps
1562
1846
  }) => {
1563
- const [copied, setCopied] = useState10(false);
1847
+ const [copied, setCopied] = useState11(false);
1564
1848
  const handleCopy = async (e) => {
1565
1849
  e.stopPropagation();
1566
1850
  if (!textToCopy) return;
@@ -1577,7 +1861,7 @@ var CopyClipboardButtonComponent = ({
1577
1861
  console.error("Failed to copy text to clipboard:", error);
1578
1862
  }
1579
1863
  };
1580
- return /* @__PURE__ */ jsx16(TranslatableTooltipComponent, { title: copied ? copiedTooltipText : copyTooltipText, children: /* @__PURE__ */ jsx16("span", { children: /* @__PURE__ */ jsx16(
1864
+ return /* @__PURE__ */ jsx17(TranslatableTooltipComponent, { title: copied ? copiedTooltipText : copyTooltipText, children: /* @__PURE__ */ jsx17("span", { children: /* @__PURE__ */ jsx17(
1581
1865
  IconButton3,
1582
1866
  {
1583
1867
  size,
@@ -1585,17 +1869,17 @@ var CopyClipboardButtonComponent = ({
1585
1869
  disabled: !textToCopy || iconButtonProps.disabled,
1586
1870
  sx: { p: 0.25, ...sx },
1587
1871
  ...iconButtonProps,
1588
- children: copied ? /* @__PURE__ */ jsx16(CheckIcon, { fontSize: size === "large" ? "medium" : "small", color: "success" }) : /* @__PURE__ */ jsx16(CopyIcon, { fontSize: size === "large" ? "medium" : "small" })
1872
+ children: copied ? /* @__PURE__ */ jsx17(CheckIcon, { fontSize: size === "large" ? "medium" : "small", color: "success" }) : /* @__PURE__ */ jsx17(CopyIcon, { fontSize: size === "large" ? "medium" : "small" })
1589
1873
  }
1590
1874
  ) }) });
1591
1875
  };
1592
1876
 
1593
1877
  // src/context/UserSettingsProvider.tsx
1594
- import { createContext as createContext11, useContext as useContext11, useEffect as useEffect7, useState as useState11, useCallback as useCallback5 } from "react";
1595
- import { jsx as jsx17 } from "react/jsx-runtime";
1596
- var UserSettingsContext = createContext11(void 0);
1878
+ import { createContext as createContext12, useContext as useContext12, useEffect as useEffect8, useState as useState12, useCallback as useCallback6 } from "react";
1879
+ import { jsx as jsx18 } from "react/jsx-runtime";
1880
+ var UserSettingsContext = createContext12(void 0);
1597
1881
  var useUserSettings = () => {
1598
- const context = useContext11(UserSettingsContext);
1882
+ const context = useContext12(UserSettingsContext);
1599
1883
  if (!context) {
1600
1884
  throw new Error("useUserSettings should be used within the UserSettingsProvider");
1601
1885
  }
@@ -1603,11 +1887,11 @@ var useUserSettings = () => {
1603
1887
  };
1604
1888
 
1605
1889
  // src/UI/components/data.display/UserPopoverComponent.tsx
1606
- import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs6 } from "react/jsx-runtime";
1890
+ import { Fragment as Fragment2, jsx as jsx19, jsxs as jsxs6 } from "react/jsx-runtime";
1607
1891
  var useUserStatus = (supabase, userId, open) => {
1608
- const [lastSeenAt, setLastSeenAt] = useState12(null);
1609
- const [loading, setLoading] = useState12(true);
1610
- useEffect8(() => {
1892
+ const [lastSeenAt, setLastSeenAt] = useState13(null);
1893
+ const [loading, setLoading] = useState13(true);
1894
+ useEffect9(() => {
1611
1895
  if (!userId || !open) {
1612
1896
  setLastSeenAt(null);
1613
1897
  setLoading(false);
@@ -1656,13 +1940,13 @@ var UserPopoverComponent = ({
1656
1940
  const { activeCompanyId, membership: currentMembership } = useAuth();
1657
1941
  const { openChatWithUser } = useUserSettings();
1658
1942
  const { formatDate, formatRelativeTime } = useLocalization();
1659
- const [profileData, setProfileData] = useState12(null);
1660
- const [membershipData, setMembershipData] = useState12(null);
1661
- const [avatarUrl, setAvatarUrl] = useState12(null);
1662
- const [coverUrl, setCoverUrl] = useState12(null);
1663
- const [loading, setLoading] = useState12(true);
1943
+ const [profileData, setProfileData] = useState13(null);
1944
+ const [membershipData, setMembershipData] = useState13(null);
1945
+ const [avatarUrl, setAvatarUrl] = useState13(null);
1946
+ const [coverUrl, setCoverUrl] = useState13(null);
1947
+ const [loading, setLoading] = useState13(true);
1664
1948
  const { lastSeenAt, isOnline } = useUserStatus(supabase, userId, open);
1665
- useEffect8(() => {
1949
+ useEffect9(() => {
1666
1950
  if (!open || !userId || !activeCompanyId) return;
1667
1951
  let isMounted = true;
1668
1952
  setLoading(true);
@@ -1708,7 +1992,7 @@ var UserPopoverComponent = ({
1708
1992
  }, [open, userId, currentMembership?.id, activeCompanyId]);
1709
1993
  const getStatusChip = () => {
1710
1994
  if (!profileData) return null;
1711
- return /* @__PURE__ */ jsx18(UserStatusChipComponent, { state: { profile_archived: profileData.archived, profile_locked: profileData.locked, excluded: membershipData?.excluded || false, locked: membershipData?.locked || false, locked_reason: membershipData?.locked_reason || "" } });
1995
+ return /* @__PURE__ */ jsx19(UserStatusChipComponent, { state: { profile_archived: profileData.archived, profile_locked: profileData.locked, excluded: membershipData?.excluded || false, locked: membershipData?.locked || false, locked_reason: membershipData?.locked_reason || "" } });
1712
1996
  };
1713
1997
  const getStatusTypographyColor = (isOnline2, lastSeenAt2) => {
1714
1998
  if (isOnline2) return "success";
@@ -1729,7 +2013,7 @@ var UserPopoverComponent = ({
1729
2013
  return "inherit";
1730
2014
  };
1731
2015
  const canChat = currentMembership && membershipData && currentMembership.id !== membershipData.id;
1732
- return /* @__PURE__ */ jsx18(
2016
+ return /* @__PURE__ */ jsx19(
1733
2017
  Popover,
1734
2018
  {
1735
2019
  open,
@@ -1748,7 +2032,7 @@ var UserPopoverComponent = ({
1748
2032
  }
1749
2033
  }
1750
2034
  },
1751
- children: loading ? /* @__PURE__ */ jsx18(Box4, { sx: { display: "flex", justifyContent: "center", py: 4 }, children: /* @__PURE__ */ jsx18(CircularProgress2, { size: 28 }) }) : profileData ? /* @__PURE__ */ jsxs6(Box4, { sx: { display: "flex", flexDirection: "column" }, children: [
2035
+ children: loading ? /* @__PURE__ */ jsx19(Box4, { sx: { display: "flex", justifyContent: "center", py: 4 }, children: /* @__PURE__ */ jsx19(CircularProgress2, { size: 28 }) }) : profileData ? /* @__PURE__ */ jsxs6(Box4, { sx: { display: "flex", flexDirection: "column" }, children: [
1752
2036
  /* @__PURE__ */ jsxs6(
1753
2037
  Box4,
1754
2038
  {
@@ -1759,7 +2043,7 @@ var UserPopoverComponent = ({
1759
2043
  bgcolor: "action.selected"
1760
2044
  },
1761
2045
  children: [
1762
- coverUrl && /* @__PURE__ */ jsx18(
2046
+ coverUrl && /* @__PURE__ */ jsx19(
1763
2047
  Box4,
1764
2048
  {
1765
2049
  component: "img",
@@ -1775,7 +2059,7 @@ var UserPopoverComponent = ({
1775
2059
  }
1776
2060
  }
1777
2061
  ),
1778
- /* @__PURE__ */ jsx18(
2062
+ /* @__PURE__ */ jsx19(
1779
2063
  IconButton4,
1780
2064
  {
1781
2065
  size: "small",
@@ -1793,7 +2077,7 @@ var UserPopoverComponent = ({
1793
2077
  transform: "scale(1.1)"
1794
2078
  }
1795
2079
  },
1796
- children: /* @__PURE__ */ jsx18(CloseIcon, { fontSize: "small" })
2080
+ children: /* @__PURE__ */ jsx19(CloseIcon, { fontSize: "small" })
1797
2081
  }
1798
2082
  )
1799
2083
  ]
@@ -1801,7 +2085,7 @@ var UserPopoverComponent = ({
1801
2085
  ),
1802
2086
  /* @__PURE__ */ jsxs6(Box4, { sx: { p: 2, pt: 0 }, children: [
1803
2087
  /* @__PURE__ */ jsxs6(Stack, { direction: "row", spacing: 1.5, sx: { alignItems: "flex-end", mt: "-18px", mb: 1 }, children: [
1804
- /* @__PURE__ */ jsx18(
2088
+ /* @__PURE__ */ jsx19(
1805
2089
  Badge,
1806
2090
  {
1807
2091
  overlap: "circular",
@@ -1838,7 +2122,7 @@ var UserPopoverComponent = ({
1838
2122
  }
1839
2123
  }
1840
2124
  },
1841
- children: /* @__PURE__ */ jsx18(
2125
+ children: /* @__PURE__ */ jsx19(
1842
2126
  Avatar,
1843
2127
  {
1844
2128
  src: avatarUrl || coverUrl || void 0,
@@ -1858,52 +2142,52 @@ var UserPopoverComponent = ({
1858
2142
  }
1859
2143
  ),
1860
2144
  /* @__PURE__ */ jsxs6(Box4, { sx: { overflow: "hidden", pb: 0.5 }, children: [
1861
- /* @__PURE__ */ jsx18(Typography2, { variant: "subtitle1", sx: { fontWeight: 600, lineHeight: 1.2 }, noWrap: true, children: profileData.display_name || `${profileData.first_name || ""} ${profileData.last_name || ""}` }),
1862
- membershipData?.employee_post && /* @__PURE__ */ jsx18(Typography2, { variant: "body2", color: "text.secondary", noWrap: true, children: membershipData.employee_post })
2145
+ /* @__PURE__ */ jsx19(Typography2, { variant: "subtitle1", sx: { fontWeight: 600, lineHeight: 1.2 }, noWrap: true, children: profileData.display_name || `${profileData.first_name || ""} ${profileData.last_name || ""}` }),
2146
+ membershipData?.employee_post && /* @__PURE__ */ jsx19(Typography2, { variant: "body2", color: "text.secondary", noWrap: true, children: membershipData.employee_post })
1863
2147
  ] })
1864
2148
  ] }),
1865
2149
  /* @__PURE__ */ jsxs6(Stack, { direction: "row", spacing: 1, sx: { my: 1, flexWrap: "wrap", gap: 0.5 }, children: [
1866
2150
  getStatusChip(),
1867
- /* @__PURE__ */ jsx18(UserRoleChipComponent, { role: membershipData?.role || "user" })
2151
+ /* @__PURE__ */ jsx19(UserRoleChipComponent, { role: membershipData?.role || "user" })
1868
2152
  ] }),
1869
- /* @__PURE__ */ jsx18(Divider, { sx: { my: 1.5 } }),
2153
+ /* @__PURE__ */ jsx19(Divider, { sx: { my: 1.5 } }),
1870
2154
  /* @__PURE__ */ jsxs6(Stack, { spacing: 1, sx: { fontSize: "0.875rem", mb: 1.5 }, children: [
1871
2155
  /* @__PURE__ */ jsxs6(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
1872
- /* @__PURE__ */ jsx18(AccessTimeIcon, { fontSize: "small", color: getStatusIconColor(isOnline, lastSeenAt) }),
1873
- /* @__PURE__ */ jsx18(Typography2, { variant: "body2", color: getStatusTypographyColor(isOnline, lastSeenAt), children: isOnline ? /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Online" }) : lastSeenAt ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
1874
- /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Last seen" }),
2156
+ /* @__PURE__ */ jsx19(AccessTimeIcon, { fontSize: "small", color: getStatusIconColor(isOnline, lastSeenAt) }),
2157
+ /* @__PURE__ */ jsx19(Typography2, { variant: "body2", color: getStatusTypographyColor(isOnline, lastSeenAt), children: isOnline ? /* @__PURE__ */ jsx19(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Online" }) : lastSeenAt ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
2158
+ /* @__PURE__ */ jsx19(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Last seen" }),
1875
2159
  ":",
1876
2160
  " ",
1877
- /* @__PURE__ */ jsx18("strong", { children: formatRelativeTime(lastSeenAt) })
1878
- ] }) : /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Offline" }) })
2161
+ /* @__PURE__ */ jsx19("strong", { children: formatRelativeTime(lastSeenAt) })
2162
+ ] }) : /* @__PURE__ */ jsx19(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Offline" }) })
1879
2163
  ] }),
1880
2164
  profileData.email && /* @__PURE__ */ jsxs6(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
1881
- /* @__PURE__ */ jsx18(EmailIcon, { fontSize: "small" }),
1882
- /* @__PURE__ */ jsx18(Typography2, { variant: "body2", color: "text.primary", noWrap: true, sx: { flexGrow: 1 }, children: profileData.email }),
1883
- /* @__PURE__ */ jsx18(CopyClipboardButtonComponent, { textToCopy: profileData.email })
2165
+ /* @__PURE__ */ jsx19(EmailIcon, { fontSize: "small" }),
2166
+ /* @__PURE__ */ jsx19(Typography2, { variant: "body2", color: "text.primary", noWrap: true, sx: { flexGrow: 1 }, children: profileData.email }),
2167
+ /* @__PURE__ */ jsx19(CopyClipboardButtonComponent, { textToCopy: profileData.email })
1884
2168
  ] }),
1885
2169
  membershipData?.employee_post && /* @__PURE__ */ jsxs6(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
1886
- /* @__PURE__ */ jsx18(WorkIcon, { fontSize: "small" }),
1887
- /* @__PURE__ */ jsx18(Typography2, { variant: "body2", color: "text.primary", noWrap: true, sx: { flexGrow: 1 }, children: membershipData.employee_post }),
1888
- /* @__PURE__ */ jsx18(CopyClipboardButtonComponent, { textToCopy: membershipData.employee_post })
2170
+ /* @__PURE__ */ jsx19(WorkIcon, { fontSize: "small" }),
2171
+ /* @__PURE__ */ jsx19(Typography2, { variant: "body2", color: "text.primary", noWrap: true, sx: { flexGrow: 1 }, children: membershipData.employee_post }),
2172
+ /* @__PURE__ */ jsx19(CopyClipboardButtonComponent, { textToCopy: membershipData.employee_post })
1889
2173
  ] }),
1890
2174
  profileData.phone && /* @__PURE__ */ jsxs6(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
1891
- /* @__PURE__ */ jsx18(PhoneIcon, { fontSize: "small" }),
1892
- /* @__PURE__ */ jsx18(Typography2, { variant: "body2", color: "text.primary", children: profileData.phone })
2175
+ /* @__PURE__ */ jsx19(PhoneIcon, { fontSize: "small" }),
2176
+ /* @__PURE__ */ jsx19(Typography2, { variant: "body2", color: "text.primary", children: profileData.phone })
1893
2177
  ] }),
1894
2178
  profileData.birthday && /* @__PURE__ */ jsxs6(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
1895
- /* @__PURE__ */ jsx18(CakeIcon, { fontSize: "small" }),
1896
- /* @__PURE__ */ jsx18(Typography2, { variant: "body2", color: "text.primary", children: formatDate(profileData.birthday) })
2179
+ /* @__PURE__ */ jsx19(CakeIcon, { fontSize: "small" }),
2180
+ /* @__PURE__ */ jsx19(Typography2, { variant: "body2", color: "text.primary", children: formatDate(profileData.birthday) })
1897
2181
  ] }),
1898
2182
  membershipData?.created_at && /* @__PURE__ */ jsxs6(Stack, { direction: "row", spacing: 1, sx: { alignItems: "center" }, color: "text.secondary", children: [
1899
- /* @__PURE__ */ jsx18(CalendarIcon, { fontSize: "small" }),
2183
+ /* @__PURE__ */ jsx19(CalendarIcon, { fontSize: "small" }),
1900
2184
  /* @__PURE__ */ jsxs6(Typography2, { variant: "body2", color: "text.primary", children: [
1901
- /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "In company from" }),
2185
+ /* @__PURE__ */ jsx19(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "In company from" }),
1902
2186
  ": ",
1903
2187
  formatDate(membershipData.created_at)
1904
2188
  ] })
1905
2189
  ] }),
1906
- profileData.description && /* @__PURE__ */ jsx18(
2190
+ profileData.description && /* @__PURE__ */ jsx19(
1907
2191
  Typography2,
1908
2192
  {
1909
2193
  variant: "caption",
@@ -1919,28 +2203,28 @@ var UserPopoverComponent = ({
1919
2203
  }
1920
2204
  )
1921
2205
  ] }),
1922
- /* @__PURE__ */ jsx18(Divider, { sx: { my: 1 } }),
2206
+ /* @__PURE__ */ jsx19(Divider, { sx: { my: 1 } }),
1923
2207
  /* @__PURE__ */ jsxs6(Stack, { direction: "row", spacing: 1, sx: { justifyContent: "space-around", pt: 0.5 }, children: [
1924
- /* @__PURE__ */ jsx18(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Send a notification" }), children: /* @__PURE__ */ jsx18(IconButton4, { size: "small", color: "primary", children: /* @__PURE__ */ jsx18(NotificationIcon, { fontSize: "small" }) }) }),
1925
- /* @__PURE__ */ jsx18(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Set a task" }), children: /* @__PURE__ */ jsx18(IconButton4, { size: "small", color: "primary", children: /* @__PURE__ */ jsx18(TaskIcon, { fontSize: "small" }) }) }),
1926
- /* @__PURE__ */ jsx18(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Start a chat" }), children: /* @__PURE__ */ jsx18(
2208
+ /* @__PURE__ */ jsx19(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx19(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Send a notification" }), children: /* @__PURE__ */ jsx19(IconButton4, { size: "small", color: "primary", children: /* @__PURE__ */ jsx19(NotificationIcon, { fontSize: "small" }) }) }),
2209
+ /* @__PURE__ */ jsx19(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx19(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Set a task" }), children: /* @__PURE__ */ jsx19(IconButton4, { size: "small", color: "primary", children: /* @__PURE__ */ jsx19(TaskIcon, { fontSize: "small" }) }) }),
2210
+ /* @__PURE__ */ jsx19(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx19(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Start a chat" }), children: /* @__PURE__ */ jsx19(
1927
2211
  IconButton4,
1928
2212
  {
1929
2213
  size: "small",
1930
2214
  color: "primary",
1931
2215
  disabled: !canChat,
1932
2216
  onClick: () => membershipData && openChatWithUser(membershipData.id),
1933
- children: /* @__PURE__ */ jsx18(ChatIcon, { fontSize: "small" })
2217
+ children: /* @__PURE__ */ jsx19(ChatIcon, { fontSize: "small" })
1934
2218
  }
1935
2219
  ) })
1936
2220
  ] })
1937
2221
  ] })
1938
- ] }) : /* @__PURE__ */ jsx18(Box4, { sx: { p: 2 }, children: /* @__PURE__ */ jsx18(
2222
+ ] }) : /* @__PURE__ */ jsx19(Box4, { sx: { p: 2 }, children: /* @__PURE__ */ jsx19(
1939
2223
  Typography2,
1940
2224
  {
1941
2225
  color: "error",
1942
2226
  variant: "body2",
1943
- children: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Failed to load user data" })
2227
+ children: /* @__PURE__ */ jsx19(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Failed to load user data" })
1944
2228
  }
1945
2229
  ) })
1946
2230
  }
@@ -1951,6 +2235,8 @@ var UserPopoverComponent_default = UserPopoverComponent;
1951
2235
  export {
1952
2236
  SupabaseProvider,
1953
2237
  useSupabase,
2238
+ AuthProvider,
2239
+ useAuth,
1954
2240
  TranslationEditProvider,
1955
2241
  useTranslationEdit,
1956
2242
  translationService,
@@ -1971,6 +2257,8 @@ export {
1971
2257
  useToast,
1972
2258
  ConfirmationProvider,
1973
2259
  useConfirmation,
2260
+ AppSettingsProvider,
2261
+ useAppSettings,
1974
2262
  Providers,
1975
2263
  UserStatusChipComponent,
1976
2264
  UserRoleChipComponent,