@serhii.olishevskyi/docs 1.1.2 → 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/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,
@@ -3452,6 +3573,399 @@ init_CopyClipboardButtonComponent();
3452
3573
  init_UserRoleChipComponent();
3453
3574
  init_UserStatusChipComponent();
3454
3575
  init_UserPopoverComponent();
3576
+
3577
+ // src/UI/components/data.display/MyAvatarComponent.tsx
3578
+ var import_react23 = require("react");
3579
+ var import_material16 = require("@mui/material");
3580
+ init_context();
3581
+ var import_jsx_runtime26 = require("react/jsx-runtime");
3582
+ var getInitials2 = (name) => {
3583
+ if (!name) return "?";
3584
+ const parts = name.trim().split(" ");
3585
+ if (parts.length >= 2) {
3586
+ return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
3587
+ }
3588
+ return name[0].toUpperCase();
3589
+ };
3590
+ var MyAvatarComponent = ({
3591
+ size = 40,
3592
+ disableBorder = false,
3593
+ disableShadow = false,
3594
+ disablePopover = false,
3595
+ sx = {}
3596
+ }) => {
3597
+ const { profile: userProfile, loading: isLoading } = useAuth();
3598
+ const [anchorEl, setAnchorEl] = (0, import_react23.useState)(null);
3599
+ const handlePopoverOpen = (event) => {
3600
+ if (!disablePopover) {
3601
+ setAnchorEl(event.currentTarget);
3602
+ }
3603
+ };
3604
+ const handlePopoverClose = () => {
3605
+ setAnchorEl(null);
3606
+ };
3607
+ const isPopoverOpen = Boolean(anchorEl);
3608
+ if (isLoading) {
3609
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3610
+ import_material16.Skeleton,
3611
+ {
3612
+ variant: "circular",
3613
+ width: size,
3614
+ height: size,
3615
+ sx: { display: "inline-block", flexShrink: 0, ...sx }
3616
+ }
3617
+ );
3618
+ }
3619
+ const initials = getInitials2(userProfile?.display_name || "");
3620
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
3621
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3622
+ import_material16.Avatar,
3623
+ {
3624
+ src: userProfile?.avatar_url || void 0,
3625
+ alt: userProfile?.display_name || "User Avatar",
3626
+ onMouseEnter: handlePopoverOpen,
3627
+ onMouseLeave: handlePopoverClose,
3628
+ sx: {
3629
+ width: size,
3630
+ height: size,
3631
+ fontSize: size * 0.4,
3632
+ fontWeight: 600,
3633
+ bgcolor: "primary.main",
3634
+ color: "primary.contrastText",
3635
+ cursor: disablePopover ? void 0 : "pointer",
3636
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
3637
+ border: disableBorder ? "none" : "2px solid",
3638
+ borderColor: "background.paper",
3639
+ boxShadow: disableShadow ? "none" : 2,
3640
+ "&:hover": {
3641
+ transform: disablePopover ? "none" : "scale(1.05)"
3642
+ },
3643
+ ...sx
3644
+ },
3645
+ children: !userProfile?.avatar_url && initials
3646
+ }
3647
+ ),
3648
+ !disablePopover && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
3649
+ import_material16.Popover,
3650
+ {
3651
+ id: `avatar-popover-${userProfile?.id}`,
3652
+ open: isPopoverOpen,
3653
+ anchorEl,
3654
+ anchorOrigin: {
3655
+ vertical: "bottom",
3656
+ horizontal: "center"
3657
+ },
3658
+ transformOrigin: {
3659
+ vertical: "top",
3660
+ horizontal: "center"
3661
+ },
3662
+ onClose: handlePopoverClose,
3663
+ disableRestoreFocus: true,
3664
+ disableAutoFocus: true,
3665
+ disableEnforceFocus: true,
3666
+ sx: {
3667
+ pointerEvents: "none",
3668
+ mt: 1
3669
+ },
3670
+ slotProps: {
3671
+ paper: {
3672
+ sx: {
3673
+ p: 1.5,
3674
+ borderRadius: 2,
3675
+ boxShadow: 3
3676
+ }
3677
+ }
3678
+ },
3679
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_material16.Box, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 0.5 }, children: [
3680
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material16.Typography, { variant: "subtitle2", sx: { fontWeight: 600 }, children: userProfile?.display_name }),
3681
+ userProfile?.email && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material16.Typography, { variant: "caption", color: "text.secondary", children: userProfile.email })
3682
+ ] })
3683
+ }
3684
+ )
3685
+ ] });
3686
+ };
3687
+
3688
+ // src/i18n/LanguageSelector.tsx
3689
+ var import_react24 = require("react");
3690
+ var import_react_i18next5 = require("react-i18next");
3691
+ var import_material17 = require("@mui/material");
3692
+ init_LocalizationProvider();
3693
+ init_UserSettingsProvider();
3694
+ init_SupabaseProvider();
3695
+ var import_jsx_runtime27 = require("react/jsx-runtime");
3696
+ var LanguageSelector = () => {
3697
+ const supabase = useSupabase();
3698
+ const { i18n: i18n2 } = (0, import_react_i18next5.useTranslation)();
3699
+ const [languages, setLanguages] = (0, import_react24.useState)([]);
3700
+ const [loading, setLoading] = (0, import_react24.useState)(true);
3701
+ const { changeLanguage } = useLocalization();
3702
+ const { settings: userSettings, setLanguage } = useUserSettings();
3703
+ const [anchorEl, setAnchorEl] = (0, import_react24.useState)(null);
3704
+ const open = Boolean(anchorEl);
3705
+ (0, import_react24.useEffect)(() => {
3706
+ const fetchLanguages = async () => {
3707
+ try {
3708
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
3709
+ if (error) throw error;
3710
+ setLanguages(data || []);
3711
+ if (userSettings.language) changeLanguage(userSettings.language);
3712
+ } catch (err) {
3713
+ console.error("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u043C\u043E\u0432:", err);
3714
+ } finally {
3715
+ setLoading(false);
3716
+ }
3717
+ };
3718
+ fetchLanguages();
3719
+ }, []);
3720
+ const handleClick = (event) => {
3721
+ setAnchorEl(event.currentTarget);
3722
+ };
3723
+ const handleClose = () => {
3724
+ setAnchorEl(null);
3725
+ };
3726
+ const handleSelectLanguage = (langCode) => {
3727
+ changeLanguage(langCode);
3728
+ setLanguage(langCode);
3729
+ handleClose();
3730
+ };
3731
+ if (loading) {
3732
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
3733
+ }
3734
+ const rawCurrentLang = i18n2.language || "uk";
3735
+ const currentLangCode = rawCurrentLang.split("-")[0];
3736
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
3737
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
3738
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.Tooltip, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3739
+ import_material17.IconButton,
3740
+ {
3741
+ onClick: handleClick,
3742
+ size: "small",
3743
+ "aria-controls": open ? "language-menu" : void 0,
3744
+ "aria-haspopup": "true",
3745
+ "aria-expanded": open ? "true" : void 0,
3746
+ sx: {
3747
+ p: 1,
3748
+ borderRadius: 2,
3749
+ transition: "background-color 0.2s",
3750
+ "&:hover": {
3751
+ backgroundColor: "action.hover"
3752
+ }
3753
+ },
3754
+ children: currentLang?.svg_flag && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3755
+ import_material17.Box,
3756
+ {
3757
+ sx: {
3758
+ width: 24,
3759
+ height: 16,
3760
+ borderRadius: "3px",
3761
+ overflow: "hidden",
3762
+ flexShrink: 0,
3763
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
3764
+ display: "flex",
3765
+ alignItems: "center",
3766
+ justifyContent: "center",
3767
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
3768
+ },
3769
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
3770
+ }
3771
+ )
3772
+ }
3773
+ ) }),
3774
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3775
+ import_material17.Menu,
3776
+ {
3777
+ id: "language-menu",
3778
+ anchorEl,
3779
+ open,
3780
+ onClose: handleClose,
3781
+ slotProps: {
3782
+ paper: {
3783
+ elevation: 3,
3784
+ sx: {
3785
+ mt: 1,
3786
+ minWidth: 150,
3787
+ borderRadius: 2
3788
+ }
3789
+ }
3790
+ },
3791
+ transformOrigin: { horizontal: "right", vertical: "top" },
3792
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
3793
+ children: languages.map((lang) => {
3794
+ const isSelected = lang.code === currentLangCode;
3795
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3796
+ import_material17.MenuItem,
3797
+ {
3798
+ selected: isSelected,
3799
+ onClick: () => handleSelectLanguage(lang.code),
3800
+ sx: {
3801
+ display: "flex",
3802
+ alignItems: "center",
3803
+ gap: 1.5,
3804
+ py: 1,
3805
+ px: 2
3806
+ },
3807
+ children: [
3808
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3809
+ import_material17.Box,
3810
+ {
3811
+ sx: {
3812
+ width: 22,
3813
+ height: 15,
3814
+ borderRadius: "2px",
3815
+ overflow: "hidden",
3816
+ flexShrink: 0,
3817
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
3818
+ "& svg": { width: "100%", height: "100%", display: "block" }
3819
+ },
3820
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
3821
+ }
3822
+ ),
3823
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.Typography, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
3824
+ ]
3825
+ },
3826
+ lang.code
3827
+ );
3828
+ })
3829
+ }
3830
+ )
3831
+ ] });
3832
+ };
3833
+ var PublicLanguageSelector = () => {
3834
+ const supabase = useSupabase();
3835
+ const { i18n: i18n2 } = (0, import_react_i18next5.useTranslation)();
3836
+ const { changeLanguage } = useLocalization();
3837
+ const [languages, setLanguages] = (0, import_react24.useState)([]);
3838
+ const [loading, setLoading] = (0, import_react24.useState)(true);
3839
+ const [anchorEl, setAnchorEl] = (0, import_react24.useState)(null);
3840
+ const open = Boolean(anchorEl);
3841
+ (0, import_react24.useEffect)(() => {
3842
+ const fetchLanguages = async () => {
3843
+ try {
3844
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
3845
+ if (error) throw error;
3846
+ setLanguages(data || []);
3847
+ } catch (err) {
3848
+ console.error("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u043C\u043E\u0432:", err);
3849
+ } finally {
3850
+ setLoading(false);
3851
+ }
3852
+ };
3853
+ fetchLanguages();
3854
+ }, []);
3855
+ const handleClick = (event) => {
3856
+ setAnchorEl(event.currentTarget);
3857
+ };
3858
+ const handleClose = () => {
3859
+ setAnchorEl(null);
3860
+ };
3861
+ const handleSelectLanguage = (langCode) => {
3862
+ changeLanguage(langCode);
3863
+ handleClose();
3864
+ };
3865
+ if (loading) {
3866
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
3867
+ }
3868
+ const rawCurrentLang = i18n2.language || "uk";
3869
+ const currentLangCode = rawCurrentLang.split("-")[0];
3870
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
3871
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
3872
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.Tooltip, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3873
+ import_material17.IconButton,
3874
+ {
3875
+ onClick: handleClick,
3876
+ size: "small",
3877
+ "aria-controls": open ? "language-menu" : void 0,
3878
+ "aria-haspopup": "true",
3879
+ "aria-expanded": open ? "true" : void 0,
3880
+ sx: {
3881
+ p: 1,
3882
+ borderRadius: 2,
3883
+ transition: "background-color 0.2s",
3884
+ "&:hover": {
3885
+ backgroundColor: "action.hover"
3886
+ }
3887
+ },
3888
+ children: currentLang?.svg_flag && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3889
+ import_material17.Box,
3890
+ {
3891
+ sx: {
3892
+ width: 24,
3893
+ height: 16,
3894
+ borderRadius: "3px",
3895
+ overflow: "hidden",
3896
+ flexShrink: 0,
3897
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
3898
+ display: "flex",
3899
+ alignItems: "center",
3900
+ justifyContent: "center",
3901
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
3902
+ },
3903
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
3904
+ }
3905
+ )
3906
+ }
3907
+ ) }),
3908
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3909
+ import_material17.Menu,
3910
+ {
3911
+ id: "language-menu",
3912
+ anchorEl,
3913
+ open,
3914
+ onClose: handleClose,
3915
+ slotProps: {
3916
+ paper: {
3917
+ elevation: 3,
3918
+ sx: {
3919
+ mt: 1,
3920
+ minWidth: 150,
3921
+ borderRadius: 2
3922
+ }
3923
+ }
3924
+ },
3925
+ transformOrigin: { horizontal: "right", vertical: "top" },
3926
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
3927
+ children: languages.map((lang) => {
3928
+ const isSelected = lang.code === currentLangCode;
3929
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
3930
+ import_material17.MenuItem,
3931
+ {
3932
+ selected: isSelected,
3933
+ onClick: () => handleSelectLanguage(lang.code),
3934
+ sx: {
3935
+ display: "flex",
3936
+ alignItems: "center",
3937
+ gap: 1.5,
3938
+ py: 1,
3939
+ px: 2
3940
+ },
3941
+ children: [
3942
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
3943
+ import_material17.Box,
3944
+ {
3945
+ sx: {
3946
+ width: 22,
3947
+ height: 15,
3948
+ borderRadius: "2px",
3949
+ overflow: "hidden",
3950
+ flexShrink: 0,
3951
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
3952
+ "& svg": { width: "100%", height: "100%", display: "block" }
3953
+ },
3954
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
3955
+ }
3956
+ ),
3957
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material17.Typography, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
3958
+ ]
3959
+ },
3960
+ lang.code
3961
+ );
3962
+ })
3963
+ }
3964
+ )
3965
+ ] });
3966
+ };
3967
+
3968
+ // src/UI/index.ts
3455
3969
  var UI = {
3456
3970
  Inputs: {
3457
3971
  TextField: TextFieldComponent,
@@ -3467,16 +3981,35 @@ var UI = {
3467
3981
  UserAvatar: UserAvatarComponent,
3468
3982
  UserPopover: UserPopoverComponent_default,
3469
3983
  UserRoleChip: UserRoleChipComponent,
3470
- UserStatusChip: UserStatusChipComponent
3471
- }
3984
+ UserStatusChip: UserStatusChipComponent,
3985
+ MyAvatar: MyAvatarComponent
3986
+ },
3472
3987
  /*Layout: {
3473
3988
  Row: FormRow,
3474
3989
  },*/
3990
+ Widgets: {
3991
+ ProtectedLanguageSelector: LanguageSelector,
3992
+ PublicLanguageSelector
3993
+ }
3475
3994
  };
3476
3995
 
3477
3996
  // src/index.ts
3478
3997
  init_context();
3479
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
+ };
3480
4013
  // Annotate the CommonJS export names for ESM import in node:
3481
4014
  0 && (module.exports = {
3482
4015
  AIProvider,
@@ -3486,6 +4019,7 @@ init_context();
3486
4019
  ConfirmationProvider,
3487
4020
  LocalizationProvider,
3488
4021
  Providers,
4022
+ Services,
3489
4023
  SupabaseProvider,
3490
4024
  ThemeProvider,
3491
4025
  ToastProvider,