@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.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-BAFKGCJJ.mjs";
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-64KAMDBO.mjs"));
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(" ");
@@ -844,6 +851,401 @@ var UserAvatarComponent = ({
844
851
  ] });
845
852
  };
846
853
 
854
+ // src/UI/components/data.display/MyAvatarComponent.tsx
855
+ import { useState as useState6 } from "react";
856
+ import { Avatar as Avatar2, Box as Box4, Popover as Popover2, Typography as Typography3, Skeleton } from "@mui/material";
857
+ import { Fragment as Fragment5, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
858
+ var getInitials2 = (name) => {
859
+ if (!name) return "?";
860
+ const parts = name.trim().split(" ");
861
+ if (parts.length >= 2) {
862
+ return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
863
+ }
864
+ return name[0].toUpperCase();
865
+ };
866
+ var MyAvatarComponent = ({
867
+ size = 40,
868
+ disableBorder = false,
869
+ disableShadow = false,
870
+ disablePopover = false,
871
+ sx = {}
872
+ }) => {
873
+ const { profile: userProfile, loading: isLoading } = useAuth();
874
+ const [anchorEl, setAnchorEl] = useState6(null);
875
+ const handlePopoverOpen = (event) => {
876
+ if (!disablePopover) {
877
+ setAnchorEl(event.currentTarget);
878
+ }
879
+ };
880
+ const handlePopoverClose = () => {
881
+ setAnchorEl(null);
882
+ };
883
+ const isPopoverOpen = Boolean(anchorEl);
884
+ if (isLoading) {
885
+ return /* @__PURE__ */ jsx6(
886
+ Skeleton,
887
+ {
888
+ variant: "circular",
889
+ width: size,
890
+ height: size,
891
+ sx: { display: "inline-block", flexShrink: 0, ...sx }
892
+ }
893
+ );
894
+ }
895
+ const initials = getInitials2(userProfile?.display_name || "");
896
+ return /* @__PURE__ */ jsxs5(Fragment5, { children: [
897
+ /* @__PURE__ */ jsx6(
898
+ Avatar2,
899
+ {
900
+ src: userProfile?.avatar_url || void 0,
901
+ alt: userProfile?.display_name || "User Avatar",
902
+ onMouseEnter: handlePopoverOpen,
903
+ onMouseLeave: handlePopoverClose,
904
+ sx: {
905
+ width: size,
906
+ height: size,
907
+ fontSize: size * 0.4,
908
+ fontWeight: 600,
909
+ bgcolor: "primary.main",
910
+ color: "primary.contrastText",
911
+ cursor: disablePopover ? void 0 : "pointer",
912
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
913
+ border: disableBorder ? "none" : "2px solid",
914
+ borderColor: "background.paper",
915
+ boxShadow: disableShadow ? "none" : 2,
916
+ "&:hover": {
917
+ transform: disablePopover ? "none" : "scale(1.05)"
918
+ },
919
+ ...sx
920
+ },
921
+ children: !userProfile?.avatar_url && initials
922
+ }
923
+ ),
924
+ !disablePopover && /* @__PURE__ */ jsx6(
925
+ Popover2,
926
+ {
927
+ id: `avatar-popover-${userProfile?.id}`,
928
+ open: isPopoverOpen,
929
+ anchorEl,
930
+ anchorOrigin: {
931
+ vertical: "bottom",
932
+ horizontal: "center"
933
+ },
934
+ transformOrigin: {
935
+ vertical: "top",
936
+ horizontal: "center"
937
+ },
938
+ onClose: handlePopoverClose,
939
+ disableRestoreFocus: true,
940
+ disableAutoFocus: true,
941
+ disableEnforceFocus: true,
942
+ sx: {
943
+ pointerEvents: "none",
944
+ mt: 1
945
+ },
946
+ slotProps: {
947
+ paper: {
948
+ sx: {
949
+ p: 1.5,
950
+ borderRadius: 2,
951
+ boxShadow: 3
952
+ }
953
+ }
954
+ },
955
+ children: /* @__PURE__ */ jsxs5(Box4, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 0.5 }, children: [
956
+ /* @__PURE__ */ jsx6(Typography3, { variant: "subtitle2", sx: { fontWeight: 600 }, children: userProfile?.display_name }),
957
+ userProfile?.email && /* @__PURE__ */ jsx6(Typography3, { variant: "caption", color: "text.secondary", children: userProfile.email })
958
+ ] })
959
+ }
960
+ )
961
+ ] });
962
+ };
963
+
964
+ // src/i18n/LanguageSelector.tsx
965
+ import { useEffect as useEffect3, useState as useState7 } from "react";
966
+ import { useTranslation as useTranslation2 } from "react-i18next";
967
+ import {
968
+ Box as Box5,
969
+ Typography as Typography4,
970
+ CircularProgress,
971
+ IconButton as IconButton4,
972
+ Menu,
973
+ MenuItem,
974
+ Tooltip as Tooltip4
975
+ } from "@mui/material";
976
+ import { Fragment as Fragment6, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
977
+ var LanguageSelector = () => {
978
+ const supabase = useSupabase();
979
+ const { i18n } = useTranslation2();
980
+ const [languages, setLanguages] = useState7([]);
981
+ const [loading, setLoading] = useState7(true);
982
+ const { changeLanguage } = useLocalization();
983
+ const { settings: userSettings, setLanguage } = useUserSettings();
984
+ const [anchorEl, setAnchorEl] = useState7(null);
985
+ const open = Boolean(anchorEl);
986
+ useEffect3(() => {
987
+ const fetchLanguages = async () => {
988
+ try {
989
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
990
+ if (error) throw error;
991
+ setLanguages(data || []);
992
+ if (userSettings.language) changeLanguage(userSettings.language);
993
+ } catch (err) {
994
+ 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);
995
+ } finally {
996
+ setLoading(false);
997
+ }
998
+ };
999
+ fetchLanguages();
1000
+ }, []);
1001
+ const handleClick = (event) => {
1002
+ setAnchorEl(event.currentTarget);
1003
+ };
1004
+ const handleClose = () => {
1005
+ setAnchorEl(null);
1006
+ };
1007
+ const handleSelectLanguage = (langCode) => {
1008
+ changeLanguage(langCode);
1009
+ setLanguage(langCode);
1010
+ handleClose();
1011
+ };
1012
+ if (loading) {
1013
+ return /* @__PURE__ */ jsx7(CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
1014
+ }
1015
+ const rawCurrentLang = i18n.language || "uk";
1016
+ const currentLangCode = rawCurrentLang.split("-")[0];
1017
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
1018
+ return /* @__PURE__ */ jsxs6(Fragment6, { children: [
1019
+ /* @__PURE__ */ jsx7(Tooltip4, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ jsx7(
1020
+ IconButton4,
1021
+ {
1022
+ onClick: handleClick,
1023
+ size: "small",
1024
+ "aria-controls": open ? "language-menu" : void 0,
1025
+ "aria-haspopup": "true",
1026
+ "aria-expanded": open ? "true" : void 0,
1027
+ sx: {
1028
+ p: 1,
1029
+ borderRadius: 2,
1030
+ transition: "background-color 0.2s",
1031
+ "&:hover": {
1032
+ backgroundColor: "action.hover"
1033
+ }
1034
+ },
1035
+ children: currentLang?.svg_flag && /* @__PURE__ */ jsx7(
1036
+ Box5,
1037
+ {
1038
+ sx: {
1039
+ width: 24,
1040
+ height: 16,
1041
+ borderRadius: "3px",
1042
+ overflow: "hidden",
1043
+ flexShrink: 0,
1044
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
1045
+ display: "flex",
1046
+ alignItems: "center",
1047
+ justifyContent: "center",
1048
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
1049
+ },
1050
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
1051
+ }
1052
+ )
1053
+ }
1054
+ ) }),
1055
+ /* @__PURE__ */ jsx7(
1056
+ Menu,
1057
+ {
1058
+ id: "language-menu",
1059
+ anchorEl,
1060
+ open,
1061
+ onClose: handleClose,
1062
+ slotProps: {
1063
+ paper: {
1064
+ elevation: 3,
1065
+ sx: {
1066
+ mt: 1,
1067
+ minWidth: 150,
1068
+ borderRadius: 2
1069
+ }
1070
+ }
1071
+ },
1072
+ transformOrigin: { horizontal: "right", vertical: "top" },
1073
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
1074
+ children: languages.map((lang) => {
1075
+ const isSelected = lang.code === currentLangCode;
1076
+ return /* @__PURE__ */ jsxs6(
1077
+ MenuItem,
1078
+ {
1079
+ selected: isSelected,
1080
+ onClick: () => handleSelectLanguage(lang.code),
1081
+ sx: {
1082
+ display: "flex",
1083
+ alignItems: "center",
1084
+ gap: 1.5,
1085
+ py: 1,
1086
+ px: 2
1087
+ },
1088
+ children: [
1089
+ /* @__PURE__ */ jsx7(
1090
+ Box5,
1091
+ {
1092
+ sx: {
1093
+ width: 22,
1094
+ height: 15,
1095
+ borderRadius: "2px",
1096
+ overflow: "hidden",
1097
+ flexShrink: 0,
1098
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
1099
+ "& svg": { width: "100%", height: "100%", display: "block" }
1100
+ },
1101
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
1102
+ }
1103
+ ),
1104
+ /* @__PURE__ */ jsx7(Typography4, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
1105
+ ]
1106
+ },
1107
+ lang.code
1108
+ );
1109
+ })
1110
+ }
1111
+ )
1112
+ ] });
1113
+ };
1114
+ var PublicLanguageSelector = () => {
1115
+ const supabase = useSupabase();
1116
+ const { i18n } = useTranslation2();
1117
+ const { changeLanguage } = useLocalization();
1118
+ const [languages, setLanguages] = useState7([]);
1119
+ const [loading, setLoading] = useState7(true);
1120
+ const [anchorEl, setAnchorEl] = useState7(null);
1121
+ const open = Boolean(anchorEl);
1122
+ useEffect3(() => {
1123
+ const fetchLanguages = async () => {
1124
+ try {
1125
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
1126
+ if (error) throw error;
1127
+ setLanguages(data || []);
1128
+ } catch (err) {
1129
+ 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);
1130
+ } finally {
1131
+ setLoading(false);
1132
+ }
1133
+ };
1134
+ fetchLanguages();
1135
+ }, []);
1136
+ const handleClick = (event) => {
1137
+ setAnchorEl(event.currentTarget);
1138
+ };
1139
+ const handleClose = () => {
1140
+ setAnchorEl(null);
1141
+ };
1142
+ const handleSelectLanguage = (langCode) => {
1143
+ changeLanguage(langCode);
1144
+ handleClose();
1145
+ };
1146
+ if (loading) {
1147
+ return /* @__PURE__ */ jsx7(CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
1148
+ }
1149
+ const rawCurrentLang = i18n.language || "uk";
1150
+ const currentLangCode = rawCurrentLang.split("-")[0];
1151
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
1152
+ return /* @__PURE__ */ jsxs6(Fragment6, { children: [
1153
+ /* @__PURE__ */ jsx7(Tooltip4, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ jsx7(
1154
+ IconButton4,
1155
+ {
1156
+ onClick: handleClick,
1157
+ size: "small",
1158
+ "aria-controls": open ? "language-menu" : void 0,
1159
+ "aria-haspopup": "true",
1160
+ "aria-expanded": open ? "true" : void 0,
1161
+ sx: {
1162
+ p: 1,
1163
+ borderRadius: 2,
1164
+ transition: "background-color 0.2s",
1165
+ "&:hover": {
1166
+ backgroundColor: "action.hover"
1167
+ }
1168
+ },
1169
+ children: currentLang?.svg_flag && /* @__PURE__ */ jsx7(
1170
+ Box5,
1171
+ {
1172
+ sx: {
1173
+ width: 24,
1174
+ height: 16,
1175
+ borderRadius: "3px",
1176
+ overflow: "hidden",
1177
+ flexShrink: 0,
1178
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
1179
+ display: "flex",
1180
+ alignItems: "center",
1181
+ justifyContent: "center",
1182
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
1183
+ },
1184
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
1185
+ }
1186
+ )
1187
+ }
1188
+ ) }),
1189
+ /* @__PURE__ */ jsx7(
1190
+ Menu,
1191
+ {
1192
+ id: "language-menu",
1193
+ anchorEl,
1194
+ open,
1195
+ onClose: handleClose,
1196
+ slotProps: {
1197
+ paper: {
1198
+ elevation: 3,
1199
+ sx: {
1200
+ mt: 1,
1201
+ minWidth: 150,
1202
+ borderRadius: 2
1203
+ }
1204
+ }
1205
+ },
1206
+ transformOrigin: { horizontal: "right", vertical: "top" },
1207
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
1208
+ children: languages.map((lang) => {
1209
+ const isSelected = lang.code === currentLangCode;
1210
+ return /* @__PURE__ */ jsxs6(
1211
+ MenuItem,
1212
+ {
1213
+ selected: isSelected,
1214
+ onClick: () => handleSelectLanguage(lang.code),
1215
+ sx: {
1216
+ display: "flex",
1217
+ alignItems: "center",
1218
+ gap: 1.5,
1219
+ py: 1,
1220
+ px: 2
1221
+ },
1222
+ children: [
1223
+ /* @__PURE__ */ jsx7(
1224
+ Box5,
1225
+ {
1226
+ sx: {
1227
+ width: 22,
1228
+ height: 15,
1229
+ borderRadius: "2px",
1230
+ overflow: "hidden",
1231
+ flexShrink: 0,
1232
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
1233
+ "& svg": { width: "100%", height: "100%", display: "block" }
1234
+ },
1235
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
1236
+ }
1237
+ ),
1238
+ /* @__PURE__ */ jsx7(Typography4, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
1239
+ ]
1240
+ },
1241
+ lang.code
1242
+ );
1243
+ })
1244
+ }
1245
+ )
1246
+ ] });
1247
+ };
1248
+
847
1249
  // src/UI/index.ts
848
1250
  var UI = {
849
1251
  Inputs: {
@@ -860,11 +1262,29 @@ var UI = {
860
1262
  UserAvatar: UserAvatarComponent,
861
1263
  UserPopover: UserPopoverComponent_default,
862
1264
  UserRoleChip: UserRoleChipComponent,
863
- UserStatusChip: UserStatusChipComponent
864
- }
1265
+ UserStatusChip: UserStatusChipComponent,
1266
+ MyAvatar: MyAvatarComponent
1267
+ },
865
1268
  /*Layout: {
866
1269
  Row: FormRow,
867
1270
  },*/
1271
+ Widgets: {
1272
+ ProtectedLanguageSelector: LanguageSelector,
1273
+ PublicLanguageSelector
1274
+ }
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
+ }
868
1288
  };
869
1289
  export {
870
1290
  AIProvider,
@@ -874,6 +1294,7 @@ export {
874
1294
  ConfirmationProvider,
875
1295
  LocalizationProvider,
876
1296
  Providers,
1297
+ Services,
877
1298
  SupabaseProvider,
878
1299
  ThemeProvider,
879
1300
  ToastProvider,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serhii.olishevskyi/docs",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "DOCS.UA react packages",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",