@serhii.olishevskyi/docs 1.1.3 → 1.1.4
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/{UserPopoverComponent-64KAMDBO.mjs → UserPopoverComponent-ZG4UFBGJ.mjs} +1 -1
- package/dist/{chunk-BAFKGCJJ.mjs → chunk-ERXHWCQ5.mjs} +127 -0
- package/dist/index.d.mts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +137 -1
- package/dist/index.mjs +23 -2
- package/package.json +1 -1
|
@@ -200,6 +200,84 @@ var getDeviceId = () => {
|
|
|
200
200
|
};
|
|
201
201
|
|
|
202
202
|
// src/services/session.service.ts
|
|
203
|
+
var fetchCompanySessions = async (supabase, companyId, page = 1, pageSize = 5, searchQuery = "") => {
|
|
204
|
+
const currentDeviceId = getDeviceId();
|
|
205
|
+
let query = supabase.from("memberships").select(`
|
|
206
|
+
user_id,
|
|
207
|
+
role,
|
|
208
|
+
employee_post,
|
|
209
|
+
profiles (
|
|
210
|
+
id,
|
|
211
|
+
display_name,
|
|
212
|
+
first_name,
|
|
213
|
+
last_name
|
|
214
|
+
)
|
|
215
|
+
`, { count: "exact" }).eq("company_id", companyId);
|
|
216
|
+
if (searchQuery.trim()) {
|
|
217
|
+
const q = `%${searchQuery.trim()}%`;
|
|
218
|
+
const { data: matchedProfiles } = await supabase.from("profiles").select("id").or(`display_name.ilike.${q},first_name.ilike.${q},last_name.ilike.${q}`);
|
|
219
|
+
const matchedUserIds = (matchedProfiles || []).map((p) => p.id);
|
|
220
|
+
if (matchedUserIds.length > 0) {
|
|
221
|
+
query = query.or(`employee_post.ilike.${q},user_id.in.(${matchedUserIds.join(",")})`);
|
|
222
|
+
} else {
|
|
223
|
+
query = query.ilike("employee_post", q);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const { data: members, error: membersError } = await query;
|
|
227
|
+
if (membersError) throw membersError;
|
|
228
|
+
if (!members || members.length === 0) {
|
|
229
|
+
return { data: [], totalCount: 0 };
|
|
230
|
+
}
|
|
231
|
+
const userMap = /* @__PURE__ */ new Map();
|
|
232
|
+
members.forEach((m) => {
|
|
233
|
+
const profile = Array.isArray(m.profiles) ? m.profiles[0] : m.profiles;
|
|
234
|
+
const name = profile?.display_name || [profile?.first_name, profile?.last_name].filter(Boolean).join(" ") || "\u041D\u0435\u0432\u0456\u0434\u043E\u043C\u0438\u0439 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447";
|
|
235
|
+
userMap.set(m.user_id, {
|
|
236
|
+
name,
|
|
237
|
+
post: m.employee_post || "\u041F\u043E\u0441\u0430\u0434\u0430 \u043D\u0435 \u0432\u043A\u0430\u0437\u0430\u043D\u0430",
|
|
238
|
+
role: m.role || "user"
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
const userIds = Array.from(userMap.keys());
|
|
242
|
+
const { data: sessions, error: sessionsError } = await supabase.from("user_sessions").select("*").in("user_id", userIds).order("last_seen_at", { ascending: false });
|
|
243
|
+
if (sessionsError) throw sessionsError;
|
|
244
|
+
const groupsMap = /* @__PURE__ */ new Map();
|
|
245
|
+
(sessions || []).forEach((s) => {
|
|
246
|
+
const userInfo = userMap.get(s.user_id);
|
|
247
|
+
if (!userInfo) return;
|
|
248
|
+
if (!groupsMap.has(s.user_id)) {
|
|
249
|
+
groupsMap.set(s.user_id, {
|
|
250
|
+
userId: s.user_id,
|
|
251
|
+
userName: userInfo.name,
|
|
252
|
+
employeePost: userInfo.post,
|
|
253
|
+
role: userInfo.role,
|
|
254
|
+
sessions: []
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
groupsMap.get(s.user_id).sessions.push({
|
|
258
|
+
id: s.id,
|
|
259
|
+
user_id: s.user_id,
|
|
260
|
+
user_agent: s.user_agent,
|
|
261
|
+
ip_address: s.ip_address,
|
|
262
|
+
created_at: s.created_at,
|
|
263
|
+
last_seen_at: s.last_seen_at,
|
|
264
|
+
device_id: s.device_id,
|
|
265
|
+
is_current: s.device_id === currentDeviceId,
|
|
266
|
+
user_name: userInfo.name,
|
|
267
|
+
employee_post: userInfo.post,
|
|
268
|
+
role: userInfo.role,
|
|
269
|
+
url: s.url
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
const allGroupedWithSessions = Array.from(groupsMap.values()).filter((group) => group.sessions.length > 0).sort((a, b) => a.userName.localeCompare(b.userName, "uk"));
|
|
273
|
+
const totalCount = allGroupedWithSessions.length;
|
|
274
|
+
const from = (page - 1) * pageSize;
|
|
275
|
+
const paginatedData = allGroupedWithSessions.slice(from, from + pageSize);
|
|
276
|
+
return {
|
|
277
|
+
data: paginatedData,
|
|
278
|
+
totalCount
|
|
279
|
+
};
|
|
280
|
+
};
|
|
203
281
|
var trackUserSession = async (supabase, userId) => {
|
|
204
282
|
const deviceId = getDeviceId();
|
|
205
283
|
let ip = "";
|
|
@@ -222,6 +300,17 @@ var trackUserSession = async (supabase, userId) => {
|
|
|
222
300
|
{ onConflict: "user_id, device_id" }
|
|
223
301
|
);
|
|
224
302
|
};
|
|
303
|
+
var fetchUserSessions = async (supabase) => {
|
|
304
|
+
const currentDeviceId = getDeviceId();
|
|
305
|
+
const { data: { user } } = await supabase.auth.getUser();
|
|
306
|
+
if (!user) return [];
|
|
307
|
+
const { data, error } = await supabase.from("user_sessions").select("*").eq("user_id", user.id).order("last_seen_at", { ascending: false });
|
|
308
|
+
if (error) throw error;
|
|
309
|
+
return (data || []).map((s) => ({
|
|
310
|
+
...s,
|
|
311
|
+
is_current: s.device_id === currentDeviceId
|
|
312
|
+
}));
|
|
313
|
+
};
|
|
225
314
|
var isCurrentSessionValid = async (supabase, userId) => {
|
|
226
315
|
try {
|
|
227
316
|
const currentDeviceId = getDeviceId();
|
|
@@ -237,11 +326,42 @@ var isCurrentSessionValid = async (supabase, userId) => {
|
|
|
237
326
|
return true;
|
|
238
327
|
}
|
|
239
328
|
};
|
|
329
|
+
var groupSessionsByUser = (sessions) => {
|
|
330
|
+
const groupsMap = /* @__PURE__ */ new Map();
|
|
331
|
+
sessions.forEach((session) => {
|
|
332
|
+
const userId = session.user_id;
|
|
333
|
+
if (!groupsMap.has(userId)) {
|
|
334
|
+
groupsMap.set(userId, {
|
|
335
|
+
userId,
|
|
336
|
+
userName: session.user_name || "\u041D\u0435\u0432\u0456\u0434\u043E\u043C\u0438\u0439 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447",
|
|
337
|
+
employeePost: session.employee_post || "\u041F\u043E\u0441\u0430\u0434\u0430 \u043D\u0435 \u0432\u043A\u0430\u0437\u0430\u043D\u0430",
|
|
338
|
+
role: session.role || "user",
|
|
339
|
+
sessions: []
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
groupsMap.get(userId).sessions.push(session);
|
|
343
|
+
});
|
|
344
|
+
return Array.from(groupsMap.values()).sort(
|
|
345
|
+
(a, b) => a.userName.localeCompare(b.userName, "uk")
|
|
346
|
+
);
|
|
347
|
+
};
|
|
240
348
|
var getUserLastSeenAt = async (supabase, userId) => {
|
|
241
349
|
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();
|
|
242
350
|
if (error || !data) return null;
|
|
243
351
|
return data.last_seen_at;
|
|
244
352
|
};
|
|
353
|
+
var getUsersLastSeenMap = async (supabase, userIds) => {
|
|
354
|
+
if (!userIds.length) return {};
|
|
355
|
+
const { data, error } = await supabase.from("user_sessions").select("user_id, last_seen_at").in("user_id", userIds).order("last_seen_at", { ascending: false });
|
|
356
|
+
if (error || !data) return {};
|
|
357
|
+
const resultMap = {};
|
|
358
|
+
for (const session of data) {
|
|
359
|
+
if (!resultMap[session.user_id]) {
|
|
360
|
+
resultMap[session.user_id] = session.last_seen_at;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return resultMap;
|
|
364
|
+
};
|
|
245
365
|
|
|
246
366
|
// src/context/AuthProvider.tsx
|
|
247
367
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
@@ -2413,6 +2533,13 @@ var UserPopoverComponent = ({
|
|
|
2413
2533
|
var UserPopoverComponent_default = UserPopoverComponent;
|
|
2414
2534
|
|
|
2415
2535
|
export {
|
|
2536
|
+
fetchCompanySessions,
|
|
2537
|
+
trackUserSession,
|
|
2538
|
+
fetchUserSessions,
|
|
2539
|
+
isCurrentSessionValid,
|
|
2540
|
+
groupSessionsByUser,
|
|
2541
|
+
getUserLastSeenAt,
|
|
2542
|
+
getUsersLastSeenMap,
|
|
2416
2543
|
SupabaseProvider,
|
|
2417
2544
|
useSupabase,
|
|
2418
2545
|
AuthProvider,
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React$1 from 'react';
|
|
2
2
|
import React__default, { ReactNode } from 'react';
|
|
3
3
|
import { TextFieldProps, IconButtonProps, TooltipProps, SxProps, Theme } from '@mui/material';
|
|
4
|
+
import * as _supabase_supabase_js from '@supabase/supabase-js';
|
|
4
5
|
import { SupabaseClient, User, Session } from '@supabase/supabase-js';
|
|
5
6
|
|
|
6
7
|
interface UrlValue {
|
|
@@ -488,4 +489,42 @@ declare const Providers: {
|
|
|
488
489
|
readonly AIProvider: React$1.FC<AIProviderProps>;
|
|
489
490
|
};
|
|
490
491
|
|
|
491
|
-
|
|
492
|
+
interface UserSessionItem {
|
|
493
|
+
id: string;
|
|
494
|
+
user_id: string;
|
|
495
|
+
user_agent: string | null;
|
|
496
|
+
ip_address: string | null;
|
|
497
|
+
created_at: string;
|
|
498
|
+
last_seen_at: string;
|
|
499
|
+
device_id: string;
|
|
500
|
+
url?: string | null;
|
|
501
|
+
is_current?: boolean;
|
|
502
|
+
user_name?: string;
|
|
503
|
+
employee_post?: string;
|
|
504
|
+
role?: string;
|
|
505
|
+
}
|
|
506
|
+
interface UserGroupedSessions {
|
|
507
|
+
userId: string;
|
|
508
|
+
userName: string;
|
|
509
|
+
employeePost: string;
|
|
510
|
+
role: string;
|
|
511
|
+
sessions: UserSessionItem[];
|
|
512
|
+
}
|
|
513
|
+
interface FetchCompanySessionsResponse {
|
|
514
|
+
data: UserGroupedSessions[];
|
|
515
|
+
totalCount: number;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
declare const Services: {
|
|
519
|
+
readonly SessionService: {
|
|
520
|
+
readonly fetchCompanySessions: (supabase: _supabase_supabase_js.SupabaseClient, companyId: string, page?: number, pageSize?: number, searchQuery?: string) => Promise<FetchCompanySessionsResponse>;
|
|
521
|
+
readonly trackUserSession: (supabase: _supabase_supabase_js.SupabaseClient, userId: string) => Promise<void>;
|
|
522
|
+
readonly fetchUserSessions: (supabase: _supabase_supabase_js.SupabaseClient) => Promise<UserSessionItem[]>;
|
|
523
|
+
readonly isCurrentSessionValid: (supabase: _supabase_supabase_js.SupabaseClient, userId: string) => Promise<boolean>;
|
|
524
|
+
readonly groupSessionsByUser: (sessions: UserSessionItem[]) => UserGroupedSessions[];
|
|
525
|
+
readonly getUserLastSeenAt: (supabase: _supabase_supabase_js.SupabaseClient, userId: string) => Promise<string | null>;
|
|
526
|
+
readonly getUsersLastSeenMap: (supabase: _supabase_supabase_js.SupabaseClient, userIds: string[]) => Promise<Record<string, string>>;
|
|
527
|
+
};
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps as CopyClipboardButtonProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps as EmailInputProps, type Language, LocalizationProvider, type MyAvatarComponentProps as MyAvatarProps, type NumberInputComponentProps as NumberInputProps, Providers, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps as TextFieldProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps as TranslatableTooltipProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps as UserAvatarProps, type UserGroupedSessions, type UserPopoverComponentProps as UserPopoverProps, type UserRoleChipComponentProps as UserRoleChipProps, type UserSessionItem, UserSettingsProvider, type UserStatusChipComponentProps as UserStatusChipProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React$1 from 'react';
|
|
2
2
|
import React__default, { ReactNode } from 'react';
|
|
3
3
|
import { TextFieldProps, IconButtonProps, TooltipProps, SxProps, Theme } from '@mui/material';
|
|
4
|
+
import * as _supabase_supabase_js from '@supabase/supabase-js';
|
|
4
5
|
import { SupabaseClient, User, Session } from '@supabase/supabase-js';
|
|
5
6
|
|
|
6
7
|
interface UrlValue {
|
|
@@ -488,4 +489,42 @@ declare const Providers: {
|
|
|
488
489
|
readonly AIProvider: React$1.FC<AIProviderProps>;
|
|
489
490
|
};
|
|
490
491
|
|
|
491
|
-
|
|
492
|
+
interface UserSessionItem {
|
|
493
|
+
id: string;
|
|
494
|
+
user_id: string;
|
|
495
|
+
user_agent: string | null;
|
|
496
|
+
ip_address: string | null;
|
|
497
|
+
created_at: string;
|
|
498
|
+
last_seen_at: string;
|
|
499
|
+
device_id: string;
|
|
500
|
+
url?: string | null;
|
|
501
|
+
is_current?: boolean;
|
|
502
|
+
user_name?: string;
|
|
503
|
+
employee_post?: string;
|
|
504
|
+
role?: string;
|
|
505
|
+
}
|
|
506
|
+
interface UserGroupedSessions {
|
|
507
|
+
userId: string;
|
|
508
|
+
userName: string;
|
|
509
|
+
employeePost: string;
|
|
510
|
+
role: string;
|
|
511
|
+
sessions: UserSessionItem[];
|
|
512
|
+
}
|
|
513
|
+
interface FetchCompanySessionsResponse {
|
|
514
|
+
data: UserGroupedSessions[];
|
|
515
|
+
totalCount: number;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
declare const Services: {
|
|
519
|
+
readonly SessionService: {
|
|
520
|
+
readonly fetchCompanySessions: (supabase: _supabase_supabase_js.SupabaseClient, companyId: string, page?: number, pageSize?: number, searchQuery?: string) => Promise<FetchCompanySessionsResponse>;
|
|
521
|
+
readonly trackUserSession: (supabase: _supabase_supabase_js.SupabaseClient, userId: string) => Promise<void>;
|
|
522
|
+
readonly fetchUserSessions: (supabase: _supabase_supabase_js.SupabaseClient) => Promise<UserSessionItem[]>;
|
|
523
|
+
readonly isCurrentSessionValid: (supabase: _supabase_supabase_js.SupabaseClient, userId: string) => Promise<boolean>;
|
|
524
|
+
readonly groupSessionsByUser: (sessions: UserSessionItem[]) => UserGroupedSessions[];
|
|
525
|
+
readonly getUserLastSeenAt: (supabase: _supabase_supabase_js.SupabaseClient, userId: string) => Promise<string | null>;
|
|
526
|
+
readonly getUsersLastSeenMap: (supabase: _supabase_supabase_js.SupabaseClient, userIds: string[]) => Promise<Record<string, string>>;
|
|
527
|
+
};
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
export { type AIConfig, type AIGenerateOptions, AIProvider, type AIProviderProps, type AIProviderType, AppSettingsProvider, AuthProvider, BreadcrumbProvider, type ConfirmOptions, type ConfirmResult, ConfirmationProvider, type ConfirmationProviderProps, type CopyClipboardButtonComponentProps as CopyClipboardButtonProps, type DialogSeverity, type DisplayState, type EmailInputComponentProps as EmailInputProps, type Language, LocalizationProvider, type MyAvatarComponentProps as MyAvatarProps, type NumberInputComponentProps as NumberInputProps, Providers, Services, type SupabaseConfig, SupabaseProvider, type SupabaseProviderProps, type TextFieldComponentProps as TextFieldProps, type ThemeColors, type ThemeConfig, type ThemeMode, ThemeProvider, ToastProvider, type ToastType, type TranslatableTooltipComponentProps as TranslatableTooltipProps, TranslateProvider, TranslateText, TranslationEditProvider, type TypographyConfig, UI, type UrlComponentProps as UrlProps, type UserAvatarComponentProps as UserAvatarProps, type UserGroupedSessions, type UserPopoverComponentProps as UserPopoverProps, type UserRoleChipComponentProps as UserRoleChipProps, type UserSessionItem, UserSettingsProvider, type UserStatusChipComponentProps as UserStatusChipProps, useAI, useAppSettings, useAppTheme, useAuth, useBreadcrumb, useConfirmation, useLocalization, useSupabase, useToast, useTranslationEdit, useTranslationNamespace, useUserSettings };
|
package/dist/index.js
CHANGED
|
@@ -169,11 +169,89 @@ var init_deviceId = __esm({
|
|
|
169
169
|
});
|
|
170
170
|
|
|
171
171
|
// src/services/session.service.ts
|
|
172
|
-
var trackUserSession, isCurrentSessionValid, getUserLastSeenAt;
|
|
172
|
+
var fetchCompanySessions, trackUserSession, fetchUserSessions, isCurrentSessionValid, groupSessionsByUser, getUserLastSeenAt, getUsersLastSeenMap;
|
|
173
173
|
var init_session_service = __esm({
|
|
174
174
|
"src/services/session.service.ts"() {
|
|
175
175
|
"use strict";
|
|
176
176
|
init_deviceId();
|
|
177
|
+
fetchCompanySessions = async (supabase, companyId, page = 1, pageSize = 5, searchQuery = "") => {
|
|
178
|
+
const currentDeviceId = getDeviceId();
|
|
179
|
+
let query = supabase.from("memberships").select(`
|
|
180
|
+
user_id,
|
|
181
|
+
role,
|
|
182
|
+
employee_post,
|
|
183
|
+
profiles (
|
|
184
|
+
id,
|
|
185
|
+
display_name,
|
|
186
|
+
first_name,
|
|
187
|
+
last_name
|
|
188
|
+
)
|
|
189
|
+
`, { count: "exact" }).eq("company_id", companyId);
|
|
190
|
+
if (searchQuery.trim()) {
|
|
191
|
+
const q = `%${searchQuery.trim()}%`;
|
|
192
|
+
const { data: matchedProfiles } = await supabase.from("profiles").select("id").or(`display_name.ilike.${q},first_name.ilike.${q},last_name.ilike.${q}`);
|
|
193
|
+
const matchedUserIds = (matchedProfiles || []).map((p) => p.id);
|
|
194
|
+
if (matchedUserIds.length > 0) {
|
|
195
|
+
query = query.or(`employee_post.ilike.${q},user_id.in.(${matchedUserIds.join(",")})`);
|
|
196
|
+
} else {
|
|
197
|
+
query = query.ilike("employee_post", q);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const { data: members, error: membersError } = await query;
|
|
201
|
+
if (membersError) throw membersError;
|
|
202
|
+
if (!members || members.length === 0) {
|
|
203
|
+
return { data: [], totalCount: 0 };
|
|
204
|
+
}
|
|
205
|
+
const userMap = /* @__PURE__ */ new Map();
|
|
206
|
+
members.forEach((m) => {
|
|
207
|
+
const profile = Array.isArray(m.profiles) ? m.profiles[0] : m.profiles;
|
|
208
|
+
const name = profile?.display_name || [profile?.first_name, profile?.last_name].filter(Boolean).join(" ") || "\u041D\u0435\u0432\u0456\u0434\u043E\u043C\u0438\u0439 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447";
|
|
209
|
+
userMap.set(m.user_id, {
|
|
210
|
+
name,
|
|
211
|
+
post: m.employee_post || "\u041F\u043E\u0441\u0430\u0434\u0430 \u043D\u0435 \u0432\u043A\u0430\u0437\u0430\u043D\u0430",
|
|
212
|
+
role: m.role || "user"
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
const userIds = Array.from(userMap.keys());
|
|
216
|
+
const { data: sessions, error: sessionsError } = await supabase.from("user_sessions").select("*").in("user_id", userIds).order("last_seen_at", { ascending: false });
|
|
217
|
+
if (sessionsError) throw sessionsError;
|
|
218
|
+
const groupsMap = /* @__PURE__ */ new Map();
|
|
219
|
+
(sessions || []).forEach((s) => {
|
|
220
|
+
const userInfo = userMap.get(s.user_id);
|
|
221
|
+
if (!userInfo) return;
|
|
222
|
+
if (!groupsMap.has(s.user_id)) {
|
|
223
|
+
groupsMap.set(s.user_id, {
|
|
224
|
+
userId: s.user_id,
|
|
225
|
+
userName: userInfo.name,
|
|
226
|
+
employeePost: userInfo.post,
|
|
227
|
+
role: userInfo.role,
|
|
228
|
+
sessions: []
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
groupsMap.get(s.user_id).sessions.push({
|
|
232
|
+
id: s.id,
|
|
233
|
+
user_id: s.user_id,
|
|
234
|
+
user_agent: s.user_agent,
|
|
235
|
+
ip_address: s.ip_address,
|
|
236
|
+
created_at: s.created_at,
|
|
237
|
+
last_seen_at: s.last_seen_at,
|
|
238
|
+
device_id: s.device_id,
|
|
239
|
+
is_current: s.device_id === currentDeviceId,
|
|
240
|
+
user_name: userInfo.name,
|
|
241
|
+
employee_post: userInfo.post,
|
|
242
|
+
role: userInfo.role,
|
|
243
|
+
url: s.url
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
const allGroupedWithSessions = Array.from(groupsMap.values()).filter((group) => group.sessions.length > 0).sort((a, b) => a.userName.localeCompare(b.userName, "uk"));
|
|
247
|
+
const totalCount = allGroupedWithSessions.length;
|
|
248
|
+
const from = (page - 1) * pageSize;
|
|
249
|
+
const paginatedData = allGroupedWithSessions.slice(from, from + pageSize);
|
|
250
|
+
return {
|
|
251
|
+
data: paginatedData,
|
|
252
|
+
totalCount
|
|
253
|
+
};
|
|
254
|
+
};
|
|
177
255
|
trackUserSession = async (supabase, userId) => {
|
|
178
256
|
const deviceId = getDeviceId();
|
|
179
257
|
let ip = "";
|
|
@@ -196,6 +274,17 @@ var init_session_service = __esm({
|
|
|
196
274
|
{ onConflict: "user_id, device_id" }
|
|
197
275
|
);
|
|
198
276
|
};
|
|
277
|
+
fetchUserSessions = async (supabase) => {
|
|
278
|
+
const currentDeviceId = getDeviceId();
|
|
279
|
+
const { data: { user } } = await supabase.auth.getUser();
|
|
280
|
+
if (!user) return [];
|
|
281
|
+
const { data, error } = await supabase.from("user_sessions").select("*").eq("user_id", user.id).order("last_seen_at", { ascending: false });
|
|
282
|
+
if (error) throw error;
|
|
283
|
+
return (data || []).map((s) => ({
|
|
284
|
+
...s,
|
|
285
|
+
is_current: s.device_id === currentDeviceId
|
|
286
|
+
}));
|
|
287
|
+
};
|
|
199
288
|
isCurrentSessionValid = async (supabase, userId) => {
|
|
200
289
|
try {
|
|
201
290
|
const currentDeviceId = getDeviceId();
|
|
@@ -211,11 +300,42 @@ var init_session_service = __esm({
|
|
|
211
300
|
return true;
|
|
212
301
|
}
|
|
213
302
|
};
|
|
303
|
+
groupSessionsByUser = (sessions) => {
|
|
304
|
+
const groupsMap = /* @__PURE__ */ new Map();
|
|
305
|
+
sessions.forEach((session) => {
|
|
306
|
+
const userId = session.user_id;
|
|
307
|
+
if (!groupsMap.has(userId)) {
|
|
308
|
+
groupsMap.set(userId, {
|
|
309
|
+
userId,
|
|
310
|
+
userName: session.user_name || "\u041D\u0435\u0432\u0456\u0434\u043E\u043C\u0438\u0439 \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447",
|
|
311
|
+
employeePost: session.employee_post || "\u041F\u043E\u0441\u0430\u0434\u0430 \u043D\u0435 \u0432\u043A\u0430\u0437\u0430\u043D\u0430",
|
|
312
|
+
role: session.role || "user",
|
|
313
|
+
sessions: []
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
groupsMap.get(userId).sessions.push(session);
|
|
317
|
+
});
|
|
318
|
+
return Array.from(groupsMap.values()).sort(
|
|
319
|
+
(a, b) => a.userName.localeCompare(b.userName, "uk")
|
|
320
|
+
);
|
|
321
|
+
};
|
|
214
322
|
getUserLastSeenAt = async (supabase, userId) => {
|
|
215
323
|
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();
|
|
216
324
|
if (error || !data) return null;
|
|
217
325
|
return data.last_seen_at;
|
|
218
326
|
};
|
|
327
|
+
getUsersLastSeenMap = async (supabase, userIds) => {
|
|
328
|
+
if (!userIds.length) return {};
|
|
329
|
+
const { data, error } = await supabase.from("user_sessions").select("user_id, last_seen_at").in("user_id", userIds).order("last_seen_at", { ascending: false });
|
|
330
|
+
if (error || !data) return {};
|
|
331
|
+
const resultMap = {};
|
|
332
|
+
for (const session of data) {
|
|
333
|
+
if (!resultMap[session.user_id]) {
|
|
334
|
+
resultMap[session.user_id] = session.last_seen_at;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return resultMap;
|
|
338
|
+
};
|
|
219
339
|
}
|
|
220
340
|
});
|
|
221
341
|
|
|
@@ -2617,6 +2737,7 @@ __export(index_exports, {
|
|
|
2617
2737
|
ConfirmationProvider: () => ConfirmationProvider,
|
|
2618
2738
|
LocalizationProvider: () => LocalizationProvider,
|
|
2619
2739
|
Providers: () => Providers,
|
|
2740
|
+
Services: () => Services,
|
|
2620
2741
|
SupabaseProvider: () => SupabaseProvider,
|
|
2621
2742
|
ThemeProvider: () => ThemeProvider,
|
|
2622
2743
|
ToastProvider: () => ToastProvider,
|
|
@@ -3875,6 +3996,20 @@ var UI = {
|
|
|
3875
3996
|
// src/index.ts
|
|
3876
3997
|
init_context();
|
|
3877
3998
|
init_context();
|
|
3999
|
+
|
|
4000
|
+
// src/services/index.ts
|
|
4001
|
+
init_session_service();
|
|
4002
|
+
var Services = {
|
|
4003
|
+
SessionService: {
|
|
4004
|
+
fetchCompanySessions,
|
|
4005
|
+
trackUserSession,
|
|
4006
|
+
fetchUserSessions,
|
|
4007
|
+
isCurrentSessionValid,
|
|
4008
|
+
groupSessionsByUser,
|
|
4009
|
+
getUserLastSeenAt,
|
|
4010
|
+
getUsersLastSeenMap
|
|
4011
|
+
}
|
|
4012
|
+
};
|
|
3878
4013
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3879
4014
|
0 && (module.exports = {
|
|
3880
4015
|
AIProvider,
|
|
@@ -3884,6 +4019,7 @@ init_context();
|
|
|
3884
4019
|
ConfirmationProvider,
|
|
3885
4020
|
LocalizationProvider,
|
|
3886
4021
|
Providers,
|
|
4022
|
+
Services,
|
|
3887
4023
|
SupabaseProvider,
|
|
3888
4024
|
ThemeProvider,
|
|
3889
4025
|
ToastProvider,
|
package/dist/index.mjs
CHANGED
|
@@ -19,6 +19,13 @@ import {
|
|
|
19
19
|
UserRoleChipComponent,
|
|
20
20
|
UserSettingsProvider,
|
|
21
21
|
UserStatusChipComponent,
|
|
22
|
+
fetchCompanySessions,
|
|
23
|
+
fetchUserSessions,
|
|
24
|
+
getUserLastSeenAt,
|
|
25
|
+
getUsersLastSeenMap,
|
|
26
|
+
groupSessionsByUser,
|
|
27
|
+
isCurrentSessionValid,
|
|
28
|
+
trackUserSession,
|
|
22
29
|
translationService,
|
|
23
30
|
useAI,
|
|
24
31
|
useAppSettings,
|
|
@@ -32,7 +39,7 @@ import {
|
|
|
32
39
|
useTranslationEdit,
|
|
33
40
|
useTranslationNamespace,
|
|
34
41
|
useUserSettings
|
|
35
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-ERXHWCQ5.mjs";
|
|
36
43
|
|
|
37
44
|
// src/UI/components/inputs/TextFieldComponent.tsx
|
|
38
45
|
import { useState } from "react";
|
|
@@ -730,7 +737,7 @@ var EmailInputComponent = ({
|
|
|
730
737
|
import { useState as useState5, useEffect as useEffect2, lazy, Suspense } from "react";
|
|
731
738
|
import { Avatar, Tooltip as Tooltip3, Typography as Typography2 } from "@mui/material";
|
|
732
739
|
import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
733
|
-
var LazyUserPopover = lazy(() => import("./UserPopoverComponent-
|
|
740
|
+
var LazyUserPopover = lazy(() => import("./UserPopoverComponent-ZG4UFBGJ.mjs"));
|
|
734
741
|
var getInitials = (name) => {
|
|
735
742
|
if (!name) return "?";
|
|
736
743
|
const parts = name.trim().split(" ");
|
|
@@ -1266,6 +1273,19 @@ var UI = {
|
|
|
1266
1273
|
PublicLanguageSelector
|
|
1267
1274
|
}
|
|
1268
1275
|
};
|
|
1276
|
+
|
|
1277
|
+
// src/services/index.ts
|
|
1278
|
+
var Services = {
|
|
1279
|
+
SessionService: {
|
|
1280
|
+
fetchCompanySessions,
|
|
1281
|
+
trackUserSession,
|
|
1282
|
+
fetchUserSessions,
|
|
1283
|
+
isCurrentSessionValid,
|
|
1284
|
+
groupSessionsByUser,
|
|
1285
|
+
getUserLastSeenAt,
|
|
1286
|
+
getUsersLastSeenMap
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1269
1289
|
export {
|
|
1270
1290
|
AIProvider,
|
|
1271
1291
|
AppSettingsProvider,
|
|
@@ -1274,6 +1294,7 @@ export {
|
|
|
1274
1294
|
ConfirmationProvider,
|
|
1275
1295
|
LocalizationProvider,
|
|
1276
1296
|
Providers,
|
|
1297
|
+
Services,
|
|
1277
1298
|
SupabaseProvider,
|
|
1278
1299
|
ThemeProvider,
|
|
1279
1300
|
ToastProvider,
|