@serhii.olishevskyi/docs 1.1.8 → 1.1.9
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.d.mts
CHANGED
|
@@ -571,10 +571,17 @@ declare const Services: {
|
|
|
571
571
|
};
|
|
572
572
|
};
|
|
573
573
|
|
|
574
|
+
type UserStatusType = 'online' | 'away' | 'offline';
|
|
575
|
+
|
|
574
576
|
declare function useDebounce<T>(value: T, delay?: number): T;
|
|
575
577
|
|
|
576
578
|
declare const Hooks: {
|
|
577
579
|
readonly useDebounce: typeof useDebounce;
|
|
580
|
+
readonly useUserStatus: (userId?: string, initialLastSeenAt?: string | null, currentAuthUserId?: string) => {
|
|
581
|
+
status: UserStatusType;
|
|
582
|
+
isOnline: boolean;
|
|
583
|
+
lastSeen: string | null;
|
|
584
|
+
};
|
|
578
585
|
};
|
|
579
586
|
|
|
580
587
|
export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps, type ExpandableNoteComponentProps, Hooks, type Language, LocalizationProvider, type MyAvatarComponentProps, type NumberInputComponentProps, Providers, type SearchComponentProps, type SelectComponentProps, type SelectOption, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps, type UserGroupedSessions, type UserPopoverComponentProps, type UserRoleChipComponentProps, type UserSessionItem, UserSettingsProvider, type UserStatusChipComponentProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
|
package/dist/index.d.ts
CHANGED
|
@@ -571,10 +571,17 @@ declare const Services: {
|
|
|
571
571
|
};
|
|
572
572
|
};
|
|
573
573
|
|
|
574
|
+
type UserStatusType = 'online' | 'away' | 'offline';
|
|
575
|
+
|
|
574
576
|
declare function useDebounce<T>(value: T, delay?: number): T;
|
|
575
577
|
|
|
576
578
|
declare const Hooks: {
|
|
577
579
|
readonly useDebounce: typeof useDebounce;
|
|
580
|
+
readonly useUserStatus: (userId?: string, initialLastSeenAt?: string | null, currentAuthUserId?: string) => {
|
|
581
|
+
status: UserStatusType;
|
|
582
|
+
isOnline: boolean;
|
|
583
|
+
lastSeen: string | null;
|
|
584
|
+
};
|
|
578
585
|
};
|
|
579
586
|
|
|
580
587
|
export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps, type ExpandableNoteComponentProps, Hooks, type Language, LocalizationProvider, type MyAvatarComponentProps, type NumberInputComponentProps, Providers, type SearchComponentProps, type SelectComponentProps, type SelectOption, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps, type UserGroupedSessions, type UserPopoverComponentProps, type UserRoleChipComponentProps, type UserSessionItem, UserSettingsProvider, type UserStatusChipComponentProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
|
package/dist/index.js
CHANGED
|
@@ -4427,9 +4427,101 @@ var Services = {
|
|
|
4427
4427
|
}
|
|
4428
4428
|
};
|
|
4429
4429
|
|
|
4430
|
+
// src/hooks/useUserStatus.ts
|
|
4431
|
+
var import_react28 = require("react");
|
|
4432
|
+
init_deviceId();
|
|
4433
|
+
init_context();
|
|
4434
|
+
var ONLINE_THRESHOLD_MINUTES = 2;
|
|
4435
|
+
var AWAY_THRESHOLD_MINUTES = 15;
|
|
4436
|
+
var useUserStatus2 = (userId, initialLastSeenAt, currentAuthUserId) => {
|
|
4437
|
+
const supabase = useSupabase();
|
|
4438
|
+
const [status, setStatus] = (0, import_react28.useState)("offline");
|
|
4439
|
+
const [lastSeen, setLastSeen] = (0, import_react28.useState)(initialLastSeenAt ?? null);
|
|
4440
|
+
const lastSeenRef = (0, import_react28.useRef)(initialLastSeenAt ?? null);
|
|
4441
|
+
lastSeenRef.current = lastSeen;
|
|
4442
|
+
const calculateStatus = (isOnline, lastSeenIso) => {
|
|
4443
|
+
if (isOnline) return "online";
|
|
4444
|
+
if (!lastSeenIso) return "offline";
|
|
4445
|
+
const lastSeenTime = new Date(lastSeenIso).getTime();
|
|
4446
|
+
if (isNaN(lastSeenTime)) return "offline";
|
|
4447
|
+
const diffInMinutes = (Date.now() - lastSeenTime) / (1e3 * 60);
|
|
4448
|
+
if (diffInMinutes >= 0 && diffInMinutes <= ONLINE_THRESHOLD_MINUTES) {
|
|
4449
|
+
return "online";
|
|
4450
|
+
}
|
|
4451
|
+
if (diffInMinutes > ONLINE_THRESHOLD_MINUTES && diffInMinutes <= AWAY_THRESHOLD_MINUTES) {
|
|
4452
|
+
return "away";
|
|
4453
|
+
}
|
|
4454
|
+
return "offline";
|
|
4455
|
+
};
|
|
4456
|
+
(0, import_react28.useEffect)(() => {
|
|
4457
|
+
if (!userId) return;
|
|
4458
|
+
let isMounted = true;
|
|
4459
|
+
const isSelf = currentAuthUserId && userId === currentAuthUserId;
|
|
4460
|
+
const fetchLastSeen = async () => {
|
|
4461
|
+
if (initialLastSeenAt !== void 0) return;
|
|
4462
|
+
let query = supabase.from("user_sessions").select("last_seen_at").eq("user_id", userId);
|
|
4463
|
+
if (isSelf) {
|
|
4464
|
+
query = query.eq("device_id", getDeviceId());
|
|
4465
|
+
} else {
|
|
4466
|
+
query = query.order("last_seen_at", { ascending: false });
|
|
4467
|
+
}
|
|
4468
|
+
const { data, error } = await query.limit(1).maybeSingle();
|
|
4469
|
+
if (error) {
|
|
4470
|
+
console.warn(`[useUserStatus] Error fetching session for ${userId}:`, error.message);
|
|
4471
|
+
return;
|
|
4472
|
+
}
|
|
4473
|
+
if (data && isMounted) {
|
|
4474
|
+
setLastSeen(data.last_seen_at);
|
|
4475
|
+
setStatus(calculateStatus(false, data.last_seen_at));
|
|
4476
|
+
}
|
|
4477
|
+
};
|
|
4478
|
+
fetchLastSeen();
|
|
4479
|
+
const channel = supabase.channel(`presence_user_${userId}`);
|
|
4480
|
+
channel.on("presence", { event: "sync" }, () => {
|
|
4481
|
+
const state = channel.presenceState();
|
|
4482
|
+
const isOnline = Object.keys(state).length > 0;
|
|
4483
|
+
if (isMounted) {
|
|
4484
|
+
setStatus(isOnline ? "online" : calculateStatus(false, lastSeenRef.current));
|
|
4485
|
+
}
|
|
4486
|
+
}).on("presence", { event: "join" }, () => {
|
|
4487
|
+
if (isMounted) setStatus("online");
|
|
4488
|
+
}).on("presence", { event: "leave" }, () => {
|
|
4489
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
4490
|
+
if (isMounted) {
|
|
4491
|
+
setLastSeen(nowIso);
|
|
4492
|
+
setStatus(calculateStatus(false, nowIso));
|
|
4493
|
+
}
|
|
4494
|
+
}).on(
|
|
4495
|
+
"postgres_changes",
|
|
4496
|
+
{
|
|
4497
|
+
event: "*",
|
|
4498
|
+
schema: "public",
|
|
4499
|
+
table: "user_sessions",
|
|
4500
|
+
filter: isSelf ? `device_id=eq.${getDeviceId()}` : `user_id=eq.${userId}`
|
|
4501
|
+
},
|
|
4502
|
+
(payload) => {
|
|
4503
|
+
if (!isMounted) return;
|
|
4504
|
+
const newLastSeen = payload.new?.last_seen_at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
4505
|
+
setLastSeen(newLastSeen);
|
|
4506
|
+
setStatus(calculateStatus(false, newLastSeen));
|
|
4507
|
+
}
|
|
4508
|
+
).subscribe();
|
|
4509
|
+
return () => {
|
|
4510
|
+
isMounted = false;
|
|
4511
|
+
supabase.removeChannel(channel);
|
|
4512
|
+
};
|
|
4513
|
+
}, [userId, initialLastSeenAt, currentAuthUserId]);
|
|
4514
|
+
return {
|
|
4515
|
+
status,
|
|
4516
|
+
isOnline: status === "online",
|
|
4517
|
+
lastSeen
|
|
4518
|
+
};
|
|
4519
|
+
};
|
|
4520
|
+
|
|
4430
4521
|
// src/hooks/index.ts
|
|
4431
4522
|
var Hooks = {
|
|
4432
|
-
useDebounce
|
|
4523
|
+
useDebounce,
|
|
4524
|
+
useUserStatus: useUserStatus2
|
|
4433
4525
|
};
|
|
4434
4526
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4435
4527
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
UserStatusChipComponent,
|
|
22
22
|
fetchCompanySessions,
|
|
23
23
|
fetchUserSessions,
|
|
24
|
+
getDeviceId,
|
|
24
25
|
getUserLastSeenAt,
|
|
25
26
|
getUsersLastSeenMap,
|
|
26
27
|
groupSessionsByUser,
|
|
@@ -40,7 +41,7 @@ import {
|
|
|
40
41
|
useTranslationEdit,
|
|
41
42
|
useTranslationNamespace,
|
|
42
43
|
useUserSettings
|
|
43
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-ZIMI3BRO.mjs";
|
|
44
45
|
|
|
45
46
|
// src/UI/components/inputs/TextFieldComponent.tsx
|
|
46
47
|
import { useState } from "react";
|
|
@@ -738,7 +739,7 @@ var EmailInputComponent = ({
|
|
|
738
739
|
import { useState as useState5, useEffect as useEffect2, lazy, Suspense } from "react";
|
|
739
740
|
import { Avatar, Tooltip as Tooltip3, Typography as Typography2 } from "@mui/material";
|
|
740
741
|
import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
741
|
-
var LazyUserPopover = lazy(() => import("./UserPopoverComponent-
|
|
742
|
+
var LazyUserPopover = lazy(() => import("./UserPopoverComponent-TEHD5DSA.mjs"));
|
|
742
743
|
var getInitials = (name) => {
|
|
743
744
|
if (!name) return "?";
|
|
744
745
|
const parts = name.trim().split(" ");
|
|
@@ -1695,9 +1696,99 @@ var Services = {
|
|
|
1695
1696
|
}
|
|
1696
1697
|
};
|
|
1697
1698
|
|
|
1699
|
+
// src/hooks/useUserStatus.ts
|
|
1700
|
+
import { useEffect as useEffect6, useRef, useState as useState11 } from "react";
|
|
1701
|
+
var ONLINE_THRESHOLD_MINUTES = 2;
|
|
1702
|
+
var AWAY_THRESHOLD_MINUTES = 15;
|
|
1703
|
+
var useUserStatus = (userId, initialLastSeenAt, currentAuthUserId) => {
|
|
1704
|
+
const supabase = useSupabase();
|
|
1705
|
+
const [status, setStatus] = useState11("offline");
|
|
1706
|
+
const [lastSeen, setLastSeen] = useState11(initialLastSeenAt ?? null);
|
|
1707
|
+
const lastSeenRef = useRef(initialLastSeenAt ?? null);
|
|
1708
|
+
lastSeenRef.current = lastSeen;
|
|
1709
|
+
const calculateStatus = (isOnline, lastSeenIso) => {
|
|
1710
|
+
if (isOnline) return "online";
|
|
1711
|
+
if (!lastSeenIso) return "offline";
|
|
1712
|
+
const lastSeenTime = new Date(lastSeenIso).getTime();
|
|
1713
|
+
if (isNaN(lastSeenTime)) return "offline";
|
|
1714
|
+
const diffInMinutes = (Date.now() - lastSeenTime) / (1e3 * 60);
|
|
1715
|
+
if (diffInMinutes >= 0 && diffInMinutes <= ONLINE_THRESHOLD_MINUTES) {
|
|
1716
|
+
return "online";
|
|
1717
|
+
}
|
|
1718
|
+
if (diffInMinutes > ONLINE_THRESHOLD_MINUTES && diffInMinutes <= AWAY_THRESHOLD_MINUTES) {
|
|
1719
|
+
return "away";
|
|
1720
|
+
}
|
|
1721
|
+
return "offline";
|
|
1722
|
+
};
|
|
1723
|
+
useEffect6(() => {
|
|
1724
|
+
if (!userId) return;
|
|
1725
|
+
let isMounted = true;
|
|
1726
|
+
const isSelf = currentAuthUserId && userId === currentAuthUserId;
|
|
1727
|
+
const fetchLastSeen = async () => {
|
|
1728
|
+
if (initialLastSeenAt !== void 0) return;
|
|
1729
|
+
let query = supabase.from("user_sessions").select("last_seen_at").eq("user_id", userId);
|
|
1730
|
+
if (isSelf) {
|
|
1731
|
+
query = query.eq("device_id", getDeviceId());
|
|
1732
|
+
} else {
|
|
1733
|
+
query = query.order("last_seen_at", { ascending: false });
|
|
1734
|
+
}
|
|
1735
|
+
const { data, error } = await query.limit(1).maybeSingle();
|
|
1736
|
+
if (error) {
|
|
1737
|
+
console.warn(`[useUserStatus] Error fetching session for ${userId}:`, error.message);
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
if (data && isMounted) {
|
|
1741
|
+
setLastSeen(data.last_seen_at);
|
|
1742
|
+
setStatus(calculateStatus(false, data.last_seen_at));
|
|
1743
|
+
}
|
|
1744
|
+
};
|
|
1745
|
+
fetchLastSeen();
|
|
1746
|
+
const channel = supabase.channel(`presence_user_${userId}`);
|
|
1747
|
+
channel.on("presence", { event: "sync" }, () => {
|
|
1748
|
+
const state = channel.presenceState();
|
|
1749
|
+
const isOnline = Object.keys(state).length > 0;
|
|
1750
|
+
if (isMounted) {
|
|
1751
|
+
setStatus(isOnline ? "online" : calculateStatus(false, lastSeenRef.current));
|
|
1752
|
+
}
|
|
1753
|
+
}).on("presence", { event: "join" }, () => {
|
|
1754
|
+
if (isMounted) setStatus("online");
|
|
1755
|
+
}).on("presence", { event: "leave" }, () => {
|
|
1756
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
1757
|
+
if (isMounted) {
|
|
1758
|
+
setLastSeen(nowIso);
|
|
1759
|
+
setStatus(calculateStatus(false, nowIso));
|
|
1760
|
+
}
|
|
1761
|
+
}).on(
|
|
1762
|
+
"postgres_changes",
|
|
1763
|
+
{
|
|
1764
|
+
event: "*",
|
|
1765
|
+
schema: "public",
|
|
1766
|
+
table: "user_sessions",
|
|
1767
|
+
filter: isSelf ? `device_id=eq.${getDeviceId()}` : `user_id=eq.${userId}`
|
|
1768
|
+
},
|
|
1769
|
+
(payload) => {
|
|
1770
|
+
if (!isMounted) return;
|
|
1771
|
+
const newLastSeen = payload.new?.last_seen_at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1772
|
+
setLastSeen(newLastSeen);
|
|
1773
|
+
setStatus(calculateStatus(false, newLastSeen));
|
|
1774
|
+
}
|
|
1775
|
+
).subscribe();
|
|
1776
|
+
return () => {
|
|
1777
|
+
isMounted = false;
|
|
1778
|
+
supabase.removeChannel(channel);
|
|
1779
|
+
};
|
|
1780
|
+
}, [userId, initialLastSeenAt, currentAuthUserId]);
|
|
1781
|
+
return {
|
|
1782
|
+
status,
|
|
1783
|
+
isOnline: status === "online",
|
|
1784
|
+
lastSeen
|
|
1785
|
+
};
|
|
1786
|
+
};
|
|
1787
|
+
|
|
1698
1788
|
// src/hooks/index.ts
|
|
1699
1789
|
var Hooks = {
|
|
1700
|
-
useDebounce
|
|
1790
|
+
useDebounce,
|
|
1791
|
+
useUserStatus
|
|
1701
1792
|
};
|
|
1702
1793
|
export {
|
|
1703
1794
|
AIProvider,
|