@serhii.olishevskyi/docs 1.2.23 → 1.2.25

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
@@ -15,7 +15,7 @@ import {
15
15
  TranslateText,
16
16
  TranslationDialog,
17
17
  TranslationEditProvider,
18
- UserPopoverComponent_default,
18
+ UserPopoverComponent,
19
19
  UserRoleChipComponent,
20
20
  UserSettingsProvider,
21
21
  UserStatusChipComponent,
@@ -43,7 +43,7 @@ import {
43
43
  useTranslationEdit,
44
44
  useTranslationNamespace,
45
45
  useUserSettings
46
- } from "./chunk-4NEOJ5KZ.mjs";
46
+ } from "./chunk-VFNVP7VE.mjs";
47
47
 
48
48
  // src/UI/components/inputs/TextFieldComponent.tsx
49
49
  import { useState } from "react";
@@ -477,208 +477,9 @@ var NumberInputComponent = ({
477
477
  );
478
478
  };
479
479
 
480
- // src/UI/components/inputs/UrlComponent.tsx
481
- import { useState as useState3 } from "react";
482
- import {
483
- TextField as TextField2,
484
- InputAdornment as InputAdornment3,
485
- IconButton as IconButton3,
486
- Tooltip as Tooltip2,
487
- Popover,
488
- Box as Box3,
489
- Typography,
490
- Button
491
- } from "@mui/material";
492
- import LinkIcon from "@mui/icons-material/Link";
493
- import LaunchIcon from "@mui/icons-material/Launch";
494
- import ContentCopyIcon2 from "@mui/icons-material/ContentCopy";
495
- import CheckIcon2 from "@mui/icons-material/Check";
496
- import EditNoteIcon from "@mui/icons-material/EditNote";
497
- import LockIcon2 from "@mui/icons-material/Lock";
498
- import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
499
- function UrlComponent({
500
- overrideNamespace,
501
- label,
502
- value,
503
- onChange,
504
- disabled = false,
505
- readOnly = false,
506
- required = false,
507
- error = false,
508
- helperText = "",
509
- description = "",
510
- fullWidth = true,
511
- openInNewTab = true,
512
- showLock = true,
513
- lockTooltip = "Field is not editable",
514
- sx
515
- }) {
516
- const [copied, setCopied] = useState3(false);
517
- const [anchorEl, setAnchorEl] = useState3(null);
518
- const isViewMode = disabled || readOnly;
519
- const currentUrl = typeof value === "object" && value !== null ? value.url || "" : value || "";
520
- const currentTitle = typeof value === "object" && value !== null ? value.title || "" : "";
521
- const getFormattedUrl = (val) => {
522
- if (!val) return "";
523
- const trimmed = val.trim();
524
- if (trimmed.match(/^[a-zA-Z]+:\/\//)) {
525
- return trimmed;
526
- }
527
- return `https://${trimmed}`;
528
- };
529
- const finalUrl = getFormattedUrl(currentUrl);
530
- const targetAttribute = openInNewTab ? "_blank" : "_self";
531
- const displayLabelText = currentTitle.trim() || currentUrl;
532
- const handleUrlChange = (newUrl) => {
533
- onChange?.({ url: newUrl, title: currentTitle });
534
- };
535
- const handleTitleChange = (newTitle) => {
536
- onChange?.({ url: currentUrl, title: newTitle });
537
- };
538
- const handleCopy = (e) => {
539
- e.stopPropagation();
540
- if (!finalUrl) return;
541
- navigator.clipboard.writeText(finalUrl);
542
- setCopied(true);
543
- setTimeout(() => setCopied(false), 2e3);
544
- };
545
- const handleOpenLink = (e) => {
546
- e.stopPropagation();
547
- if (finalUrl) {
548
- window.open(finalUrl, targetAttribute, openInNewTab ? "noopener,noreferrer" : void 0);
549
- }
550
- };
551
- const handleInputClick = (e) => {
552
- if (isViewMode && finalUrl) {
553
- handleOpenLink(e);
554
- }
555
- };
556
- const handleOpenTitleMenu = (e) => {
557
- e.stopPropagation();
558
- setAnchorEl(e.currentTarget);
559
- };
560
- const handleCloseTitleMenu = () => {
561
- setAnchorEl(null);
562
- };
563
- const isTitlePopoverOpen = Boolean(anchorEl);
564
- const displayHelperText = error ? helperText : description || helperText;
565
- return /* @__PURE__ */ jsxs3(Fragment3, { children: [
566
- /* @__PURE__ */ jsx3(
567
- TextField2,
568
- {
569
- label: /* @__PURE__ */ jsx3(TranslateText, { overrideNamespace, children: label }),
570
- type: isViewMode ? "text" : "url",
571
- value: isViewMode ? displayLabelText : currentUrl,
572
- onChange: (e) => handleUrlChange(e.target.value),
573
- required,
574
- error,
575
- disabled,
576
- margin: "dense",
577
- helperText: displayHelperText,
578
- fullWidth,
579
- placeholder: "example.com",
580
- sx: {
581
- "& .MuiInputLabel-asterisk": {
582
- color: "red",
583
- fontSize: "1.5rem"
584
- },
585
- "& .MuiInputBase-input": {
586
- color: isViewMode && finalUrl ? "primary.main" : void 0,
587
- textDecoration: isViewMode && finalUrl ? "underline" : "none",
588
- cursor: isViewMode && finalUrl ? "pointer" : void 0,
589
- fontWeight: isViewMode && finalUrl ? 500 : void 0
590
- },
591
- ...sx
592
- },
593
- slotProps: {
594
- htmlInput: {
595
- readOnly,
596
- onClick: handleInputClick
597
- },
598
- input: {
599
- startAdornment: /* @__PURE__ */ jsx3(InputAdornment3, { position: "start", children: /* @__PURE__ */ jsx3(LinkIcon, { fontSize: "small", color: isViewMode && finalUrl ? "primary" : "action" }) }),
600
- endAdornment: /* @__PURE__ */ jsxs3(InputAdornment3, { position: "end", sx: { gap: 0.5 }, children: [
601
- !isViewMode && /* @__PURE__ */ jsx3(Tooltip2, { title: currentTitle ? `Title: "${currentTitle}"` : /* @__PURE__ */ jsx3(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Set link title" }), children: /* @__PURE__ */ jsx3(
602
- IconButton3,
603
- {
604
- size: "small",
605
- onClick: handleOpenTitleMenu,
606
- color: currentTitle ? "primary" : "default",
607
- children: /* @__PURE__ */ jsx3(EditNoteIcon, { fontSize: "small" })
608
- }
609
- ) }),
610
- finalUrl && /* @__PURE__ */ jsx3(Tooltip2, { title: copied ? /* @__PURE__ */ jsx3(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Copied!" }) : /* @__PURE__ */ jsx3(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Copy link" }), children: /* @__PURE__ */ jsx3(IconButton3, { size: "small", onClick: handleCopy, color: copied ? "success" : "default", children: copied ? /* @__PURE__ */ jsx3(CheckIcon2, { fontSize: "small" }) : /* @__PURE__ */ jsx3(ContentCopyIcon2, { fontSize: "small" }) }) }),
611
- isViewMode && showLock && /* @__PURE__ */ jsx3(Tooltip2, { title: /* @__PURE__ */ jsx3(TranslateText, { overrideNamespace, children: lockTooltip }), children: /* @__PURE__ */ jsx3(
612
- IconButton3,
613
- {
614
- size: "small",
615
- disabled: true,
616
- edge: "end",
617
- "aria-label": "locked input",
618
- sx: {
619
- "&.Mui-disabled": {
620
- color: "text.secondary"
621
- }
622
- },
623
- children: /* @__PURE__ */ jsx3(LockIcon2, { fontSize: "small" })
624
- }
625
- ) }),
626
- finalUrl && /* @__PURE__ */ jsx3(Tooltip2, { title: /* @__PURE__ */ jsx3(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Open link" }), children: /* @__PURE__ */ jsx3(IconButton3, { size: "small", onClick: handleOpenLink, children: /* @__PURE__ */ jsx3(LaunchIcon, { fontSize: "small", color: isViewMode ? "primary" : "action" }) }) })
627
- ] })
628
- }
629
- }
630
- }
631
- ),
632
- /* @__PURE__ */ jsxs3(
633
- Popover,
634
- {
635
- open: isTitlePopoverOpen,
636
- anchorEl,
637
- onClose: handleCloseTitleMenu,
638
- anchorOrigin: {
639
- vertical: "bottom",
640
- horizontal: "right"
641
- },
642
- transformOrigin: {
643
- vertical: "top",
644
- horizontal: "right"
645
- },
646
- slotProps: {
647
- paper: { sx: { p: 2, width: 280 } }
648
- },
649
- children: [
650
- /* @__PURE__ */ jsx3(Typography, { variant: "subtitle2", sx: { mb: 1, fontWeight: "bold" }, children: /* @__PURE__ */ jsx3(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Link Title (Anchor)" }) }),
651
- /* @__PURE__ */ jsxs3(Typography, { variant: "caption", color: "text.secondary", sx: { mb: 1.5, display: "block" }, children: [
652
- /* @__PURE__ */ jsx3(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Specify the text to display instead of the URL address" }),
653
- ":"
654
- ] }),
655
- /* @__PURE__ */ jsx3(
656
- TextField2,
657
- {
658
- size: "small",
659
- fullWidth: true,
660
- placeholder: "e.g. Instruction",
661
- value: currentTitle,
662
- onChange: (e) => handleTitleChange(e.target.value),
663
- autoFocus: true,
664
- onKeyDown: (e) => {
665
- if (e.key === "Enter") {
666
- e.preventDefault();
667
- handleCloseTitleMenu();
668
- }
669
- }
670
- }
671
- ),
672
- /* @__PURE__ */ jsx3(Box3, { sx: { display: "flex", justifyContent: "flex-end", mt: 1.5 }, children: /* @__PURE__ */ jsx3(Button, { size: "small", variant: "contained", onClick: handleCloseTitleMenu, children: /* @__PURE__ */ jsx3(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Done" }) }) })
673
- ]
674
- }
675
- )
676
- ] });
677
- }
678
-
679
480
  // src/UI/components/inputs/EmailInputComponent.tsx
680
- import { useState as useState4 } from "react";
681
- import { jsx as jsx4 } from "react/jsx-runtime";
481
+ import { useState as useState3 } from "react";
482
+ import { jsx as jsx3 } from "react/jsx-runtime";
682
483
  var EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
683
484
  var EmailInputComponent = ({
684
485
  value = "",
@@ -691,7 +492,7 @@ var EmailInputComponent = ({
691
492
  onValidationChange,
692
493
  ...props
693
494
  }) => {
694
- const [internalError, setInternalError] = useState4(null);
495
+ const [internalError, setInternalError] = useState3(null);
695
496
  const validateEmail = (val) => {
696
497
  if (disableValidation) return true;
697
498
  const stringVal = String(val ?? "").trim();
@@ -723,7 +524,7 @@ var EmailInputComponent = ({
723
524
  };
724
525
  const hasError = Boolean(externalError || internalError);
725
526
  const displayHelperText = externalHelperText || internalError || void 0;
726
- return /* @__PURE__ */ jsx4(
527
+ return /* @__PURE__ */ jsx3(
727
528
  TextFieldComponent,
728
529
  {
729
530
  type: "email",
@@ -737,942 +538,1560 @@ var EmailInputComponent = ({
737
538
  );
738
539
  };
739
540
 
740
- // src/UI/components/data.display/UserAvatarComponent.tsx
741
- import { useState as useState5, useEffect as useEffect2, lazy, Suspense } from "react";
742
- import { Avatar, Tooltip as Tooltip3, Typography as Typography2 } from "@mui/material";
743
- import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
744
- var LazyUserPopover = lazy(() => import("./UserPopoverComponent-RAEPOSIE.mjs"));
745
- var getInitials = (name) => {
746
- if (!name) return "?";
747
- const parts = name.trim().split(" ");
748
- if (parts.length >= 2) {
749
- return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
750
- }
751
- return name[0].toUpperCase();
752
- };
753
- var UserAvatarComponent = ({
754
- userId = "",
755
- avatarUrl = "",
756
- displayName = "",
757
- employeePost = "",
758
- size = 40,
759
- disableBorder = false,
760
- disableShadow = false,
761
- disablePopover = false,
762
- disableTooltip = false,
763
- sx = {}
764
- }) => {
765
- const supabase = useSupabase();
766
- const [anchorEl, setAnchorEl] = useState5(null);
767
- const [hasInteracted, setHasInteracted] = useState5(false);
768
- const [resolvedAvatarUrl, setResolvedAvatarUrl] = useState5(null);
769
- const canShowPopover = !disablePopover && Boolean(userId);
541
+ // src/UI/components/inputs/SearchComponent.tsx
542
+ import { useState as useState5, useEffect as useEffect3 } from "react";
543
+ import { useTranslation as useTranslation2 } from "react-i18next";
544
+ import { TextField as TextField2, InputAdornment as InputAdornment3, IconButton as IconButton3, Tooltip as Tooltip2 } from "@mui/material";
545
+ import TranslateIcon2 from "@mui/icons-material/Translate";
546
+ import ClearIcon2 from "@mui/icons-material/Clear";
547
+
548
+ // src/hooks/useDebounce.ts
549
+ import { useEffect as useEffect2, useState as useState4 } from "react";
550
+ function useDebounce(value, delay = 500) {
551
+ const [debouncedValue, setDebouncedValue] = useState4(value);
770
552
  useEffect2(() => {
771
- let isMounted = true;
772
- const resolveAvatar = async () => {
773
- if (!avatarUrl) {
774
- if (isMounted) setResolvedAvatarUrl(null);
775
- return;
776
- }
777
- if (!avatarUrl.startsWith("http") && !avatarUrl.startsWith("data:")) {
778
- try {
779
- const { data } = await supabase.storage.from("user-media").createSignedUrl(avatarUrl, 3600);
780
- if (isMounted) {
781
- setResolvedAvatarUrl(data?.signedUrl || null);
782
- }
783
- } catch (err) {
784
- console.error("Error resolving signed url for avatar:", err);
785
- if (isMounted) setResolvedAvatarUrl(null);
786
- }
787
- } else {
788
- if (isMounted) setResolvedAvatarUrl(avatarUrl);
789
- }
790
- };
791
- resolveAvatar();
553
+ const timer = setTimeout(() => {
554
+ setDebouncedValue(value);
555
+ }, delay);
792
556
  return () => {
793
- isMounted = false;
557
+ clearTimeout(timer);
794
558
  };
795
- }, [avatarUrl]);
796
- const handleClick = (event) => {
797
- event.stopPropagation();
798
- event.preventDefault();
799
- if (canShowPopover) {
800
- setAnchorEl(event.currentTarget);
801
- if (!hasInteracted) {
802
- setHasInteracted(true);
803
- }
804
- }
805
- };
806
- const handleClose = (event) => {
807
- if (event) {
808
- event.stopPropagation();
809
- event.preventDefault();
810
- }
811
- setAnchorEl(null);
812
- };
813
- const isPopoverOpen = Boolean(anchorEl);
814
- const initials = getInitials(displayName || "");
815
- const getTooltip = /* @__PURE__ */ jsxs4(Fragment4, { children: [
816
- /* @__PURE__ */ jsx5(Typography2, { component: "div", variant: "caption", children: displayName }),
817
- displayName && employeePost && /* @__PURE__ */ jsx5(Typography2, { component: "div", variant: "caption", children: employeePost })
818
- ] });
819
- return /* @__PURE__ */ jsxs4(Fragment4, { children: [
820
- /* @__PURE__ */ jsx5(Tooltip3, { title: disableTooltip || isPopoverOpen ? "" : getTooltip, children: /* @__PURE__ */ jsx5(
821
- Avatar,
822
- {
823
- src: resolvedAvatarUrl || void 0,
824
- alt: displayName || "User Avatar",
825
- onClick: handleClick,
826
- sx: {
827
- width: size,
828
- height: size,
829
- fontSize: size * 0.4,
830
- fontWeight: 600,
831
- bgcolor: "primary.main",
832
- color: "primary.contrastText",
833
- cursor: canShowPopover ? "pointer" : void 0,
834
- transition: "transform 0.2s ease, box-shadow 0.2s ease",
835
- border: disableBorder ? "none" : "2px solid",
836
- borderColor: "background.paper",
837
- boxShadow: disableShadow ? "none" : 2,
838
- "&:hover": {
839
- transform: canShowPopover ? "scale(1.05)" : "none"
840
- },
841
- ...sx
842
- },
843
- children: !resolvedAvatarUrl && initials
844
- }
845
- ) }),
846
- canShowPopover && hasInteracted && /* @__PURE__ */ jsx5(Suspense, { fallback: null, children: /* @__PURE__ */ jsx5(
847
- LazyUserPopover,
848
- {
849
- userId,
850
- anchorEl,
851
- open: isPopoverOpen,
852
- onClose: handleClose
853
- }
854
- ) })
855
- ] });
856
- };
559
+ }, [value, delay]);
560
+ return debouncedValue;
561
+ }
857
562
 
858
- // src/UI/components/data.display/MyAvatarComponent.tsx
859
- import { useState as useState6 } from "react";
860
- import { Avatar as Avatar2, Box as Box4, Popover as Popover2, Typography as Typography3, Skeleton } from "@mui/material";
861
- import { Fragment as Fragment5, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
862
- var getInitials2 = (name) => {
863
- if (!name) return "?";
864
- const parts = name.trim().split(" ");
865
- if (parts.length >= 2) {
866
- return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
867
- }
868
- return name[0].toUpperCase();
869
- };
870
- var MyAvatarComponent = ({
871
- size = 40,
872
- disableBorder = false,
873
- disableShadow = false,
874
- disablePopover = false,
875
- sx = {}
563
+ // src/UI/components/inputs/SearchComponent.tsx
564
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
565
+ var SearchComponent = ({
566
+ overrideNamespace,
567
+ label = "",
568
+ value = "",
569
+ onChange,
570
+ onClear,
571
+ placeholderKey,
572
+ clearTooltip = "Clear",
573
+ debounceDelay = 500,
574
+ onDebounceChange,
575
+ slotProps,
576
+ ...restProps
876
577
  }) => {
877
- const { profile: userProfile, loading: isLoading } = useAuth();
878
- const [anchorEl, setAnchorEl] = useState6(null);
879
- const handlePopoverOpen = (event) => {
880
- if (!disablePopover) {
881
- setAnchorEl(event.currentTarget);
578
+ const supabase = useSupabase();
579
+ const namespace = useTranslationNamespace();
580
+ const { t, i18n } = useTranslation2(namespace);
581
+ const { isTranslationMode } = useTranslationEdit();
582
+ const [isDialogOpen, setIsDialogOpen] = useState5(false);
583
+ const [localValue, setLocalValue] = useState5(String(value ?? ""));
584
+ const debouncedValue = useDebounce(localValue, debounceDelay);
585
+ useEffect3(() => {
586
+ setLocalValue(String(value ?? ""));
587
+ }, [value]);
588
+ useEffect3(() => {
589
+ if (onDebounceChange) {
590
+ onDebounceChange(debouncedValue);
591
+ }
592
+ if (onChange && debouncedValue !== String(value ?? "")) {
593
+ const syntheticEvent = {
594
+ target: { value: debouncedValue },
595
+ currentTarget: { value: debouncedValue }
596
+ };
597
+ onChange(syntheticEvent);
882
598
  }
599
+ }, [debouncedValue]);
600
+ const hasValue = localValue.length > 0;
601
+ const handleChange = (e) => {
602
+ setLocalValue(e.target.value);
883
603
  };
884
- const handlePopoverClose = () => {
885
- setAnchorEl(null);
604
+ const handleClear = (e) => {
605
+ e.stopPropagation();
606
+ setLocalValue("");
607
+ if (onClear) {
608
+ onClear();
609
+ }
610
+ if (onChange) {
611
+ const syntheticEvent = {
612
+ ...e,
613
+ target: { ...e.target, value: "" },
614
+ currentTarget: { ...e.currentTarget, value: "" }
615
+ };
616
+ onChange(syntheticEvent);
617
+ }
886
618
  };
887
- const isPopoverOpen = Boolean(anchorEl);
888
- if (isLoading) {
889
- return /* @__PURE__ */ jsx6(
890
- Skeleton,
891
- {
892
- variant: "circular",
893
- width: size,
894
- height: size,
895
- sx: { display: "inline-block", flexShrink: 0, ...sx }
896
- }
897
- );
898
- }
899
- const initials = getInitials2(userProfile?.display_name || "");
900
- return /* @__PURE__ */ jsxs5(Fragment5, { children: [
901
- /* @__PURE__ */ jsx6(
902
- Avatar2,
619
+ const translatedPlaceholder = placeholderKey ? t(placeholderKey) : void 0;
620
+ const handleSaveTranslations = async (newValues, contextHint) => {
621
+ if (!placeholderKey) return;
622
+ const upsertData = Object.entries(newValues).map(([langCode, text]) => ({
623
+ lang_code: langCode,
624
+ namespace,
625
+ key: placeholderKey,
626
+ value: text,
627
+ context_hint: contextHint
628
+ }));
629
+ const { error } = await supabase.from("translations").upsert(upsertData, { onConflict: "lang_code,namespace,key" });
630
+ if (error) {
631
+ alert("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u043F\u0456\u0434 \u0447\u0430\u0441 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043D\u044F \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043D\u0438\u0445");
632
+ throw error;
633
+ }
634
+ await translationService.incrementVersion(supabase, namespace, Object.keys(newValues));
635
+ Object.entries(newValues).forEach(([langCode, text]) => {
636
+ i18n.addResource(langCode, namespace, placeholderKey, text);
637
+ });
638
+ };
639
+ const renderEndAdornment = () => {
640
+ const rawInputProps = slotProps?.input;
641
+ const isInputObject = typeof rawInputProps === "object" && rawInputProps !== null;
642
+ const existingEndAdornment = isInputObject && "endAdornment" in rawInputProps ? rawInputProps.endAdornment : void 0;
643
+ if (!hasValue && (!isTranslationMode || !placeholderKey)) {
644
+ return existingEndAdornment;
645
+ }
646
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
647
+ existingEndAdornment,
648
+ /* @__PURE__ */ jsxs3(InputAdornment3, { position: "end", children: [
649
+ hasValue && /* @__PURE__ */ jsx4(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx4(TranslateText, { overrideNamespace, children: clearTooltip }), children: /* @__PURE__ */ jsx4(
650
+ IconButton3,
651
+ {
652
+ size: "small",
653
+ onClick: handleClear,
654
+ edge: "end",
655
+ "aria-label": "clear input",
656
+ children: /* @__PURE__ */ jsx4(ClearIcon2, { fontSize: "small" })
657
+ }
658
+ ) }),
659
+ isTranslationMode && placeholderKey && /* @__PURE__ */ jsx4(Tooltip2, { title: `Translate placeholder: "${placeholderKey}"`, children: /* @__PURE__ */ jsx4(
660
+ IconButton3,
661
+ {
662
+ size: "small",
663
+ onClick: (e) => {
664
+ e.preventDefault();
665
+ e.stopPropagation();
666
+ setIsDialogOpen(true);
667
+ },
668
+ sx: {
669
+ color: "#d97706",
670
+ backgroundColor: "rgba(254, 243, 199, 0.6)",
671
+ border: "1px dashed #f59e0b",
672
+ p: "3px",
673
+ ml: 0.5,
674
+ "&:hover": {
675
+ backgroundColor: "#fef08a"
676
+ }
677
+ },
678
+ children: /* @__PURE__ */ jsx4(TranslateIcon2, { fontSize: "small" })
679
+ }
680
+ ) })
681
+ ] })
682
+ ] });
683
+ };
684
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
685
+ /* @__PURE__ */ jsx4(
686
+ TextField2,
903
687
  {
904
- src: userProfile?.avatar_url || void 0,
905
- alt: userProfile?.display_name || "User Avatar",
906
- onMouseEnter: handlePopoverOpen,
907
- onMouseLeave: handlePopoverClose,
908
- sx: {
909
- width: size,
910
- height: size,
911
- fontSize: size * 0.4,
912
- fontWeight: 600,
913
- bgcolor: "primary.main",
914
- color: "primary.contrastText",
915
- cursor: disablePopover ? void 0 : "pointer",
916
- transition: "transform 0.2s ease, box-shadow 0.2s ease",
917
- border: disableBorder ? "none" : "2px solid",
918
- borderColor: "background.paper",
919
- boxShadow: disableShadow ? "none" : 2,
920
- "&:hover": {
921
- transform: disablePopover ? "none" : "scale(1.05)"
922
- },
923
- ...sx
924
- },
925
- children: !userProfile?.avatar_url && initials
688
+ ...restProps,
689
+ label: typeof label === "string" ? /* @__PURE__ */ jsx4(TranslateText, { overrideNamespace, children: label }) : label,
690
+ value: localValue,
691
+ onChange: handleChange,
692
+ placeholder: translatedPlaceholder,
693
+ slotProps: {
694
+ ...slotProps,
695
+ input: {
696
+ ...slotProps?.input,
697
+ endAdornment: renderEndAdornment()
698
+ }
699
+ }
926
700
  }
927
701
  ),
928
- !disablePopover && /* @__PURE__ */ jsx6(
929
- Popover2,
702
+ placeholderKey && /* @__PURE__ */ jsx4(
703
+ TranslationDialog,
930
704
  {
931
- id: `avatar-popover-${userProfile?.id}`,
932
- open: isPopoverOpen,
933
- anchorEl,
934
- anchorOrigin: {
935
- vertical: "bottom",
936
- horizontal: "center"
937
- },
938
- transformOrigin: {
939
- vertical: "top",
940
- horizontal: "center"
941
- },
942
- onClose: handlePopoverClose,
943
- disableRestoreFocus: true,
944
- disableAutoFocus: true,
945
- disableEnforceFocus: true,
946
- sx: {
947
- pointerEvents: "none",
948
- mt: 1
949
- },
950
- slotProps: {
951
- paper: {
952
- sx: {
953
- p: 1.5,
954
- borderRadius: 2,
955
- boxShadow: 3
956
- }
957
- }
958
- },
959
- children: /* @__PURE__ */ jsxs5(Box4, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 0.5 }, children: [
960
- /* @__PURE__ */ jsx6(Typography3, { variant: "subtitle2", sx: { fontWeight: 600 }, children: userProfile?.display_name }),
961
- userProfile?.email && /* @__PURE__ */ jsx6(Typography3, { variant: "caption", color: "text.secondary", children: userProfile.email })
962
- ] })
705
+ open: isDialogOpen,
706
+ onClose: () => setIsDialogOpen(false),
707
+ translationKey: placeholderKey,
708
+ namespace,
709
+ onSave: handleSaveTranslations
963
710
  }
964
711
  )
965
712
  ] });
966
713
  };
967
714
 
968
- // src/i18n/LanguageSelector.tsx
969
- import { useEffect as useEffect3, useState as useState7 } from "react";
970
- import { useTranslation as useTranslation2 } from "react-i18next";
715
+ // src/UI/components/inputs/SelectComponent.tsx
971
716
  import {
972
- Box as Box5,
973
- Typography as Typography4,
974
- CircularProgress,
975
- IconButton as IconButton4,
976
- Menu,
717
+ FormControl,
718
+ InputLabel,
719
+ Select,
977
720
  MenuItem,
978
- Tooltip as Tooltip4
979
- } from "@mui/material";
980
- import { Fragment as Fragment6, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
981
- var LanguageSelector = () => {
982
- const supabase = useSupabase();
983
- const { i18n } = useTranslation2();
984
- const [languages, setLanguages] = useState7([]);
985
- const [loading, setLoading] = useState7(true);
986
- const { changeLanguage } = useLocalization();
987
- const { settings: userSettings, setLanguage } = useUserSettings();
988
- const [anchorEl, setAnchorEl] = useState7(null);
989
- const open = Boolean(anchorEl);
990
- useEffect3(() => {
991
- const fetchLanguages = async () => {
992
- try {
993
- const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
994
- if (error) throw error;
995
- setLanguages(data || []);
996
- if (userSettings.language) changeLanguage(userSettings.language);
997
- } catch (err) {
998
- 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);
999
- } finally {
1000
- setLoading(false);
721
+ Checkbox,
722
+ ListItemText,
723
+ IconButton as IconButton4,
724
+ InputAdornment as InputAdornment4,
725
+ Tooltip as Tooltip3,
726
+ FormHelperText
727
+ } from "@mui/material";
728
+ import CloseIcon from "@mui/icons-material/Close";
729
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
730
+ var SelectComponent = ({
731
+ overrideNamespace,
732
+ label,
733
+ value,
734
+ options,
735
+ onChange,
736
+ id = "translated-select",
737
+ fullWidth,
738
+ size = "medium",
739
+ multiple = false,
740
+ withCheckboxes = false,
741
+ clearable = true,
742
+ maxSelect,
743
+ disabled,
744
+ maxDisplayedTags = 2,
745
+ helperText,
746
+ defaultValueOnClear,
747
+ sx,
748
+ ...restProps
749
+ }) => {
750
+ const labelId = `${id}-label`;
751
+ const safeValue = multiple ? Array.isArray(value) ? value : [] : value ?? "";
752
+ const selectedArray = multiple ? safeValue : [];
753
+ const isLimitReached = Boolean(multiple && maxSelect && selectedArray.length >= maxSelect);
754
+ const hasValue = multiple ? selectedArray.length > 0 : safeValue !== "" && safeValue !== null && safeValue !== void 0;
755
+ const handleChange = (event, child) => {
756
+ if (multiple && maxSelect) {
757
+ const newValue = event.target.value;
758
+ if (newValue.length > maxSelect) {
759
+ return;
1001
760
  }
1002
- };
1003
- fetchLanguages();
1004
- }, []);
1005
- const handleClick = (event) => {
1006
- setAnchorEl(event.currentTarget);
761
+ }
762
+ onChange?.(event, child);
1007
763
  };
1008
- const handleClose = () => {
1009
- setAnchorEl(null);
764
+ const handleClear = (e) => {
765
+ e.stopPropagation();
766
+ if (!onChange) return;
767
+ const emptyValue = multiple ? [] : "";
768
+ const targetValue = defaultValueOnClear !== void 0 ? defaultValueOnClear : emptyValue;
769
+ const syntheticEvent = {
770
+ target: {
771
+ value: targetValue,
772
+ name: restProps.name
773
+ }
774
+ };
775
+ onChange(syntheticEvent, null);
1010
776
  };
1011
- const handleSelectLanguage = (langCode) => {
1012
- changeLanguage(langCode);
1013
- setLanguage(langCode);
1014
- handleClose();
777
+ const renderValueHandler = (selected) => {
778
+ if (!multiple) return void 0;
779
+ const currentSelected = selected;
780
+ if (currentSelected.length === 0) return null;
781
+ const selectedOptions = options.filter((opt) => currentSelected.includes(opt.value));
782
+ const visibleLabels = selectedOptions.slice(0, maxDisplayedTags).map((opt) => typeof opt.label === "string" ? opt.label : String(opt.value));
783
+ const hiddenCount = selectedOptions.length - maxDisplayedTags;
784
+ if (hiddenCount > 0) {
785
+ return `${visibleLabels.join(", ")} (+${hiddenCount})`;
786
+ }
787
+ return visibleLabels.join(", ");
1015
788
  };
1016
- if (loading) {
1017
- return /* @__PURE__ */ jsx7(CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
1018
- }
1019
- const rawCurrentLang = i18n.language || "uk";
1020
- const currentLangCode = rawCurrentLang.split("-")[0];
1021
- const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
1022
- return /* @__PURE__ */ jsxs6(Fragment6, { children: [
1023
- /* @__PURE__ */ jsx7(Tooltip4, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ jsx7(
1024
- IconButton4,
1025
- {
1026
- onClick: handleClick,
1027
- size: "small",
1028
- "aria-controls": open ? "language-menu" : void 0,
1029
- "aria-haspopup": "true",
1030
- "aria-expanded": open ? "true" : void 0,
1031
- sx: {
1032
- p: 1,
1033
- borderRadius: 2,
1034
- transition: "background-color 0.2s",
1035
- "&:hover": {
1036
- backgroundColor: "action.hover"
1037
- }
1038
- },
1039
- children: currentLang?.svg_flag && /* @__PURE__ */ jsx7(
1040
- Box5,
789
+ const isSmall = size === "small";
790
+ return /* @__PURE__ */ jsx5(
791
+ Tooltip3,
792
+ {
793
+ title: multiple ? Array.isArray(value) ? options.filter((opt) => value.includes(opt.value)).map((opt) => typeof opt.label === "string" ? opt.label : String(opt.value)).join(", ") : "" : options.find((opt) => opt.value === value)?.label ?? String(value ?? ""),
794
+ children: /* @__PURE__ */ jsxs4(FormControl, { fullWidth, size, sx: { mt: 1 }, children: [
795
+ /* @__PURE__ */ jsx5(InputLabel, { id: labelId, size: isSmall ? "small" : "medium", children: typeof label === "string" ? /* @__PURE__ */ jsx5(TranslateText, { overrideNamespace, children: label }) : label }),
796
+ /* @__PURE__ */ jsx5(
797
+ Select,
1041
798
  {
799
+ labelId,
800
+ id,
801
+ value: safeValue,
802
+ label: typeof label === "string" ? /* @__PURE__ */ jsx5(TranslateText, { overrideNamespace, children: label }) : label,
803
+ size,
804
+ multiple,
805
+ disabled,
806
+ onChange: handleChange,
807
+ renderValue: multiple ? renderValueHandler : void 0,
808
+ ...restProps,
809
+ endAdornment: clearable && hasValue && !disabled ? /* @__PURE__ */ jsx5(InputAdornment4, { position: "end", sx: { mr: 1 }, children: /* @__PURE__ */ jsx5(
810
+ IconButton4,
811
+ {
812
+ size: "small",
813
+ onClick: handleClear,
814
+ "aria-label": "clear selection",
815
+ edge: "end",
816
+ sx: { p: 0.5 },
817
+ children: /* @__PURE__ */ jsx5(CloseIcon, { fontSize: "small" })
818
+ }
819
+ ) }) : null,
1042
820
  sx: {
1043
- width: 24,
1044
- height: 16,
1045
- borderRadius: "3px",
1046
- overflow: "hidden",
1047
- flexShrink: 0,
1048
- boxShadow: "0 0 2px rgba(0,0,0,0.3)",
1049
- display: "flex",
1050
- alignItems: "center",
1051
- justifyContent: "center",
1052
- "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
1053
- },
1054
- dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
1055
- }
1056
- )
1057
- }
1058
- ) }),
1059
- /* @__PURE__ */ jsx7(
1060
- Menu,
1061
- {
1062
- id: "language-menu",
1063
- anchorEl,
1064
- open,
1065
- onClose: handleClose,
1066
- slotProps: {
1067
- paper: {
1068
- elevation: 3,
1069
- sx: {
1070
- mt: 1,
1071
- minWidth: 150,
1072
- borderRadius: 2
1073
- }
1074
- }
1075
- },
1076
- transformOrigin: { horizontal: "right", vertical: "top" },
1077
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
1078
- children: languages.map((lang) => {
1079
- const isSelected = lang.code === currentLangCode;
1080
- return /* @__PURE__ */ jsxs6(
1081
- MenuItem,
1082
- {
1083
- selected: isSelected,
1084
- onClick: () => handleSelectLanguage(lang.code),
1085
- sx: {
821
+ // 1. Задаем фиксированную высоту для всего контейнера инпута
822
+ height: isSmall ? "40px" : "56px",
823
+ minHeight: isSmall ? "40px" : "56px",
824
+ // 2. Выравниваем внутренний класс текстового поля
825
+ "& .MuiSelect-select": {
1086
826
  display: "flex",
1087
827
  alignItems: "center",
1088
- gap: 1.5,
1089
- py: 1,
1090
- px: 2
828
+ boxSizing: "border-box",
829
+ height: "100%",
830
+ minHeight: "100% !important",
831
+ py: 0,
832
+ lineHeight: "normal",
833
+ overflow: "hidden",
834
+ textOverflow: "ellipsis",
835
+ whiteSpace: "nowrap",
836
+ paddingRight: clearable && hasValue ? "64px !important" : "32px !important"
1091
837
  },
1092
- children: [
1093
- /* @__PURE__ */ jsx7(
1094
- Box5,
1095
- {
1096
- sx: {
1097
- width: 22,
1098
- height: 15,
1099
- borderRadius: "2px",
1100
- overflow: "hidden",
1101
- flexShrink: 0,
1102
- boxShadow: "0 0 1px rgba(0,0,0,0.4)",
1103
- "& svg": { width: "100%", height: "100%", display: "block" }
1104
- },
1105
- dangerouslySetInnerHTML: { __html: lang.svg_flag }
1106
- }
1107
- ),
1108
- /* @__PURE__ */ jsx7(Typography4, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
1109
- ]
838
+ // 3. Корректируем иконку стрелки выпадающего списка
839
+ "& .MuiSelect-icon": {
840
+ top: "calc(50% - 12px)"
841
+ },
842
+ // 4. Корректируем расположение иконки очистки
843
+ "& .MuiInputAdornment-root": {
844
+ maxHeight: "100%",
845
+ height: "100%",
846
+ alignItems: "center"
847
+ },
848
+ ...sx
1110
849
  },
1111
- lang.code
1112
- );
1113
- })
1114
- }
1115
- )
1116
- ] });
850
+ children: options.map((option) => {
851
+ const isSelected = multiple && selectedArray.includes(option.value);
852
+ const isDisabled = Boolean(isLimitReached && !isSelected);
853
+ return /* @__PURE__ */ jsxs4(
854
+ MenuItem,
855
+ {
856
+ value: option.value,
857
+ disabled: isDisabled,
858
+ children: [
859
+ multiple && withCheckboxes && /* @__PURE__ */ jsx5(Checkbox, { checked: isSelected, size, disabled: isDisabled }),
860
+ /* @__PURE__ */ jsx5(
861
+ ListItemText,
862
+ {
863
+ primary: option.isItalic ? /* @__PURE__ */ jsx5("em", { children: option.label }) : option.label
864
+ }
865
+ )
866
+ ]
867
+ },
868
+ String(option.value)
869
+ );
870
+ })
871
+ }
872
+ ),
873
+ helperText && /* @__PURE__ */ jsx5(FormHelperText, { children: helperText })
874
+ ] })
875
+ }
876
+ );
1117
877
  };
1118
- var PublicLanguageSelector = () => {
1119
- const supabase = useSupabase();
1120
- const { i18n } = useTranslation2();
1121
- const { changeLanguage } = useLocalization();
1122
- const [languages, setLanguages] = useState7([]);
1123
- const [loading, setLoading] = useState7(true);
1124
- const [anchorEl, setAnchorEl] = useState7(null);
1125
- const open = Boolean(anchorEl);
1126
- useEffect3(() => {
1127
- const fetchLanguages = async () => {
1128
- try {
1129
- const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
1130
- if (error) throw error;
1131
- setLanguages(data || []);
1132
- } catch (err) {
1133
- 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);
1134
- } finally {
1135
- setLoading(false);
1136
- }
1137
- };
1138
- fetchLanguages();
1139
- }, []);
1140
- const handleClick = (event) => {
1141
- setAnchorEl(event.currentTarget);
878
+
879
+ // src/UI/components/inputs/CheckboxComponent.tsx
880
+ import {
881
+ FormControlLabel,
882
+ Checkbox as Checkbox2,
883
+ Box as Box3
884
+ } from "@mui/material";
885
+ import { jsx as jsx6 } from "react/jsx-runtime";
886
+ var CheckboxComponent = ({
887
+ checked = false,
888
+ onChange,
889
+ label,
890
+ checkedLabel,
891
+ uncheckedLabel,
892
+ overrideNamespace,
893
+ checkboxProps,
894
+ ...props
895
+ }) => {
896
+ const currentLabel = label ?? (checked ? checkedLabel : uncheckedLabel);
897
+ const renderLabel = (node) => {
898
+ if (typeof node === "string") {
899
+ return /* @__PURE__ */ jsx6(TranslateText, { overrideNamespace, children: node });
900
+ }
901
+ return node;
1142
902
  };
1143
- const handleClose = () => {
1144
- setAnchorEl(null);
903
+ return /* @__PURE__ */ jsx6(Box3, { sx: { display: "inline-flex", alignItems: "center", gap: 0.5 }, children: /* @__PURE__ */ jsx6(
904
+ FormControlLabel,
905
+ {
906
+ control: /* @__PURE__ */ jsx6(
907
+ Checkbox2,
908
+ {
909
+ checked,
910
+ onChange,
911
+ ...checkboxProps
912
+ }
913
+ ),
914
+ label: renderLabel(currentLabel),
915
+ ...props
916
+ }
917
+ ) });
918
+ };
919
+
920
+ // src/UI/components/inputs/SwitchComponent.tsx
921
+ import {
922
+ FormControlLabel as FormControlLabel2,
923
+ Box as Box4,
924
+ Switch
925
+ } from "@mui/material";
926
+ import { jsx as jsx7 } from "react/jsx-runtime";
927
+ var SwitchComponent = ({
928
+ checked = false,
929
+ onChange,
930
+ label,
931
+ checkedLabel,
932
+ uncheckedLabel,
933
+ overrideNamespace,
934
+ switchProps,
935
+ ...props
936
+ }) => {
937
+ const currentLabel = label ?? (checked ? checkedLabel : uncheckedLabel);
938
+ const renderLabel = (node) => {
939
+ if (typeof node === "string") {
940
+ return /* @__PURE__ */ jsx7(TranslateText, { overrideNamespace, children: node });
941
+ }
942
+ return node;
1145
943
  };
1146
- const handleSelectLanguage = (langCode) => {
1147
- changeLanguage(langCode);
1148
- handleClose();
944
+ return /* @__PURE__ */ jsx7(Box4, { sx: { display: "inline-flex", alignItems: "center", gap: 0.5 }, children: /* @__PURE__ */ jsx7(
945
+ FormControlLabel2,
946
+ {
947
+ control: /* @__PURE__ */ jsx7(
948
+ Switch,
949
+ {
950
+ checked,
951
+ onChange,
952
+ ...switchProps
953
+ }
954
+ ),
955
+ label: renderLabel(currentLabel),
956
+ ...props
957
+ }
958
+ ) });
959
+ };
960
+
961
+ // src/UI/components/inputs/UrlComponent.tsx
962
+ import { useState as useState6 } from "react";
963
+ import {
964
+ TextField as TextField3,
965
+ InputAdornment as InputAdornment5,
966
+ IconButton as IconButton5,
967
+ Tooltip as Tooltip4,
968
+ Popover,
969
+ Box as Box5,
970
+ Typography,
971
+ Button
972
+ } from "@mui/material";
973
+ import LinkIcon from "@mui/icons-material/Link";
974
+ import LaunchIcon from "@mui/icons-material/Launch";
975
+ import ContentCopyIcon2 from "@mui/icons-material/ContentCopy";
976
+ import CheckIcon2 from "@mui/icons-material/Check";
977
+ import EditNoteIcon from "@mui/icons-material/EditNote";
978
+ import LockIcon2 from "@mui/icons-material/Lock";
979
+ import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
980
+ function UrlComponent({
981
+ overrideNamespace,
982
+ label,
983
+ value,
984
+ onChange,
985
+ disabled = false,
986
+ readOnly = false,
987
+ required = false,
988
+ error = false,
989
+ helperText = "",
990
+ description = "",
991
+ fullWidth = true,
992
+ openInNewTab = true,
993
+ showLock = true,
994
+ lockTooltip = "Field is not editable",
995
+ sx
996
+ }) {
997
+ const [copied, setCopied] = useState6(false);
998
+ const [anchorEl, setAnchorEl] = useState6(null);
999
+ const isViewMode = disabled || readOnly;
1000
+ const currentUrl = typeof value === "object" && value !== null ? value.url || "" : value || "";
1001
+ const currentTitle = typeof value === "object" && value !== null ? value.title || "" : "";
1002
+ const getFormattedUrl = (val) => {
1003
+ if (!val) return "";
1004
+ const trimmed = val.trim();
1005
+ if (trimmed.match(/^[a-zA-Z]+:\/\//)) {
1006
+ return trimmed;
1007
+ }
1008
+ return `https://${trimmed}`;
1149
1009
  };
1150
- if (loading) {
1151
- return /* @__PURE__ */ jsx7(CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
1152
- }
1153
- const rawCurrentLang = i18n.language || "uk";
1154
- const currentLangCode = rawCurrentLang.split("-")[0];
1155
- const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
1156
- return /* @__PURE__ */ jsxs6(Fragment6, { children: [
1157
- /* @__PURE__ */ jsx7(Tooltip4, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ jsx7(
1158
- IconButton4,
1010
+ const finalUrl = getFormattedUrl(currentUrl);
1011
+ const targetAttribute = openInNewTab ? "_blank" : "_self";
1012
+ const displayLabelText = currentTitle.trim() || currentUrl;
1013
+ const handleUrlChange = (newUrl) => {
1014
+ onChange?.({ url: newUrl, title: currentTitle });
1015
+ };
1016
+ const handleTitleChange = (newTitle) => {
1017
+ onChange?.({ url: currentUrl, title: newTitle });
1018
+ };
1019
+ const handleCopy = (e) => {
1020
+ e.stopPropagation();
1021
+ if (!finalUrl) return;
1022
+ navigator.clipboard.writeText(finalUrl);
1023
+ setCopied(true);
1024
+ setTimeout(() => setCopied(false), 2e3);
1025
+ };
1026
+ const handleOpenLink = (e) => {
1027
+ e.stopPropagation();
1028
+ if (finalUrl) {
1029
+ window.open(finalUrl, targetAttribute, openInNewTab ? "noopener,noreferrer" : void 0);
1030
+ }
1031
+ };
1032
+ const handleInputClick = (e) => {
1033
+ if (isViewMode && finalUrl) {
1034
+ handleOpenLink(e);
1035
+ }
1036
+ };
1037
+ const handleOpenTitleMenu = (e) => {
1038
+ e.stopPropagation();
1039
+ setAnchorEl(e.currentTarget);
1040
+ };
1041
+ const handleCloseTitleMenu = () => {
1042
+ setAnchorEl(null);
1043
+ };
1044
+ const isTitlePopoverOpen = Boolean(anchorEl);
1045
+ const displayHelperText = error ? helperText : description || helperText;
1046
+ return /* @__PURE__ */ jsxs5(Fragment4, { children: [
1047
+ /* @__PURE__ */ jsx8(
1048
+ TextField3,
1159
1049
  {
1160
- onClick: handleClick,
1161
- size: "small",
1162
- "aria-controls": open ? "language-menu" : void 0,
1163
- "aria-haspopup": "true",
1164
- "aria-expanded": open ? "true" : void 0,
1050
+ label: /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace, children: label }),
1051
+ type: isViewMode ? "text" : "url",
1052
+ value: isViewMode ? displayLabelText : currentUrl,
1053
+ onChange: (e) => handleUrlChange(e.target.value),
1054
+ required,
1055
+ error,
1056
+ disabled,
1057
+ margin: "dense",
1058
+ helperText: displayHelperText,
1059
+ fullWidth,
1060
+ placeholder: "example.com",
1165
1061
  sx: {
1166
- p: 1,
1167
- borderRadius: 2,
1168
- transition: "background-color 0.2s",
1169
- "&:hover": {
1170
- backgroundColor: "action.hover"
1171
- }
1062
+ "& .MuiInputLabel-asterisk": {
1063
+ color: "red",
1064
+ fontSize: "1.5rem"
1065
+ },
1066
+ "& .MuiInputBase-input": {
1067
+ color: isViewMode && finalUrl ? "primary.main" : void 0,
1068
+ textDecoration: isViewMode && finalUrl ? "underline" : "none",
1069
+ cursor: isViewMode && finalUrl ? "pointer" : void 0,
1070
+ fontWeight: isViewMode && finalUrl ? 500 : void 0
1071
+ },
1072
+ ...sx
1172
1073
  },
1173
- children: currentLang?.svg_flag && /* @__PURE__ */ jsx7(
1174
- Box5,
1175
- {
1176
- sx: {
1177
- width: 24,
1178
- height: 16,
1179
- borderRadius: "3px",
1180
- overflow: "hidden",
1181
- flexShrink: 0,
1182
- boxShadow: "0 0 2px rgba(0,0,0,0.3)",
1183
- display: "flex",
1184
- alignItems: "center",
1185
- justifyContent: "center",
1186
- "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
1187
- },
1188
- dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
1074
+ slotProps: {
1075
+ htmlInput: {
1076
+ readOnly,
1077
+ onClick: handleInputClick
1078
+ },
1079
+ input: {
1080
+ startAdornment: /* @__PURE__ */ jsx8(InputAdornment5, { position: "start", children: /* @__PURE__ */ jsx8(LinkIcon, { fontSize: "small", color: isViewMode && finalUrl ? "primary" : "action" }) }),
1081
+ endAdornment: /* @__PURE__ */ jsxs5(InputAdornment5, { position: "end", sx: { gap: 0.5 }, children: [
1082
+ !isViewMode && /* @__PURE__ */ jsx8(Tooltip4, { title: currentTitle ? `Title: "${currentTitle}"` : /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Set link title" }), children: /* @__PURE__ */ jsx8(
1083
+ IconButton5,
1084
+ {
1085
+ size: "small",
1086
+ onClick: handleOpenTitleMenu,
1087
+ color: currentTitle ? "primary" : "default",
1088
+ children: /* @__PURE__ */ jsx8(EditNoteIcon, { fontSize: "small" })
1089
+ }
1090
+ ) }),
1091
+ finalUrl && /* @__PURE__ */ jsx8(Tooltip4, { title: copied ? /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Copied!" }) : /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Copy link" }), children: /* @__PURE__ */ jsx8(IconButton5, { size: "small", onClick: handleCopy, color: copied ? "success" : "default", children: copied ? /* @__PURE__ */ jsx8(CheckIcon2, { fontSize: "small" }) : /* @__PURE__ */ jsx8(ContentCopyIcon2, { fontSize: "small" }) }) }),
1092
+ isViewMode && showLock && /* @__PURE__ */ jsx8(Tooltip4, { title: /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace, children: lockTooltip }), children: /* @__PURE__ */ jsx8(
1093
+ IconButton5,
1094
+ {
1095
+ size: "small",
1096
+ disabled: true,
1097
+ edge: "end",
1098
+ "aria-label": "locked input",
1099
+ sx: {
1100
+ "&.Mui-disabled": {
1101
+ color: "text.secondary"
1102
+ }
1103
+ },
1104
+ children: /* @__PURE__ */ jsx8(LockIcon2, { fontSize: "small" })
1105
+ }
1106
+ ) }),
1107
+ finalUrl && /* @__PURE__ */ jsx8(Tooltip4, { title: /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Open link" }), children: /* @__PURE__ */ jsx8(IconButton5, { size: "small", onClick: handleOpenLink, children: /* @__PURE__ */ jsx8(LaunchIcon, { fontSize: "small", color: isViewMode ? "primary" : "action" }) }) })
1108
+ ] })
1189
1109
  }
1190
- )
1110
+ }
1191
1111
  }
1192
- ) }),
1193
- /* @__PURE__ */ jsx7(
1194
- Menu,
1112
+ ),
1113
+ /* @__PURE__ */ jsxs5(
1114
+ Popover,
1195
1115
  {
1196
- id: "language-menu",
1116
+ open: isTitlePopoverOpen,
1197
1117
  anchorEl,
1198
- open,
1199
- onClose: handleClose,
1118
+ onClose: handleCloseTitleMenu,
1119
+ anchorOrigin: {
1120
+ vertical: "bottom",
1121
+ horizontal: "right"
1122
+ },
1123
+ transformOrigin: {
1124
+ vertical: "top",
1125
+ horizontal: "right"
1126
+ },
1200
1127
  slotProps: {
1201
- paper: {
1202
- elevation: 3,
1203
- sx: {
1204
- mt: 1,
1205
- minWidth: 150,
1206
- borderRadius: 2
1207
- }
1208
- }
1128
+ paper: { sx: { p: 2, width: 280 } }
1209
1129
  },
1210
- transformOrigin: { horizontal: "right", vertical: "top" },
1211
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
1212
- children: languages.map((lang) => {
1213
- const isSelected = lang.code === currentLangCode;
1214
- return /* @__PURE__ */ jsxs6(
1215
- MenuItem,
1130
+ children: [
1131
+ /* @__PURE__ */ jsx8(Typography, { variant: "subtitle2", sx: { mb: 1, fontWeight: "bold" }, children: /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Link Title (Anchor)" }) }),
1132
+ /* @__PURE__ */ jsxs5(Typography, { variant: "caption", color: "text.secondary", sx: { mb: 1.5, display: "block" }, children: [
1133
+ /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Specify the text to display instead of the URL address" }),
1134
+ ":"
1135
+ ] }),
1136
+ /* @__PURE__ */ jsx8(
1137
+ TextField3,
1216
1138
  {
1217
- selected: isSelected,
1218
- onClick: () => handleSelectLanguage(lang.code),
1219
- sx: {
1220
- display: "flex",
1221
- alignItems: "center",
1222
- gap: 1.5,
1223
- py: 1,
1224
- px: 2
1225
- },
1226
- children: [
1227
- /* @__PURE__ */ jsx7(
1228
- Box5,
1229
- {
1230
- sx: {
1231
- width: 22,
1232
- height: 15,
1233
- borderRadius: "2px",
1234
- overflow: "hidden",
1235
- flexShrink: 0,
1236
- boxShadow: "0 0 1px rgba(0,0,0,0.4)",
1237
- "& svg": { width: "100%", height: "100%", display: "block" }
1238
- },
1239
- dangerouslySetInnerHTML: { __html: lang.svg_flag }
1240
- }
1241
- ),
1242
- /* @__PURE__ */ jsx7(Typography4, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
1243
- ]
1244
- },
1245
- lang.code
1246
- );
1247
- })
1139
+ size: "small",
1140
+ fullWidth: true,
1141
+ placeholder: "e.g. Instruction",
1142
+ value: currentTitle,
1143
+ onChange: (e) => handleTitleChange(e.target.value),
1144
+ autoFocus: true,
1145
+ onKeyDown: (e) => {
1146
+ if (e.key === "Enter") {
1147
+ e.preventDefault();
1148
+ handleCloseTitleMenu();
1149
+ }
1150
+ }
1151
+ }
1152
+ ),
1153
+ /* @__PURE__ */ jsx8(Box5, { sx: { display: "flex", justifyContent: "flex-end", mt: 1.5 }, children: /* @__PURE__ */ jsx8(Button, { size: "small", variant: "contained", onClick: handleCloseTitleMenu, children: /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Done" }) }) })
1154
+ ]
1248
1155
  }
1249
1156
  )
1250
1157
  ] });
1251
- };
1252
-
1253
- // src/UI/components/inputs/SearchComponent.tsx
1254
- import { useState as useState9, useEffect as useEffect5 } from "react";
1255
- import { useTranslation as useTranslation3 } from "react-i18next";
1256
- import { TextField as TextField3, InputAdornment as InputAdornment4, IconButton as IconButton5, Tooltip as Tooltip5 } from "@mui/material";
1257
- import TranslateIcon2 from "@mui/icons-material/Translate";
1258
- import ClearIcon2 from "@mui/icons-material/Clear";
1158
+ }
1259
1159
 
1260
- // src/hooks/useDebounce.ts
1261
- import { useEffect as useEffect4, useState as useState8 } from "react";
1262
- function useDebounce(value, delay = 500) {
1263
- const [debouncedValue, setDebouncedValue] = useState8(value);
1264
- useEffect4(() => {
1265
- const timer = setTimeout(() => {
1266
- setDebouncedValue(value);
1267
- }, delay);
1268
- return () => {
1269
- clearTimeout(timer);
1160
+ // src/UI/components/buttons/ButtonComponent.tsx
1161
+ import { forwardRef } from "react";
1162
+ import { Button as Button2 } from "@mui/material";
1163
+ import { jsx as jsx9 } from "react/jsx-runtime";
1164
+ var ButtonComponent = forwardRef(
1165
+ ({ label, children, overrideNamespace, ...props }, ref) => {
1166
+ const renderContent = (content) => {
1167
+ if (typeof content === "string") {
1168
+ return /* @__PURE__ */ jsx9(TranslateText, { overrideNamespace, children: content });
1169
+ }
1170
+ return content;
1270
1171
  };
1271
- }, [value, delay]);
1272
- return debouncedValue;
1273
- }
1172
+ const contentToRender = label !== void 0 ? label : children;
1173
+ return /* @__PURE__ */ jsx9(Button2, { ref, ...props, children: renderContent(contentToRender) });
1174
+ }
1175
+ );
1176
+ ButtonComponent.displayName = "ButtonComponent";
1274
1177
 
1275
- // src/UI/components/inputs/SearchComponent.tsx
1276
- import { Fragment as Fragment7, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1277
- var SearchComponent = ({
1178
+ // src/UI/components/buttons/RefreshButtonComponent.tsx
1179
+ import { useState as useState7 } from "react";
1180
+ import {
1181
+ Button as Button3,
1182
+ Fab,
1183
+ styled
1184
+ } from "@mui/material";
1185
+ import RefreshIconMui from "@mui/icons-material/Refresh";
1186
+ import { Fragment as Fragment5, jsx as jsx10 } from "react/jsx-runtime";
1187
+ var AnimatedRefreshIcon = styled(RefreshIconMui, {
1188
+ shouldForwardProp: (prop) => prop !== "isSpinning"
1189
+ })(({ isSpinning }) => ({
1190
+ animation: isSpinning ? "spin 1s linear infinite" : "none",
1191
+ "@keyframes spin": {
1192
+ "0%": {
1193
+ transform: "rotate(0deg)"
1194
+ },
1195
+ "100%": {
1196
+ transform: "rotate(360deg)"
1197
+ }
1198
+ }
1199
+ }));
1200
+ var RefreshButtonComponent = ({
1278
1201
  overrideNamespace,
1279
- label = "",
1280
- value = "",
1281
- onChange,
1282
- onClear,
1283
- placeholderKey,
1284
- clearTooltip = "Clear",
1285
- debounceDelay = 500,
1286
- onDebounceChange,
1287
- slotProps,
1288
- ...restProps
1202
+ size = "small",
1203
+ onClick,
1204
+ disabled = false,
1205
+ fullWidth = false,
1206
+ loading: externalLoading,
1207
+ tooltip,
1208
+ mobileViewOnly,
1209
+ disableMobileView,
1210
+ hideTooltipOnMobile,
1211
+ hideTooltipOnDesktop
1289
1212
  }) => {
1290
- const supabase = useSupabase();
1291
- const namespace = useTranslationNamespace();
1292
- const { t, i18n } = useTranslation3(namespace);
1293
- const { isTranslationMode } = useTranslationEdit();
1294
- const [isDialogOpen, setIsDialogOpen] = useState9(false);
1295
- const [localValue, setLocalValue] = useState9(String(value ?? ""));
1296
- const debouncedValue = useDebounce(localValue, debounceDelay);
1297
- useEffect5(() => {
1298
- setLocalValue(String(value ?? ""));
1299
- }, [value]);
1300
- useEffect5(() => {
1301
- if (onDebounceChange) {
1302
- onDebounceChange(debouncedValue);
1303
- }
1304
- if (onChange && debouncedValue !== String(value ?? "")) {
1305
- const syntheticEvent = {
1306
- target: { value: debouncedValue },
1307
- currentTarget: { value: debouncedValue }
1308
- };
1309
- onChange(syntheticEvent);
1213
+ const { displayState } = useAppTheme();
1214
+ const [internalLoading, setInternalLoading] = useState7(false);
1215
+ const isLoading = externalLoading !== void 0 ? externalLoading : internalLoading;
1216
+ const handleClick = async (event) => {
1217
+ if (!onClick || isLoading || disabled) return;
1218
+ try {
1219
+ setInternalLoading(true);
1220
+ await onClick(event);
1221
+ } finally {
1222
+ setInternalLoading(false);
1310
1223
  }
1311
- }, [debouncedValue]);
1312
- const hasValue = localValue.length > 0;
1313
- const handleChange = (e) => {
1314
- setLocalValue(e.target.value);
1315
1224
  };
1316
- const handleClear = (e) => {
1317
- e.stopPropagation();
1318
- setLocalValue("");
1319
- if (onClear) {
1320
- onClear();
1225
+ const renderIcon = () => /* @__PURE__ */ jsx10(AnimatedRefreshIcon, { fontSize: size, isSpinning: isLoading });
1226
+ if (displayState.isMobile && !disableMobileView || mobileViewOnly) {
1227
+ return /* @__PURE__ */ jsx10(TranslatableTooltipComponent, { title: hideTooltipOnMobile ? /* @__PURE__ */ jsx10(Fragment5, {}) : tooltip || /* @__PURE__ */ jsx10(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), children: /* @__PURE__ */ jsx10("span", { children: /* @__PURE__ */ jsx10(
1228
+ Fab,
1229
+ {
1230
+ size,
1231
+ color: "inherit",
1232
+ onClick: handleClick,
1233
+ disabled: disabled || isLoading,
1234
+ "aria-label": "refresh",
1235
+ children: renderIcon()
1236
+ }
1237
+ ) }) });
1238
+ }
1239
+ return /* @__PURE__ */ jsx10(TranslatableTooltipComponent, { title: hideTooltipOnDesktop ? /* @__PURE__ */ jsx10(Fragment5, {}) : tooltip || /* @__PURE__ */ jsx10(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), children: /* @__PURE__ */ jsx10(
1240
+ Button3,
1241
+ {
1242
+ variant: "contained",
1243
+ color: "inherit",
1244
+ size,
1245
+ onClick: handleClick,
1246
+ disabled: disabled || isLoading,
1247
+ fullWidth,
1248
+ startIcon: renderIcon(),
1249
+ children: /* @__PURE__ */ jsx10(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" })
1321
1250
  }
1322
- if (onChange) {
1323
- const syntheticEvent = {
1324
- ...e,
1325
- target: { ...e.target, value: "" },
1326
- currentTarget: { ...e.currentTarget, value: "" }
1327
- };
1328
- onChange(syntheticEvent);
1251
+ ) });
1252
+ };
1253
+
1254
+ // src/UI/components/data.display/UserAvatarComponent.tsx
1255
+ import { useState as useState8, useEffect as useEffect4, lazy, Suspense } from "react";
1256
+ import { Avatar, Tooltip as Tooltip5, Typography as Typography2 } from "@mui/material";
1257
+ import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
1258
+ var LazyUserPopover = lazy(() => import("./UserPopoverComponent-VFSZ5ZO2.mjs"));
1259
+ var getInitials = (name) => {
1260
+ if (!name) return "?";
1261
+ const parts = name.trim().split(" ");
1262
+ if (parts.length >= 2) {
1263
+ return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
1264
+ }
1265
+ return name[0].toUpperCase();
1266
+ };
1267
+ var UserAvatarComponent = ({
1268
+ userId = "",
1269
+ avatarUrl = "",
1270
+ displayName = "",
1271
+ employeePost = "",
1272
+ size = 40,
1273
+ disableBorder = false,
1274
+ disableShadow = false,
1275
+ disablePopover = false,
1276
+ disableTooltip = false,
1277
+ sx = {}
1278
+ }) => {
1279
+ const supabase = useSupabase();
1280
+ const [anchorEl, setAnchorEl] = useState8(null);
1281
+ const [hasInteracted, setHasInteracted] = useState8(false);
1282
+ const [resolvedAvatarUrl, setResolvedAvatarUrl] = useState8(null);
1283
+ const canShowPopover = !disablePopover && Boolean(userId);
1284
+ useEffect4(() => {
1285
+ let isMounted = true;
1286
+ const resolveAvatar = async () => {
1287
+ if (!avatarUrl) {
1288
+ if (isMounted) setResolvedAvatarUrl(null);
1289
+ return;
1290
+ }
1291
+ if (!avatarUrl.startsWith("http") && !avatarUrl.startsWith("data:")) {
1292
+ try {
1293
+ const { data } = await supabase.storage.from("user-media").createSignedUrl(avatarUrl, 3600);
1294
+ if (isMounted) {
1295
+ setResolvedAvatarUrl(data?.signedUrl || null);
1296
+ }
1297
+ } catch (err) {
1298
+ console.error("Error resolving signed url for avatar:", err);
1299
+ if (isMounted) setResolvedAvatarUrl(null);
1300
+ }
1301
+ } else {
1302
+ if (isMounted) setResolvedAvatarUrl(avatarUrl);
1303
+ }
1304
+ };
1305
+ resolveAvatar();
1306
+ return () => {
1307
+ isMounted = false;
1308
+ };
1309
+ }, [avatarUrl]);
1310
+ const handleClick = (event) => {
1311
+ event.stopPropagation();
1312
+ event.preventDefault();
1313
+ if (canShowPopover) {
1314
+ setAnchorEl(event.currentTarget);
1315
+ if (!hasInteracted) {
1316
+ setHasInteracted(true);
1317
+ }
1329
1318
  }
1330
1319
  };
1331
- const translatedPlaceholder = placeholderKey ? t(placeholderKey) : void 0;
1332
- const handleSaveTranslations = async (newValues, contextHint) => {
1333
- if (!placeholderKey) return;
1334
- const upsertData = Object.entries(newValues).map(([langCode, text]) => ({
1335
- lang_code: langCode,
1336
- namespace,
1337
- key: placeholderKey,
1338
- value: text,
1339
- context_hint: contextHint
1340
- }));
1341
- const { error } = await supabase.from("translations").upsert(upsertData, { onConflict: "lang_code,namespace,key" });
1342
- if (error) {
1343
- alert("\u041F\u043E\u043C\u0438\u043B\u043A\u0430 \u043F\u0456\u0434 \u0447\u0430\u0441 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043D\u043D\u044F \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043D\u0438\u0445");
1344
- throw error;
1320
+ const handleClose = (event) => {
1321
+ if (event) {
1322
+ event.stopPropagation();
1323
+ event.preventDefault();
1345
1324
  }
1346
- await translationService.incrementVersion(supabase, namespace, Object.keys(newValues));
1347
- Object.entries(newValues).forEach(([langCode, text]) => {
1348
- i18n.addResource(langCode, namespace, placeholderKey, text);
1349
- });
1325
+ setAnchorEl(null);
1350
1326
  };
1351
- const renderEndAdornment = () => {
1352
- const rawInputProps = slotProps?.input;
1353
- const isInputObject = typeof rawInputProps === "object" && rawInputProps !== null;
1354
- const existingEndAdornment = isInputObject && "endAdornment" in rawInputProps ? rawInputProps.endAdornment : void 0;
1355
- if (!hasValue && (!isTranslationMode || !placeholderKey)) {
1356
- return existingEndAdornment;
1327
+ const isPopoverOpen = Boolean(anchorEl);
1328
+ const initials = getInitials(displayName || "");
1329
+ const getTooltip = /* @__PURE__ */ jsxs6(Fragment6, { children: [
1330
+ /* @__PURE__ */ jsx11(Typography2, { component: "div", variant: "caption", children: displayName }),
1331
+ displayName && employeePost && /* @__PURE__ */ jsx11(Typography2, { component: "div", variant: "caption", children: employeePost })
1332
+ ] });
1333
+ return /* @__PURE__ */ jsxs6(Fragment6, { children: [
1334
+ /* @__PURE__ */ jsx11(Tooltip5, { title: disableTooltip || isPopoverOpen ? "" : getTooltip, children: /* @__PURE__ */ jsx11(
1335
+ Avatar,
1336
+ {
1337
+ src: resolvedAvatarUrl || void 0,
1338
+ alt: displayName || "User Avatar",
1339
+ onClick: handleClick,
1340
+ sx: {
1341
+ width: size,
1342
+ height: size,
1343
+ fontSize: size * 0.4,
1344
+ fontWeight: 600,
1345
+ bgcolor: "primary.main",
1346
+ color: "primary.contrastText",
1347
+ cursor: canShowPopover ? "pointer" : void 0,
1348
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
1349
+ border: disableBorder ? "none" : "2px solid",
1350
+ borderColor: "background.paper",
1351
+ boxShadow: disableShadow ? "none" : 2,
1352
+ "&:hover": {
1353
+ transform: canShowPopover ? "scale(1.05)" : "none"
1354
+ },
1355
+ ...sx
1356
+ },
1357
+ children: !resolvedAvatarUrl && initials
1358
+ }
1359
+ ) }),
1360
+ canShowPopover && hasInteracted && /* @__PURE__ */ jsx11(Suspense, { fallback: null, children: /* @__PURE__ */ jsx11(
1361
+ LazyUserPopover,
1362
+ {
1363
+ userId,
1364
+ anchorEl,
1365
+ open: isPopoverOpen,
1366
+ onClose: handleClose
1367
+ }
1368
+ ) })
1369
+ ] });
1370
+ };
1371
+
1372
+ // src/UI/components/data.display/MyAvatarComponent.tsx
1373
+ import { useState as useState9 } from "react";
1374
+ import { Avatar as Avatar2, Box as Box6, Popover as Popover2, Typography as Typography3, Skeleton } from "@mui/material";
1375
+ import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1376
+ var getInitials2 = (name) => {
1377
+ if (!name) return "?";
1378
+ const parts = name.trim().split(" ");
1379
+ if (parts.length >= 2) {
1380
+ return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
1381
+ }
1382
+ return name[0].toUpperCase();
1383
+ };
1384
+ var MyAvatarComponent = ({
1385
+ size = 40,
1386
+ disableBorder = false,
1387
+ disableShadow = false,
1388
+ disablePopover = false,
1389
+ sx = {}
1390
+ }) => {
1391
+ const { profile: userProfile, loading: isLoading } = useAuth();
1392
+ const [anchorEl, setAnchorEl] = useState9(null);
1393
+ const handlePopoverOpen = (event) => {
1394
+ if (!disablePopover) {
1395
+ setAnchorEl(event.currentTarget);
1357
1396
  }
1358
- return /* @__PURE__ */ jsxs7(Fragment7, { children: [
1359
- existingEndAdornment,
1360
- /* @__PURE__ */ jsxs7(InputAdornment4, { position: "end", children: [
1361
- hasValue && /* @__PURE__ */ jsx8(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace, children: clearTooltip }), children: /* @__PURE__ */ jsx8(
1362
- IconButton5,
1363
- {
1364
- size: "small",
1365
- onClick: handleClear,
1366
- edge: "end",
1367
- "aria-label": "clear input",
1368
- children: /* @__PURE__ */ jsx8(ClearIcon2, { fontSize: "small" })
1369
- }
1370
- ) }),
1371
- isTranslationMode && placeholderKey && /* @__PURE__ */ jsx8(Tooltip5, { title: `Translate placeholder: "${placeholderKey}"`, children: /* @__PURE__ */ jsx8(
1372
- IconButton5,
1373
- {
1374
- size: "small",
1375
- onClick: (e) => {
1376
- e.preventDefault();
1377
- e.stopPropagation();
1378
- setIsDialogOpen(true);
1379
- },
1380
- sx: {
1381
- color: "#d97706",
1382
- backgroundColor: "rgba(254, 243, 199, 0.6)",
1383
- border: "1px dashed #f59e0b",
1384
- p: "3px",
1385
- ml: 0.5,
1386
- "&:hover": {
1387
- backgroundColor: "#fef08a"
1388
- }
1389
- },
1390
- children: /* @__PURE__ */ jsx8(TranslateIcon2, { fontSize: "small" })
1391
- }
1392
- ) })
1393
- ] })
1394
- ] });
1395
1397
  };
1398
+ const handlePopoverClose = () => {
1399
+ setAnchorEl(null);
1400
+ };
1401
+ const isPopoverOpen = Boolean(anchorEl);
1402
+ if (isLoading) {
1403
+ return /* @__PURE__ */ jsx12(
1404
+ Skeleton,
1405
+ {
1406
+ variant: "circular",
1407
+ width: size,
1408
+ height: size,
1409
+ sx: { display: "inline-block", flexShrink: 0, ...sx }
1410
+ }
1411
+ );
1412
+ }
1413
+ const initials = getInitials2(userProfile?.display_name || "");
1396
1414
  return /* @__PURE__ */ jsxs7(Fragment7, { children: [
1397
- /* @__PURE__ */ jsx8(
1398
- TextField3,
1415
+ /* @__PURE__ */ jsx12(
1416
+ Avatar2,
1399
1417
  {
1400
- ...restProps,
1401
- label: typeof label === "string" ? /* @__PURE__ */ jsx8(TranslateText, { overrideNamespace, children: label }) : label,
1402
- value: localValue,
1403
- onChange: handleChange,
1404
- placeholder: translatedPlaceholder,
1405
- slotProps: {
1406
- ...slotProps,
1407
- input: {
1408
- ...slotProps?.input,
1409
- endAdornment: renderEndAdornment()
1410
- }
1411
- }
1418
+ src: userProfile?.avatar_url || void 0,
1419
+ alt: userProfile?.display_name || "User Avatar",
1420
+ onMouseEnter: handlePopoverOpen,
1421
+ onMouseLeave: handlePopoverClose,
1422
+ sx: {
1423
+ width: size,
1424
+ height: size,
1425
+ fontSize: size * 0.4,
1426
+ fontWeight: 600,
1427
+ bgcolor: "primary.main",
1428
+ color: "primary.contrastText",
1429
+ cursor: disablePopover ? void 0 : "pointer",
1430
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
1431
+ border: disableBorder ? "none" : "2px solid",
1432
+ borderColor: "background.paper",
1433
+ boxShadow: disableShadow ? "none" : 2,
1434
+ "&:hover": {
1435
+ transform: disablePopover ? "none" : "scale(1.05)"
1436
+ },
1437
+ ...sx
1438
+ },
1439
+ children: !userProfile?.avatar_url && initials
1412
1440
  }
1413
1441
  ),
1414
- placeholderKey && /* @__PURE__ */ jsx8(
1415
- TranslationDialog,
1442
+ !disablePopover && /* @__PURE__ */ jsx12(
1443
+ Popover2,
1416
1444
  {
1417
- open: isDialogOpen,
1418
- onClose: () => setIsDialogOpen(false),
1419
- translationKey: placeholderKey,
1420
- namespace,
1421
- onSave: handleSaveTranslations
1445
+ id: `avatar-popover-${userProfile?.id}`,
1446
+ open: isPopoverOpen,
1447
+ anchorEl,
1448
+ anchorOrigin: {
1449
+ vertical: "bottom",
1450
+ horizontal: "center"
1451
+ },
1452
+ transformOrigin: {
1453
+ vertical: "top",
1454
+ horizontal: "center"
1455
+ },
1456
+ onClose: handlePopoverClose,
1457
+ disableRestoreFocus: true,
1458
+ disableAutoFocus: true,
1459
+ disableEnforceFocus: true,
1460
+ sx: {
1461
+ pointerEvents: "none",
1462
+ mt: 1
1463
+ },
1464
+ slotProps: {
1465
+ paper: {
1466
+ sx: {
1467
+ p: 1.5,
1468
+ borderRadius: 2,
1469
+ boxShadow: 3
1470
+ }
1471
+ }
1472
+ },
1473
+ children: /* @__PURE__ */ jsxs7(Box6, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 0.5 }, children: [
1474
+ /* @__PURE__ */ jsx12(Typography3, { variant: "subtitle2", sx: { fontWeight: 600 }, children: userProfile?.display_name }),
1475
+ userProfile?.email && /* @__PURE__ */ jsx12(Typography3, { variant: "caption", color: "text.secondary", children: userProfile.email })
1476
+ ] })
1422
1477
  }
1423
1478
  )
1424
1479
  ] });
1425
1480
  };
1426
1481
 
1427
- // src/UI/components/inputs/SelectComponent.tsx
1428
- import {
1429
- FormControl,
1430
- InputLabel,
1431
- Select,
1432
- MenuItem as MenuItem2,
1433
- Checkbox,
1434
- ListItemText,
1435
- IconButton as IconButton6,
1436
- InputAdornment as InputAdornment5,
1437
- Tooltip as Tooltip6,
1438
- FormHelperText
1439
- } from "@mui/material";
1440
- import CloseIcon from "@mui/icons-material/Close";
1441
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1442
- var SelectComponent = ({
1482
+ // src/UI/components/data.display/ExpandableNoteComponent.tsx
1483
+ import { useState as useState10 } from "react";
1484
+ import { Typography as Typography4, Link } from "@mui/material";
1485
+ import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
1486
+ var ExpandableNoteComponent = ({
1443
1487
  overrideNamespace,
1488
+ text,
1489
+ maxLength = 100,
1444
1490
  label,
1445
- value,
1446
- options,
1447
- onChange,
1448
- id = "translated-select",
1449
- fullWidth,
1450
- size = "medium",
1451
- multiple = false,
1452
- withCheckboxes = false,
1453
- clearable = true,
1454
- maxSelect,
1455
- disabled,
1456
- maxDisplayedTags = 2,
1457
- helperText,
1458
- defaultValueOnClear,
1459
1491
  sx,
1460
1492
  ...restProps
1461
1493
  }) => {
1462
- const labelId = `${id}-label`;
1463
- const safeValue = multiple ? Array.isArray(value) ? value : [] : value ?? "";
1464
- const selectedArray = multiple ? safeValue : [];
1465
- const isLimitReached = Boolean(multiple && maxSelect && selectedArray.length >= maxSelect);
1466
- const hasValue = multiple ? selectedArray.length > 0 : safeValue !== "" && safeValue !== null && safeValue !== void 0;
1467
- const handleChange = (event, child) => {
1468
- if (multiple && maxSelect) {
1469
- const newValue = event.target.value;
1470
- if (newValue.length > maxSelect) {
1471
- return;
1472
- }
1473
- }
1474
- onChange?.(event, child);
1475
- };
1476
- const handleClear = (e) => {
1494
+ const [isExpanded, setIsExpanded] = useState10(false);
1495
+ if (!text) return null;
1496
+ const isLong = text.length > maxLength;
1497
+ const displayedText = isExpanded || !isLong ? text : `${text.slice(0, maxLength).trim()}...`;
1498
+ const toggleExpand = (e) => {
1477
1499
  e.stopPropagation();
1478
- if (!onChange) return;
1479
- const emptyValue = multiple ? [] : "";
1480
- const targetValue = defaultValueOnClear !== void 0 ? defaultValueOnClear : emptyValue;
1481
- const syntheticEvent = {
1482
- target: {
1483
- value: targetValue,
1484
- name: restProps.name
1485
- }
1486
- };
1487
- onChange(syntheticEvent, null);
1488
- };
1489
- const renderValueHandler = (selected) => {
1490
- if (!multiple) return void 0;
1491
- const currentSelected = selected;
1492
- if (currentSelected.length === 0) return null;
1493
- const selectedOptions = options.filter((opt) => currentSelected.includes(opt.value));
1494
- const visibleLabels = selectedOptions.slice(0, maxDisplayedTags).map((opt) => typeof opt.label === "string" ? opt.label : String(opt.value));
1495
- const hiddenCount = selectedOptions.length - maxDisplayedTags;
1496
- if (hiddenCount > 0) {
1497
- return `${visibleLabels.join(", ")} (+${hiddenCount})`;
1498
- }
1499
- return visibleLabels.join(", ");
1500
+ setIsExpanded((prev) => !prev);
1500
1501
  };
1501
- const isSmall = size === "small";
1502
- return /* @__PURE__ */ jsx9(
1503
- Tooltip6,
1502
+ return /* @__PURE__ */ jsxs8(
1503
+ Typography4,
1504
1504
  {
1505
- title: multiple ? Array.isArray(value) ? options.filter((opt) => value.includes(opt.value)).map((opt) => typeof opt.label === "string" ? opt.label : String(opt.value)).join(", ") : "" : options.find((opt) => opt.value === value)?.label ?? String(value ?? ""),
1506
- children: /* @__PURE__ */ jsxs8(FormControl, { fullWidth, size, sx: { mt: 1 }, children: [
1507
- /* @__PURE__ */ jsx9(InputLabel, { id: labelId, size: isSmall ? "small" : "medium", children: typeof label === "string" ? /* @__PURE__ */ jsx9(TranslateText, { overrideNamespace, children: label }) : label }),
1508
- /* @__PURE__ */ jsx9(
1509
- Select,
1505
+ variant: "caption",
1506
+ sx: {
1507
+ color: "text.secondary",
1508
+ fontStyle: "italic",
1509
+ display: "inline-block",
1510
+ ...sx
1511
+ },
1512
+ ...restProps,
1513
+ children: [
1514
+ label !== void 0 ? label : /* @__PURE__ */ jsxs8(Fragment8, { children: [
1515
+ /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Note" }),
1516
+ ": "
1517
+ ] }),
1518
+ " ",
1519
+ displayedText,
1520
+ " ",
1521
+ isLong && /* @__PURE__ */ jsx13(
1522
+ Link,
1510
1523
  {
1511
- labelId,
1512
- id,
1513
- value: safeValue,
1514
- label: typeof label === "string" ? /* @__PURE__ */ jsx9(TranslateText, { overrideNamespace, children: label }) : label,
1515
- size,
1516
- multiple,
1517
- disabled,
1518
- onChange: handleChange,
1519
- renderValue: multiple ? renderValueHandler : void 0,
1520
- ...restProps,
1521
- endAdornment: clearable && hasValue && !disabled ? /* @__PURE__ */ jsx9(InputAdornment5, { position: "end", sx: { mr: 1 }, children: /* @__PURE__ */ jsx9(
1522
- IconButton6,
1524
+ component: "button",
1525
+ type: "button",
1526
+ variant: "caption",
1527
+ underline: "hover",
1528
+ onClick: toggleExpand,
1529
+ sx: {
1530
+ fontStyle: "normal",
1531
+ fontWeight: "bold",
1532
+ ml: 0.5,
1533
+ cursor: "pointer",
1534
+ verticalAlign: "baseline"
1535
+ },
1536
+ children: isExpanded ? /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "less" }) : /* @__PURE__ */ jsxs8(Fragment8, { children: [
1537
+ /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "more" }),
1538
+ "..."
1539
+ ] })
1540
+ }
1541
+ )
1542
+ ]
1543
+ }
1544
+ );
1545
+ };
1546
+
1547
+ // src/UI/components/data.display/ErrorAlertComponent.tsx
1548
+ import { Alert, Box as Box7, Button as Button4, Typography as Typography5, useTheme } from "@mui/material";
1549
+ import ReplayIcon from "@mui/icons-material/Replay";
1550
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
1551
+ var ErrorIllustration = ({ size = 64 }) => {
1552
+ const theme = useTheme();
1553
+ const mainColor = theme.palette.error.main;
1554
+ const lightColor = theme.palette.error.light;
1555
+ return /* @__PURE__ */ jsx14(
1556
+ Box7,
1557
+ {
1558
+ sx: {
1559
+ display: "flex",
1560
+ alignItems: "center",
1561
+ justifyContent: "center",
1562
+ flexShrink: 0
1563
+ },
1564
+ children: /* @__PURE__ */ jsxs9(
1565
+ "svg",
1566
+ {
1567
+ width: size,
1568
+ height: size,
1569
+ viewBox: "0 0 100 100",
1570
+ fill: "none",
1571
+ xmlns: "http://www.w3.org/2000/svg",
1572
+ children: [
1573
+ /* @__PURE__ */ jsxs9(
1574
+ "circle",
1523
1575
  {
1524
- size: "small",
1525
- onClick: handleClear,
1526
- "aria-label": "clear selection",
1527
- edge: "end",
1528
- sx: { p: 0.5 },
1529
- children: /* @__PURE__ */ jsx9(CloseIcon, { fontSize: "small" })
1576
+ cx: "50",
1577
+ cy: "50",
1578
+ r: "42",
1579
+ fill: lightColor,
1580
+ fillOpacity: "0.25",
1581
+ children: [
1582
+ /* @__PURE__ */ jsx14(
1583
+ "animate",
1584
+ {
1585
+ attributeName: "r",
1586
+ values: "38;44;38",
1587
+ dur: "3s",
1588
+ repeatCount: "indefinite"
1589
+ }
1590
+ ),
1591
+ /* @__PURE__ */ jsx14(
1592
+ "animate",
1593
+ {
1594
+ attributeName: "fill-opacity",
1595
+ values: "0.2;0.4;0.2",
1596
+ dur: "3s",
1597
+ repeatCount: "indefinite"
1598
+ }
1599
+ )
1600
+ ]
1530
1601
  }
1531
- ) }) : null,
1532
- sx: {
1533
- // 1. Задаем фиксированную высоту для всего контейнера инпута
1534
- height: isSmall ? "40px" : "56px",
1535
- minHeight: isSmall ? "40px" : "56px",
1536
- // 2. Выравниваем внутренний класс текстового поля
1537
- "& .MuiSelect-select": {
1602
+ ),
1603
+ /* @__PURE__ */ jsx14("circle", { cx: "50", cy: "50", r: "34", fill: lightColor, fillOpacity: "0.35" }),
1604
+ /* @__PURE__ */ jsx14(
1605
+ "path",
1606
+ {
1607
+ d: "M50 20L80 72H20L50 20Z",
1608
+ fill: mainColor,
1609
+ stroke: theme.palette.background.paper,
1610
+ strokeWidth: "3",
1611
+ strokeLinejoin: "round"
1612
+ }
1613
+ ),
1614
+ /* @__PURE__ */ jsx14(
1615
+ "path",
1616
+ {
1617
+ d: "M50 36V54",
1618
+ stroke: "#FFFFFF",
1619
+ strokeWidth: "4",
1620
+ strokeLinecap: "round"
1621
+ }
1622
+ ),
1623
+ /* @__PURE__ */ jsx14("circle", { cx: "50", cy: "62", r: "2.5", fill: "#FFFFFF" }),
1624
+ /* @__PURE__ */ jsx14("circle", { cx: "16", cy: "30", r: "3", fill: mainColor, opacity: "0.4" }),
1625
+ /* @__PURE__ */ jsx14("circle", { cx: "84", cy: "30", r: "2", fill: mainColor, opacity: "0.6" }),
1626
+ /* @__PURE__ */ jsx14("circle", { cx: "88", cy: "68", r: "3", fill: mainColor, opacity: "0.3" })
1627
+ ]
1628
+ }
1629
+ )
1630
+ }
1631
+ );
1632
+ };
1633
+ var ErrorAlertComponent = ({
1634
+ overrideNamespace,
1635
+ title = "An error occurred",
1636
+ message,
1637
+ onRetry,
1638
+ retryText = "Retry",
1639
+ isRetrying = false
1640
+ }) => {
1641
+ return /* @__PURE__ */ jsx14(
1642
+ Alert,
1643
+ {
1644
+ severity: "error",
1645
+ icon: false,
1646
+ sx: {
1647
+ borderRadius: 1,
1648
+ p: 2.5,
1649
+ m: 3,
1650
+ border: "1px solid",
1651
+ borderColor: "error.light",
1652
+ bgcolor: (theme) => theme.palette.mode === "dark" ? "rgba(211, 47, 47, 0.08)" : "rgba(211, 47, 47, 0.04)",
1653
+ boxShadow: "0 4px 20px rgba(0, 0, 0, 0.05)",
1654
+ "& .MuiAlert-message": {
1655
+ width: "100%",
1656
+ p: 0
1657
+ }
1658
+ },
1659
+ children: /* @__PURE__ */ jsxs9(
1660
+ Box7,
1661
+ {
1662
+ sx: {
1663
+ display: "flex",
1664
+ flexDirection: { xs: "column", sm: "row" },
1665
+ alignItems: { xs: "flex-start", sm: "center" },
1666
+ gap: 2
1667
+ },
1668
+ children: [
1669
+ /* @__PURE__ */ jsx14(ErrorIllustration, { size: 68 }),
1670
+ /* @__PURE__ */ jsxs9(Box7, { sx: { flexGrow: 1 }, children: [
1671
+ typeof title === "string" ? /* @__PURE__ */ jsx14(
1672
+ Typography5,
1673
+ {
1674
+ variant: "subtitle1",
1675
+ sx: { fontWeight: 600, color: "error.main", mb: 0.5 },
1676
+ children: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace, children: title })
1677
+ }
1678
+ ) : title,
1679
+ typeof message === "string" ? /* @__PURE__ */ jsx14(Typography5, { variant: "body2", color: "text.secondary", children: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace, children: message }) }) : message
1680
+ ] }),
1681
+ onRetry && /* @__PURE__ */ jsx14(
1682
+ Box7,
1683
+ {
1684
+ sx: {
1685
+ alignSelf: { xs: "flex-end", sm: "center" },
1686
+ mt: { xs: 1, sm: 0 }
1687
+ },
1688
+ children: /* @__PURE__ */ jsx14(
1689
+ Button4,
1690
+ {
1691
+ variant: "outlined",
1692
+ color: "error",
1693
+ size: "small",
1694
+ disabled: isRetrying,
1695
+ onClick: onRetry,
1696
+ startIcon: /* @__PURE__ */ jsx14(
1697
+ ReplayIcon,
1698
+ {
1699
+ sx: {
1700
+ animation: isRetrying ? "spin 1s linear infinite" : "none",
1701
+ "@keyframes spin": {
1702
+ "0%": { transform: "rotate(0deg)" },
1703
+ "100%": { transform: "rotate(360deg)" }
1704
+ }
1705
+ }
1706
+ }
1707
+ ),
1708
+ sx: {
1709
+ //borderRadius: 2,
1710
+ textTransform: "none",
1711
+ fontWeight: 600,
1712
+ px: 2,
1713
+ py: 0.75,
1714
+ whiteSpace: "nowrap"
1715
+ },
1716
+ children: retryText
1717
+ }
1718
+ )
1719
+ }
1720
+ )
1721
+ ]
1722
+ }
1723
+ )
1724
+ }
1725
+ );
1726
+ };
1727
+
1728
+ // src/UI/components/layout/PageComponent.tsx
1729
+ import React10, { useState as useState11 } from "react";
1730
+ import {
1731
+ Box as Box8,
1732
+ Typography as Typography6,
1733
+ Button as Button5,
1734
+ IconButton as IconButton6,
1735
+ Menu,
1736
+ MenuItem as MenuItem2,
1737
+ ListItemIcon,
1738
+ ListItemText as ListItemText2,
1739
+ Divider,
1740
+ Tooltip as Tooltip6,
1741
+ useTheme as useTheme2,
1742
+ useMediaQuery,
1743
+ Stack,
1744
+ Fab as Fab2
1745
+ } from "@mui/material";
1746
+ import MoreVertIcon from "@mui/icons-material/MoreVert";
1747
+ import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
1748
+ import { Refresh as RefreshIcon } from "@mui/icons-material";
1749
+ import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1750
+ var getTruncateStyles = (mode = "truncate") => {
1751
+ switch (mode) {
1752
+ case "truncate":
1753
+ return { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", display: "block" };
1754
+ case "clamp-2":
1755
+ return { display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "normal" };
1756
+ case "wrap":
1757
+ default:
1758
+ return { whiteSpace: "normal", wordBreak: "break-word" };
1759
+ }
1760
+ };
1761
+ var PageHeader = ({
1762
+ overrideNamespace,
1763
+ icon,
1764
+ title,
1765
+ subtitle,
1766
+ tag,
1767
+ titleTruncateMode = "truncate",
1768
+ subtitleTruncateMode = "truncate",
1769
+ customFragment,
1770
+ primaryAction,
1771
+ secondaryActions = [],
1772
+ refreshAction,
1773
+ mobileBreakpoint = "sm",
1774
+ forceMobileView,
1775
+ sx = []
1776
+ }) => {
1777
+ const theme = useTheme2();
1778
+ const mediaIsMobile = useMediaQuery(theme.breakpoints.down(mobileBreakpoint));
1779
+ const isMobile = forceMobileView ?? mediaIsMobile;
1780
+ const [anchorEl, setAnchorEl] = useState11(null);
1781
+ const isMenuOpen = Boolean(anchorEl);
1782
+ const handleOpenMenu = (e) => setAnchorEl(e.currentTarget);
1783
+ const handleCloseMenu = () => setAnchorEl(null);
1784
+ const handleMenuAction = (cb) => {
1785
+ handleCloseMenu();
1786
+ cb();
1787
+ };
1788
+ const hasSecondaryActions = secondaryActions.length > 0;
1789
+ const hasActions = Boolean(primaryAction || hasSecondaryActions || refreshAction);
1790
+ return /* @__PURE__ */ jsxs10(
1791
+ Box8,
1792
+ {
1793
+ sx: [
1794
+ {
1795
+ display: "flex",
1796
+ alignItems: "center",
1797
+ justifyContent: "space-between",
1798
+ width: "100%",
1799
+ gap: { xs: 1.5, sm: 2.5 },
1800
+ py: 1.5,
1801
+ px: { xs: 1.5, sm: 2 },
1802
+ borderRadius: 2,
1803
+ backgroundColor: "background.paper",
1804
+ boxShadow: "0 1px 3px rgba(0,0,0,0.05)"
1805
+ },
1806
+ ...Array.isArray(sx) ? sx : [sx]
1807
+ ],
1808
+ children: [
1809
+ /* @__PURE__ */ jsxs10(Box8, { sx: { display: "flex", alignItems: "center", gap: { xs: 1.5, sm: 2 }, minWidth: 0, flex: 1 }, children: [
1810
+ icon && /* @__PURE__ */ jsx15(
1811
+ Box8,
1812
+ {
1813
+ sx: {
1538
1814
  display: "flex",
1539
1815
  alignItems: "center",
1540
- boxSizing: "border-box",
1541
- height: "100%",
1542
- minHeight: "100% !important",
1543
- py: 0,
1544
- lineHeight: "normal",
1545
- overflow: "hidden",
1546
- textOverflow: "ellipsis",
1547
- whiteSpace: "nowrap",
1548
- paddingRight: clearable && hasValue ? "64px !important" : "32px !important"
1549
- },
1550
- // 3. Корректируем иконку стрелки выпадающего списка
1551
- "& .MuiSelect-icon": {
1552
- top: "calc(50% - 12px)"
1553
- },
1554
- // 4. Корректируем расположение иконки очистки
1555
- "& .MuiInputAdornment-root": {
1556
- maxHeight: "100%",
1557
- height: "100%",
1558
- alignItems: "center"
1816
+ justifyContent: "center",
1817
+ width: { xs: 40, sm: 48 },
1818
+ height: { xs: 40, sm: 48 },
1819
+ borderRadius: 2.5,
1820
+ backgroundColor: "primary.50",
1821
+ color: "primary.main",
1822
+ flexShrink: 0,
1823
+ border: "1px solid",
1824
+ borderColor: "primary.100",
1825
+ "& svg": { fontSize: { xs: 22, sm: 26 } }
1559
1826
  },
1560
- ...sx
1561
- },
1562
- children: options.map((option) => {
1563
- const isSelected = multiple && selectedArray.includes(option.value);
1564
- const isDisabled = Boolean(isLimitReached && !isSelected);
1565
- return /* @__PURE__ */ jsxs8(
1566
- MenuItem2,
1827
+ children: icon
1828
+ }
1829
+ ),
1830
+ /* @__PURE__ */ jsxs10(Box8, { sx: { minWidth: 0, flex: 1 }, children: [
1831
+ tag && /* @__PURE__ */ jsx15(Box8, { sx: { mb: 0.5, display: "flex", alignItems: "center" }, children: tag }),
1832
+ /* @__PURE__ */ jsx15(Tooltip6, { title: titleTruncateMode === "truncate" ? /* @__PURE__ */ jsx15(TranslateText, { children: title }) : void 0, arrow: true, placement: "top", children: /* @__PURE__ */ jsx15(
1833
+ Typography6,
1834
+ {
1835
+ variant: "h5",
1836
+ component: "h1",
1837
+ sx: {
1838
+ fontWeight: 700,
1839
+ color: "text.primary",
1840
+ fontSize: { xs: "1.125rem", sm: "1.35rem" },
1841
+ lineHeight: 1.3,
1842
+ ...getTruncateStyles(titleTruncateMode)
1843
+ },
1844
+ children: /* @__PURE__ */ jsx15(TranslateText, { children: title })
1845
+ }
1846
+ ) }),
1847
+ subtitle && /* @__PURE__ */ jsx15(Tooltip6, { title: subtitleTruncateMode === "truncate" ? /* @__PURE__ */ jsx15(TranslateText, { children: subtitle }) : void 0, arrow: true, placement: "top", children: /* @__PURE__ */ jsx15(
1848
+ Typography6,
1849
+ {
1850
+ variant: "body2",
1851
+ sx: {
1852
+ color: "text.secondary",
1853
+ mt: 0.25,
1854
+ fontSize: { xs: "0.8125rem", sm: "0.875rem" },
1855
+ lineHeight: 1.4,
1856
+ ...getTruncateStyles(subtitleTruncateMode)
1857
+ },
1858
+ children: /* @__PURE__ */ jsx15(TranslateText, { children: subtitle })
1859
+ }
1860
+ ) })
1861
+ ] })
1862
+ ] }),
1863
+ hasActions && /* @__PURE__ */ jsx15(Box8, { sx: { flexShrink: 0, display: "flex", alignItems: "center", gap: 1 }, children: isMobile ? (
1864
+ /* MOBILE: IconButton with MoreVertIcon showing ALL actions inside Menu */
1865
+ /* @__PURE__ */ jsxs10(Fragment9, { children: [
1866
+ /* @__PURE__ */ jsx15(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Actions" }), children: /* @__PURE__ */ jsx15(
1867
+ IconButton6,
1868
+ {
1869
+ onClick: handleOpenMenu,
1870
+ sx: { border: "1px solid", borderColor: "divider", borderRadius: 2, p: 1 },
1871
+ children: /* @__PURE__ */ jsx15(MoreVertIcon, {})
1872
+ }
1873
+ ) }),
1874
+ /* @__PURE__ */ jsxs10(
1875
+ Menu,
1876
+ {
1877
+ anchorEl,
1878
+ open: isMenuOpen,
1879
+ onClose: handleCloseMenu,
1880
+ transformOrigin: { horizontal: "right", vertical: "top" },
1881
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
1882
+ slotProps: { paper: { elevation: 4, sx: { minWidth: 200, borderRadius: 2, mt: 1, p: 0.5 } } },
1883
+ children: [
1884
+ primaryAction && /* @__PURE__ */ jsxs10(Fragment9, { children: [
1885
+ /* @__PURE__ */ jsxs10(
1886
+ MenuItem2,
1887
+ {
1888
+ onClick: () => handleMenuAction(primaryAction.onClick),
1889
+ disabled: primaryAction.disabled,
1890
+ sx: {
1891
+ borderRadius: 1.5,
1892
+ fontWeight: 700,
1893
+ backgroundColor: "primary.50",
1894
+ color: primaryAction.color ? `${primaryAction.color}.main` : "primary.main",
1895
+ py: 1.2,
1896
+ px: 1.5
1897
+ },
1898
+ children: [
1899
+ primaryAction.icon && /* @__PURE__ */ jsx15(ListItemIcon, { sx: { color: "inherit", minWidth: 32 }, children: primaryAction.icon }),
1900
+ /* @__PURE__ */ jsx15(ListItemText2, { primary: /* @__PURE__ */ jsx15(TranslateText, { children: primaryAction.label }), slotProps: { primary: { sx: { fontWeight: 700, fontSize: "0.9rem" } } } })
1901
+ ]
1902
+ }
1903
+ ),
1904
+ hasSecondaryActions && /* @__PURE__ */ jsx15(Divider, { sx: { my: 0.75 } })
1905
+ ] }),
1906
+ secondaryActions.map((action) => /* @__PURE__ */ jsxs10(React10.Fragment, { children: [
1907
+ action.divider && /* @__PURE__ */ jsx15(Divider, { sx: { my: 0.5 } }),
1908
+ /* @__PURE__ */ jsxs10(
1909
+ MenuItem2,
1910
+ {
1911
+ onClick: () => handleMenuAction(action.onClick),
1912
+ disabled: action.disabled,
1913
+ sx: { borderRadius: 1, py: 1, px: 1.5, color: action.color ? `${action.color}.main` : "text.primary" },
1914
+ children: [
1915
+ action.icon && /* @__PURE__ */ jsx15(ListItemIcon, { sx: { color: action.color ? `${action.color}.main` : "text.secondary", minWidth: 32 }, children: action.icon }),
1916
+ /* @__PURE__ */ jsx15(ListItemText2, { primary: action.label, slotProps: { primary: { sx: { fontSize: "0.875rem" } } } })
1917
+ ]
1918
+ }
1919
+ )
1920
+ ] }, action.id)),
1921
+ refreshAction && /* @__PURE__ */ jsxs10(Fragment9, { children: [
1922
+ /* @__PURE__ */ jsx15(Divider, { sx: { my: 0.5 } }),
1923
+ /* @__PURE__ */ jsxs10(
1924
+ MenuItem2,
1925
+ {
1926
+ onClick: () => handleMenuAction(refreshAction.onClick),
1927
+ disabled: refreshAction.disabled,
1928
+ sx: {
1929
+ borderRadius: 1.5,
1930
+ fontWeight: 700,
1931
+ backgroundColor: "primary.50",
1932
+ py: 1.2,
1933
+ px: 1.5
1934
+ },
1935
+ children: [
1936
+ /* @__PURE__ */ jsx15(ListItemIcon, { sx: { color: "inherit", minWidth: 32 }, children: /* @__PURE__ */ jsx15(RefreshIcon, {}) }),
1937
+ /* @__PURE__ */ jsx15(ListItemText2, { primary: /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), slotProps: { primary: { sx: { fontWeight: 700, fontSize: "0.9rem" } } } })
1938
+ ]
1939
+ }
1940
+ )
1941
+ ] })
1942
+ ]
1943
+ }
1944
+ )
1945
+ ] })
1946
+ ) : (
1947
+ /* DESKTOP: Primary Action Button + Secondary Actions Dropdown Button */
1948
+ /* @__PURE__ */ jsxs10(Box8, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
1949
+ (primaryAction || refreshAction) && /* @__PURE__ */ jsxs10(Stack, { direction: "row", spacing: 2, children: [
1950
+ primaryAction && /* @__PURE__ */ jsx15(
1951
+ Button5,
1567
1952
  {
1568
- value: option.value,
1569
- disabled: isDisabled,
1570
- children: [
1571
- multiple && withCheckboxes && /* @__PURE__ */ jsx9(Checkbox, { checked: isSelected, size, disabled: isDisabled }),
1572
- /* @__PURE__ */ jsx9(
1573
- ListItemText,
1953
+ variant: primaryAction.variant || "contained",
1954
+ color: primaryAction.color || "primary",
1955
+ onClick: primaryAction.onClick,
1956
+ disabled: primaryAction.disabled,
1957
+ startIcon: primaryAction.icon,
1958
+ sx: { borderRadius: 2, textTransform: "none", fontWeight: 600, px: 2, py: 0.85 },
1959
+ children: /* @__PURE__ */ jsx15(TranslateText, { children: primaryAction.label })
1960
+ }
1961
+ ),
1962
+ refreshAction && /* @__PURE__ */ jsx15(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), children: /* @__PURE__ */ jsx15(
1963
+ Fab2,
1964
+ {
1965
+ color: "default",
1966
+ onClick: refreshAction.onClick,
1967
+ disabled: refreshAction.disabled,
1968
+ "aria-label": "refresh",
1969
+ size: "small",
1970
+ children: /* @__PURE__ */ jsx15(RefreshIcon, {})
1971
+ }
1972
+ ) })
1973
+ ] }),
1974
+ hasSecondaryActions && /* @__PURE__ */ jsxs10(Fragment9, { children: [
1975
+ /* @__PURE__ */ jsx15(
1976
+ IconButton6,
1977
+ {
1978
+ onClick: handleOpenMenu,
1979
+ sx: { border: "1px solid", borderColor: "divider", borderRadius: 2, p: 1 },
1980
+ children: /* @__PURE__ */ jsx15(KeyboardArrowDownIcon, {})
1981
+ }
1982
+ ),
1983
+ /* @__PURE__ */ jsx15(
1984
+ Menu,
1985
+ {
1986
+ anchorEl,
1987
+ open: isMenuOpen,
1988
+ onClose: handleCloseMenu,
1989
+ transformOrigin: { horizontal: "right", vertical: "top" },
1990
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
1991
+ slotProps: { paper: { elevation: 4, sx: { minWidth: 180, borderRadius: 2, mt: 1, p: 0.5 } } },
1992
+ children: secondaryActions.map((action) => /* @__PURE__ */ jsxs10(React10.Fragment, { children: [
1993
+ action.divider && /* @__PURE__ */ jsx15(Divider, { sx: { my: 0.5 } }),
1994
+ /* @__PURE__ */ jsxs10(
1995
+ MenuItem2,
1574
1996
  {
1575
- primary: option.isItalic ? /* @__PURE__ */ jsx9("em", { children: option.label }) : option.label
1997
+ onClick: () => handleMenuAction(action.onClick),
1998
+ disabled: action.disabled,
1999
+ sx: { borderRadius: 1, py: 0.85, color: action.color ? `${action.color}.main` : "text.primary" },
2000
+ children: [
2001
+ action.icon && /* @__PURE__ */ jsx15(ListItemIcon, { sx: { color: action.color ? `${action.color}.main` : "text.secondary", minWidth: 32 }, children: action.icon }),
2002
+ /* @__PURE__ */ jsx15(ListItemText2, { primary: action.label, slotProps: { primary: { sx: { fontSize: "0.875rem" } } } })
2003
+ ]
1576
2004
  }
1577
2005
  )
1578
- ]
1579
- },
1580
- String(option.value)
1581
- );
1582
- })
1583
- }
1584
- ),
1585
- helperText && /* @__PURE__ */ jsx9(FormHelperText, { children: helperText })
1586
- ] })
2006
+ ] }, action.id))
2007
+ }
2008
+ )
2009
+ ] })
2010
+ ] })
2011
+ ) }),
2012
+ customFragment && /* @__PURE__ */ jsx15(Fragment9, { children: customFragment })
2013
+ ]
1587
2014
  }
1588
2015
  );
1589
2016
  };
1590
-
1591
- // src/UI/components/data.display/ExpandableNoteComponent.tsx
1592
- import { useState as useState10 } from "react";
1593
- import { Typography as Typography5, Link } from "@mui/material";
1594
- import { Fragment as Fragment8, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1595
- var ExpandableNoteComponent = ({
1596
- overrideNamespace,
1597
- text,
1598
- maxLength = 100,
1599
- label,
1600
- sx,
1601
- ...restProps
2017
+ var PageContainer = ({ children }) => {
2018
+ return /* @__PURE__ */ jsx15(
2019
+ Box8,
2020
+ {
2021
+ sx: {
2022
+ width: "100%",
2023
+ boxSizing: "border-box",
2024
+ p: { xs: 1.5, sm: 3 },
2025
+ backgroundColor: "background.paper"
2026
+ },
2027
+ children
2028
+ }
2029
+ );
2030
+ };
2031
+ var PageComponent = ({
2032
+ header,
2033
+ children
1602
2034
  }) => {
1603
- const [isExpanded, setIsExpanded] = useState10(false);
1604
- if (!text) return null;
1605
- const isLong = text.length > maxLength;
1606
- const displayedText = isExpanded || !isLong ? text : `${text.slice(0, maxLength).trim()}...`;
1607
- const toggleExpand = (e) => {
1608
- e.stopPropagation();
1609
- setIsExpanded((prev) => !prev);
1610
- };
1611
- return /* @__PURE__ */ jsxs9(
1612
- Typography5,
2035
+ return /* @__PURE__ */ jsx15(
2036
+ Box8,
1613
2037
  {
1614
- variant: "caption",
1615
2038
  sx: {
1616
- color: "text.secondary",
1617
- fontStyle: "italic",
1618
- display: "inline-block",
1619
- ...sx
2039
+ //pt: 2,
2040
+ flexGrow: 1,
2041
+ minHeight: 0,
2042
+ overflowY: "auto",
2043
+ boxSizing: "border-box"
1620
2044
  },
1621
- ...restProps,
1622
- children: [
1623
- label !== void 0 ? label : /* @__PURE__ */ jsxs9(Fragment8, { children: [
1624
- /* @__PURE__ */ jsx10(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Note" }),
1625
- ": "
1626
- ] }),
1627
- " ",
1628
- displayedText,
1629
- " ",
1630
- isLong && /* @__PURE__ */ jsx10(
1631
- Link,
1632
- {
1633
- component: "button",
1634
- type: "button",
1635
- variant: "caption",
1636
- underline: "hover",
1637
- onClick: toggleExpand,
1638
- sx: {
1639
- fontStyle: "normal",
1640
- fontWeight: "bold",
1641
- ml: 0.5,
1642
- cursor: "pointer",
1643
- verticalAlign: "baseline"
1644
- },
1645
- children: isExpanded ? /* @__PURE__ */ jsx10(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "less" }) : /* @__PURE__ */ jsxs9(Fragment8, { children: [
1646
- /* @__PURE__ */ jsx10(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "more" }),
1647
- "..."
1648
- ] })
1649
- }
1650
- )
1651
- ]
2045
+ children: /* @__PURE__ */ jsxs10(PageContainer, { children: [
2046
+ header && /* @__PURE__ */ jsx15(PageHeader, { ...header }),
2047
+ children
2048
+ ] })
2049
+ }
2050
+ );
2051
+ };
2052
+
2053
+ // src/UI/components/layout/FilterContainerComponent.tsx
2054
+ import React11 from "react";
2055
+ import { Grid, Paper } from "@mui/material";
2056
+ import { jsx as jsx16 } from "react/jsx-runtime";
2057
+ var FilterContainerComponent = ({
2058
+ sections,
2059
+ children,
2060
+ sx
2061
+ }) => {
2062
+ return /* @__PURE__ */ jsx16(
2063
+ Paper,
2064
+ {
2065
+ variant: "outlined",
2066
+ sx: [
2067
+ { p: 2, mb: 3 },
2068
+ ...Array.isArray(sx) ? sx : [sx]
2069
+ ],
2070
+ children: /* @__PURE__ */ jsx16(Grid, { container: true, spacing: 2, sx: { alignItems: "center" }, children: sections ? sections.map((sec, idx) => /* @__PURE__ */ jsx16(React11.Fragment, { children: sec }, idx)) : children })
1652
2071
  }
1653
2072
  );
1654
2073
  };
1655
2074
 
1656
- // src/UI/widgets/page/PageLinkWidget.tsx
2075
+ // src/UI/components/layout/PageLinkComponent.tsx
1657
2076
  import { ArrowRight, Settings } from "@mui/icons-material";
1658
2077
  import {
1659
- Button as Button2,
2078
+ Button as Button6,
1660
2079
  Card,
1661
2080
  CardActions,
1662
2081
  CardContent,
1663
2082
  CardHeader,
1664
- Divider,
2083
+ Divider as Divider2,
1665
2084
  List,
1666
2085
  ListItem,
1667
- ListItemIcon,
1668
- ListItemText as ListItemText2,
1669
- Typography as Typography6,
2086
+ ListItemIcon as ListItemIcon2,
2087
+ ListItemText as ListItemText3,
2088
+ Typography as Typography7,
1670
2089
  Link as MuiLink
1671
2090
  } from "@mui/material";
1672
- import React10 from "react";
2091
+ import React12 from "react";
1673
2092
  import { Link as RouterLink, useNavigate } from "react-router-dom";
1674
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1675
- var PageLinkWidget = ({
2093
+ import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
2094
+ var PageLinkComponent = ({
1676
2095
  overrideNamespace,
1677
2096
  title,
1678
2097
  subheader,
@@ -1684,7 +2103,7 @@ var PageLinkWidget = ({
1684
2103
  bgcolor
1685
2104
  }) => {
1686
2105
  const navigate = useNavigate();
1687
- return /* @__PURE__ */ jsxs10(
2106
+ return /* @__PURE__ */ jsxs11(
1688
2107
  Card,
1689
2108
  {
1690
2109
  sx: (theme) => ({
@@ -1698,20 +2117,20 @@ var PageLinkWidget = ({
1698
2117
  ) : typeof bgcolor === "function" ? theme.palette.getContrastText(bgcolor(theme)) : theme.palette.getContrastText(bgcolor) : "text.primary"
1699
2118
  }),
1700
2119
  children: [
1701
- /* @__PURE__ */ jsx11(
2120
+ /* @__PURE__ */ jsx17(
1702
2121
  CardHeader,
1703
2122
  {
1704
- avatar: icon ? React10.cloneElement(icon, {
2123
+ avatar: icon ? React12.cloneElement(icon, {
1705
2124
  sx: { color: bgcolor ? "inherit" : "primary", ...icon.props.sx }
1706
- }) : /* @__PURE__ */ jsx11(Settings, { color: bgcolor ? "inherit" : "primary" }),
1707
- title: /* @__PURE__ */ jsx11(Typography6, { variant: "h6", component: "div", color: "inherit", children: typeof title === "string" ? /* @__PURE__ */ jsx11(TranslateText, { overrideNamespace, children: title }) : title }),
1708
- subheader: subheader && /* @__PURE__ */ jsx11(Typography6, { variant: "body2", sx: { opacity: 0.8, color: "inherit" }, children: typeof subheader === "string" ? /* @__PURE__ */ jsx11(TranslateText, { overrideNamespace, children: subheader }) : subheader })
2125
+ }) : /* @__PURE__ */ jsx17(Settings, { color: bgcolor ? "inherit" : "primary" }),
2126
+ title: /* @__PURE__ */ jsx17(Typography7, { variant: "h6", component: "div", color: "inherit", children: typeof title === "string" ? /* @__PURE__ */ jsx17(TranslateText, { overrideNamespace, children: title }) : title }),
2127
+ subheader: subheader && /* @__PURE__ */ jsx17(Typography7, { variant: "body2", sx: { opacity: 0.8, color: "inherit" }, children: typeof subheader === "string" ? /* @__PURE__ */ jsx17(TranslateText, { overrideNamespace, children: subheader }) : subheader })
1709
2128
  }
1710
2129
  ),
1711
- /* @__PURE__ */ jsx11(Divider, { sx: { borderColor: "inherit", opacity: 0.2 } }),
1712
- /* @__PURE__ */ jsxs10(CardContent, { sx: { flexGrow: 1 }, children: [
1713
- /* @__PURE__ */ jsx11(Typography6, { variant: "body2", sx: { opacity: 0.85, color: "inherit" }, children: typeof description === "string" ? /* @__PURE__ */ jsx11(TranslateText, { overrideNamespace, children: description }) : description }),
1714
- links && links.length > 0 && /* @__PURE__ */ jsx11(List, { dense: true, disablePadding: true, children: links.filter((f) => !f.hidden).map((link, index) => /* @__PURE__ */ jsxs10(
2130
+ /* @__PURE__ */ jsx17(Divider2, { sx: { borderColor: "inherit", opacity: 0.2 } }),
2131
+ /* @__PURE__ */ jsxs11(CardContent, { sx: { flexGrow: 1 }, children: [
2132
+ /* @__PURE__ */ jsx17(Typography7, { variant: "body2", sx: { opacity: 0.85, color: "inherit" }, children: typeof description === "string" ? /* @__PURE__ */ jsx17(TranslateText, { overrideNamespace, children: description }) : description }),
2133
+ links && links.length > 0 && /* @__PURE__ */ jsx17(List, { dense: true, disablePadding: true, children: links.filter((f) => !f.hidden).map((link, index) => /* @__PURE__ */ jsxs11(
1715
2134
  ListItem,
1716
2135
  {
1717
2136
  disablePadding: true,
@@ -1723,18 +2142,18 @@ var PageLinkWidget = ({
1723
2142
  }
1724
2143
  },
1725
2144
  children: [
1726
- /* @__PURE__ */ jsx11(
1727
- ListItemIcon,
2145
+ /* @__PURE__ */ jsx17(
2146
+ ListItemIcon2,
1728
2147
  {
1729
2148
  sx: { minWidth: 30, cursor: "pointer", color: "inherit" },
1730
2149
  onClick: () => {
1731
2150
  if (link?.href) navigate(link.href);
1732
2151
  },
1733
- children: /* @__PURE__ */ jsx11(ArrowRight, { fontSize: "small", color: "inherit" })
2152
+ children: /* @__PURE__ */ jsx17(ArrowRight, { fontSize: "small", color: "inherit" })
1734
2153
  }
1735
2154
  ),
1736
- /* @__PURE__ */ jsx11(ListItemText2, { children: link.onClick ? /* @__PURE__ */ jsx11(
1737
- Button2,
2155
+ /* @__PURE__ */ jsx17(ListItemText3, { children: link.onClick ? /* @__PURE__ */ jsx17(
2156
+ Button6,
1738
2157
  {
1739
2158
  size: "small",
1740
2159
  variant: "text",
@@ -1757,9 +2176,9 @@ var PageLinkWidget = ({
1757
2176
  // Эффект подчеркивания, как у ссылки
1758
2177
  }
1759
2178
  },
1760
- children: typeof link.text === "string" ? /* @__PURE__ */ jsx11(TranslateText, { overrideNamespace, children: link.text }) : link.text
2179
+ children: typeof link.text === "string" ? /* @__PURE__ */ jsx17(TranslateText, { overrideNamespace, children: link.text }) : link.text
1761
2180
  }
1762
- ) : link.href ? /* @__PURE__ */ jsx11(
2181
+ ) : link.href ? /* @__PURE__ */ jsx17(
1763
2182
  MuiLink,
1764
2183
  {
1765
2184
  component: RouterLink,
@@ -1775,112 +2194,30 @@ var PageLinkWidget = ({
1775
2194
  "&:hover": {
1776
2195
  opacity: 0.75,
1777
2196
  backgroundColor: "transparent"
1778
- }
1779
- },
1780
- children: typeof link.text === "string" ? /* @__PURE__ */ jsx11(TranslateText, { overrideNamespace, children: link.text }) : link.text
1781
- }
1782
- ) : /* @__PURE__ */ jsx11(Typography6, { variant: "body2", sx: { fontWeight: 500, color: "inherit" }, children: typeof link.text === "string" ? /* @__PURE__ */ jsx11(TranslateText, { overrideNamespace, children: link.text }) : link.text }) })
1783
- ]
1784
- },
1785
- index
1786
- )) })
1787
- ] }),
1788
- actionButtonText && onActionButtonClick && /* @__PURE__ */ jsx11(CardActions, { sx: { justifyContent: "flex-end", padding: 2 }, children: /* @__PURE__ */ jsx11(Button2, { size: "small", variant: "contained", onClick: onActionButtonClick, children: typeof actionButtonText === "string" ? /* @__PURE__ */ jsx11(TranslateText, { overrideNamespace, children: actionButtonText }) : actionButtonText }) })
1789
- ]
1790
- }
1791
- );
1792
- };
1793
-
1794
- // src/UI/components/inputs/SwitchComponent.tsx
1795
- import {
1796
- FormControlLabel,
1797
- Box as Box6,
1798
- Switch
1799
- } from "@mui/material";
1800
- import { jsx as jsx12 } from "react/jsx-runtime";
1801
- var SwitchComponent = ({
1802
- checked = false,
1803
- onChange,
1804
- label,
1805
- checkedLabel,
1806
- uncheckedLabel,
1807
- overrideNamespace,
1808
- switchProps,
1809
- ...props
1810
- }) => {
1811
- const currentLabel = label ?? (checked ? checkedLabel : uncheckedLabel);
1812
- const renderLabel = (node) => {
1813
- if (typeof node === "string") {
1814
- return /* @__PURE__ */ jsx12(TranslateText, { overrideNamespace, children: node });
1815
- }
1816
- return node;
1817
- };
1818
- return /* @__PURE__ */ jsx12(Box6, { sx: { display: "inline-flex", alignItems: "center", gap: 0.5 }, children: /* @__PURE__ */ jsx12(
1819
- FormControlLabel,
1820
- {
1821
- control: /* @__PURE__ */ jsx12(
1822
- Switch,
1823
- {
1824
- checked,
1825
- onChange,
1826
- ...switchProps
1827
- }
1828
- ),
1829
- label: renderLabel(currentLabel),
1830
- ...props
1831
- }
1832
- ) });
1833
- };
1834
-
1835
- // src/UI/components/inputs/CheckboxComponent.tsx
1836
- import {
1837
- FormControlLabel as FormControlLabel2,
1838
- Checkbox as Checkbox2,
1839
- Box as Box7
1840
- } from "@mui/material";
1841
- import { jsx as jsx13 } from "react/jsx-runtime";
1842
- var CheckboxComponent = ({
1843
- checked = false,
1844
- onChange,
1845
- label,
1846
- checkedLabel,
1847
- uncheckedLabel,
1848
- overrideNamespace,
1849
- checkboxProps,
1850
- ...props
1851
- }) => {
1852
- const currentLabel = label ?? (checked ? checkedLabel : uncheckedLabel);
1853
- const renderLabel = (node) => {
1854
- if (typeof node === "string") {
1855
- return /* @__PURE__ */ jsx13(TranslateText, { overrideNamespace, children: node });
1856
- }
1857
- return node;
1858
- };
1859
- return /* @__PURE__ */ jsx13(Box7, { sx: { display: "inline-flex", alignItems: "center", gap: 0.5 }, children: /* @__PURE__ */ jsx13(
1860
- FormControlLabel2,
1861
- {
1862
- control: /* @__PURE__ */ jsx13(
1863
- Checkbox2,
1864
- {
1865
- checked,
1866
- onChange,
1867
- ...checkboxProps
1868
- }
1869
- ),
1870
- label: renderLabel(currentLabel),
1871
- ...props
2197
+ }
2198
+ },
2199
+ children: typeof link.text === "string" ? /* @__PURE__ */ jsx17(TranslateText, { overrideNamespace, children: link.text }) : link.text
2200
+ }
2201
+ ) : /* @__PURE__ */ jsx17(Typography7, { variant: "body2", sx: { fontWeight: 500, color: "inherit" }, children: typeof link.text === "string" ? /* @__PURE__ */ jsx17(TranslateText, { overrideNamespace, children: link.text }) : link.text }) })
2202
+ ]
2203
+ },
2204
+ index
2205
+ )) })
2206
+ ] }),
2207
+ actionButtonText && onActionButtonClick && /* @__PURE__ */ jsx17(CardActions, { sx: { justifyContent: "flex-end", padding: 2 }, children: /* @__PURE__ */ jsx17(Button6, { size: "small", variant: "contained", onClick: onActionButtonClick, children: typeof actionButtonText === "string" ? /* @__PURE__ */ jsx17(TranslateText, { overrideNamespace, children: actionButtonText }) : actionButtonText }) })
2208
+ ]
1872
2209
  }
1873
- ) });
2210
+ );
1874
2211
  };
1875
2212
 
1876
- // src/UI/widgets/page/CollapsedWidgetContainer.tsx
2213
+ // src/UI/components/layout/CollapsedContainerComponent.tsx
1877
2214
  import { ExpandMore as ExpandMoreIcon } from "@mui/icons-material";
1878
- import { Avatar as Avatar3, Box as Box8, Card as Card2, CardContent as CardContent2, CardHeader as CardHeader2, Collapse, Divider as Divider2, IconButton as IconButton7, styled, Tooltip as Tooltip7, Typography as Typography7 } from "@mui/material";
1879
- import { useState as useState11 } from "react";
1880
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1881
- var ExpandMore = styled((props) => {
2215
+ import { Avatar as Avatar3, Box as Box9, Card as Card2, CardContent as CardContent2, CardHeader as CardHeader2, Collapse, Divider as Divider3, IconButton as IconButton7, styled as styled2, Tooltip as Tooltip7, Typography as Typography8 } from "@mui/material";
2216
+ import { useState as useState12 } from "react";
2217
+ import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
2218
+ var ExpandMore = styled2((props) => {
1882
2219
  const { expand, ...other } = props;
1883
- return /* @__PURE__ */ jsx14(IconButton7, { size: "small", ...other, children: /* @__PURE__ */ jsx14(ExpandMoreIcon, {}) });
2220
+ return /* @__PURE__ */ jsx18(IconButton7, { size: "small", ...other, children: /* @__PURE__ */ jsx18(ExpandMoreIcon, {}) });
1884
2221
  })(({ theme, expand }) => ({
1885
2222
  transform: !expand ? "rotate(0deg)" : "rotate(180deg)",
1886
2223
  transition: theme.transitions.create("transform", {
@@ -1893,16 +2230,16 @@ var ExpandMore = styled((props) => {
1893
2230
  backgroundColor: expand ? theme.palette.primary.dark : theme.palette.action.hover
1894
2231
  }
1895
2232
  }));
1896
- var CollapsedWidgetContainer = (props) => {
2233
+ var CollapsedContainerComponent = (props) => {
1897
2234
  const { displayState } = useAppTheme();
1898
- const [expanded, setExpanded] = useState11(props.expanded === void 0 ? false : props.expanded);
2235
+ const [expanded, setExpanded] = useState12(props.expanded === void 0 ? false : props.expanded);
1899
2236
  const handleExpandClick = () => {
1900
2237
  setExpanded(!expanded);
1901
2238
  props.onExpanded && props.onExpanded(!expanded);
1902
2239
  };
1903
- return /* @__PURE__ */ jsxs11(Card2, { sx: { width: "100%", overflow: "hidden", mb: 2, boxShadow: displayState.isMobile ? "none" : props.disableShadow ? "none" : "0 20px 25px -5px rgb(0 0 0 / 0.1)", borderRadius: displayState.isMobile ? 0 : 1 }, children: [
1904
- /* @__PURE__ */ jsxs11(
1905
- Box8,
2240
+ return /* @__PURE__ */ jsxs12(Card2, { sx: { width: "100%", overflow: "hidden", mb: 2, boxShadow: displayState.isMobile ? "none" : props.disableShadow ? "none" : "0 20px 25px -5px rgb(0 0 0 / 0.1)", borderRadius: displayState.isMobile ? 0 : 1 }, children: [
2241
+ /* @__PURE__ */ jsxs12(
2242
+ Box9,
1906
2243
  {
1907
2244
  onClick: () => handleExpandClick(),
1908
2245
  sx: {
@@ -1913,739 +2250,316 @@ var CollapsedWidgetContainer = (props) => {
1913
2250
  pr: 2
1914
2251
  },
1915
2252
  children: [
1916
- /* @__PURE__ */ jsx14(
2253
+ /* @__PURE__ */ jsx18(
1917
2254
  CardHeader2,
1918
2255
  {
1919
2256
  sx: { flexGrow: 1 },
1920
- avatar: /* @__PURE__ */ jsx14(Avatar3, { sx: { bgcolor: "primary.main" }, children: props.icon }),
1921
- title: typeof props.title === "string" ? /* @__PURE__ */ jsx14(Typography7, { variant: "subtitle1", sx: { fontWeight: "700" }, children: /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: props.overrideNamespace, children: props.title }) }) : props.title,
1922
- subheader: typeof props.subtitle === "string" ? /* @__PURE__ */ jsx14(TranslateText, { overrideNamespace: props.overrideNamespace, children: props.subtitle }) : props.subtitle
2257
+ avatar: /* @__PURE__ */ jsx18(Avatar3, { sx: { bgcolor: "primary.main" }, children: props.icon }),
2258
+ title: typeof props.title === "string" ? /* @__PURE__ */ jsx18(Typography8, { variant: "subtitle1", sx: { fontWeight: "700" }, children: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: props.overrideNamespace, children: props.title }) }) : props.title,
2259
+ subheader: typeof props.subtitle === "string" ? /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: props.overrideNamespace, children: props.subtitle }) : props.subtitle
1923
2260
  }
1924
2261
  ),
1925
- /* @__PURE__ */ jsx14(Tooltip7, { title: expanded ? "Show Less" : "Show More", children: /* @__PURE__ */ jsx14(Box8, { sx: { ml: 1 }, children: /* @__PURE__ */ jsx14(
2262
+ /* @__PURE__ */ jsx18(Tooltip7, { title: expanded ? "Show Less" : "Show More", children: /* @__PURE__ */ jsx18(Box9, { sx: { ml: 1 }, children: /* @__PURE__ */ jsx18(
1926
2263
  ExpandMore,
1927
2264
  {
1928
2265
  expand: expanded,
1929
2266
  onClick: handleExpandClick,
1930
- "aria-expanded": expanded
1931
- }
1932
- ) }) })
1933
- ]
1934
- }
1935
- ),
1936
- /* @__PURE__ */ jsxs11(Collapse, { in: expanded, timeout: "auto", children: [
1937
- /* @__PURE__ */ jsx14(Divider2, { variant: "middle" }),
1938
- /* @__PURE__ */ jsx14(CardContent2, { children: props.children })
1939
- ] })
1940
- ] });
1941
- };
1942
-
1943
- // src/UI/components/buttons/RefreshButtonComponent.tsx
1944
- import { useState as useState12 } from "react";
1945
- import {
1946
- Button as Button3,
1947
- Fab,
1948
- styled as styled2
1949
- } from "@mui/material";
1950
- import RefreshIconMui from "@mui/icons-material/Refresh";
1951
- import { Fragment as Fragment9, jsx as jsx15 } from "react/jsx-runtime";
1952
- var AnimatedRefreshIcon = styled2(RefreshIconMui, {
1953
- shouldForwardProp: (prop) => prop !== "isSpinning"
1954
- })(({ isSpinning }) => ({
1955
- animation: isSpinning ? "spin 1s linear infinite" : "none",
1956
- "@keyframes spin": {
1957
- "0%": {
1958
- transform: "rotate(0deg)"
1959
- },
1960
- "100%": {
1961
- transform: "rotate(360deg)"
1962
- }
1963
- }
1964
- }));
1965
- var RefreshButtonComponent = ({
1966
- overrideNamespace,
1967
- size = "small",
1968
- onClick,
1969
- disabled = false,
1970
- fullWidth = false,
1971
- loading: externalLoading,
1972
- tooltip,
1973
- mobileViewOnly,
1974
- disableMobileView,
1975
- hideTooltipOnMobile,
1976
- hideTooltipOnDesktop
1977
- }) => {
1978
- const { displayState } = useAppTheme();
1979
- const [internalLoading, setInternalLoading] = useState12(false);
1980
- const isLoading = externalLoading !== void 0 ? externalLoading : internalLoading;
1981
- const handleClick = async (event) => {
1982
- if (!onClick || isLoading || disabled) return;
1983
- try {
1984
- setInternalLoading(true);
1985
- await onClick(event);
1986
- } finally {
1987
- setInternalLoading(false);
1988
- }
1989
- };
1990
- const renderIcon = () => /* @__PURE__ */ jsx15(AnimatedRefreshIcon, { fontSize: size, isSpinning: isLoading });
1991
- if (displayState.isMobile && !disableMobileView || mobileViewOnly) {
1992
- return /* @__PURE__ */ jsx15(TranslatableTooltipComponent, { title: hideTooltipOnMobile ? /* @__PURE__ */ jsx15(Fragment9, {}) : tooltip || /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), children: /* @__PURE__ */ jsx15("span", { children: /* @__PURE__ */ jsx15(
1993
- Fab,
1994
- {
1995
- size,
1996
- color: "inherit",
1997
- onClick: handleClick,
1998
- disabled: disabled || isLoading,
1999
- "aria-label": "refresh",
2000
- children: renderIcon()
2001
- }
2002
- ) }) });
2003
- }
2004
- return /* @__PURE__ */ jsx15(TranslatableTooltipComponent, { title: hideTooltipOnDesktop ? /* @__PURE__ */ jsx15(Fragment9, {}) : tooltip || /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), children: /* @__PURE__ */ jsx15(
2005
- Button3,
2006
- {
2007
- variant: "contained",
2008
- color: "inherit",
2009
- size,
2010
- onClick: handleClick,
2011
- disabled: disabled || isLoading,
2012
- fullWidth,
2013
- startIcon: renderIcon(),
2014
- children: /* @__PURE__ */ jsx15(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" })
2015
- }
2016
- ) });
2017
- };
2018
-
2019
- // src/UI/widgets/misc/ErrorAlertWidget.tsx
2020
- import { Alert, Box as Box9, Button as Button4, Typography as Typography8, useTheme } from "@mui/material";
2021
- import ReplayIcon from "@mui/icons-material/Replay";
2022
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
2023
- var ErrorIllustration = ({ size = 64 }) => {
2024
- const theme = useTheme();
2025
- const mainColor = theme.palette.error.main;
2026
- const lightColor = theme.palette.error.light;
2027
- return /* @__PURE__ */ jsx16(
2028
- Box9,
2029
- {
2030
- sx: {
2031
- display: "flex",
2032
- alignItems: "center",
2033
- justifyContent: "center",
2034
- flexShrink: 0
2035
- },
2036
- children: /* @__PURE__ */ jsxs12(
2037
- "svg",
2038
- {
2039
- width: size,
2040
- height: size,
2041
- viewBox: "0 0 100 100",
2042
- fill: "none",
2043
- xmlns: "http://www.w3.org/2000/svg",
2044
- children: [
2045
- /* @__PURE__ */ jsxs12(
2046
- "circle",
2047
- {
2048
- cx: "50",
2049
- cy: "50",
2050
- r: "42",
2051
- fill: lightColor,
2052
- fillOpacity: "0.25",
2053
- children: [
2054
- /* @__PURE__ */ jsx16(
2055
- "animate",
2056
- {
2057
- attributeName: "r",
2058
- values: "38;44;38",
2059
- dur: "3s",
2060
- repeatCount: "indefinite"
2061
- }
2062
- ),
2063
- /* @__PURE__ */ jsx16(
2064
- "animate",
2065
- {
2066
- attributeName: "fill-opacity",
2067
- values: "0.2;0.4;0.2",
2068
- dur: "3s",
2069
- repeatCount: "indefinite"
2070
- }
2071
- )
2072
- ]
2073
- }
2074
- ),
2075
- /* @__PURE__ */ jsx16("circle", { cx: "50", cy: "50", r: "34", fill: lightColor, fillOpacity: "0.35" }),
2076
- /* @__PURE__ */ jsx16(
2077
- "path",
2078
- {
2079
- d: "M50 20L80 72H20L50 20Z",
2080
- fill: mainColor,
2081
- stroke: theme.palette.background.paper,
2082
- strokeWidth: "3",
2083
- strokeLinejoin: "round"
2084
- }
2085
- ),
2086
- /* @__PURE__ */ jsx16(
2087
- "path",
2088
- {
2089
- d: "M50 36V54",
2090
- stroke: "#FFFFFF",
2091
- strokeWidth: "4",
2092
- strokeLinecap: "round"
2093
- }
2094
- ),
2095
- /* @__PURE__ */ jsx16("circle", { cx: "50", cy: "62", r: "2.5", fill: "#FFFFFF" }),
2096
- /* @__PURE__ */ jsx16("circle", { cx: "16", cy: "30", r: "3", fill: mainColor, opacity: "0.4" }),
2097
- /* @__PURE__ */ jsx16("circle", { cx: "84", cy: "30", r: "2", fill: mainColor, opacity: "0.6" }),
2098
- /* @__PURE__ */ jsx16("circle", { cx: "88", cy: "68", r: "3", fill: mainColor, opacity: "0.3" })
2099
- ]
2100
- }
2101
- )
2102
- }
2103
- );
2104
- };
2105
- var ErrorAlertWidget = ({
2106
- overrideNamespace,
2107
- title = "An error occurred",
2108
- message,
2109
- onRetry,
2110
- retryText = "Retry",
2111
- isRetrying = false
2112
- }) => {
2113
- return /* @__PURE__ */ jsx16(
2114
- Alert,
2115
- {
2116
- severity: "error",
2117
- icon: false,
2118
- sx: {
2119
- borderRadius: 1,
2120
- p: 2.5,
2121
- m: 3,
2122
- border: "1px solid",
2123
- borderColor: "error.light",
2124
- bgcolor: (theme) => theme.palette.mode === "dark" ? "rgba(211, 47, 47, 0.08)" : "rgba(211, 47, 47, 0.04)",
2125
- boxShadow: "0 4px 20px rgba(0, 0, 0, 0.05)",
2126
- "& .MuiAlert-message": {
2127
- width: "100%",
2128
- p: 0
2129
- }
2130
- },
2131
- children: /* @__PURE__ */ jsxs12(
2132
- Box9,
2133
- {
2134
- sx: {
2135
- display: "flex",
2136
- flexDirection: { xs: "column", sm: "row" },
2137
- alignItems: { xs: "flex-start", sm: "center" },
2138
- gap: 2
2139
- },
2140
- children: [
2141
- /* @__PURE__ */ jsx16(ErrorIllustration, { size: 68 }),
2142
- /* @__PURE__ */ jsxs12(Box9, { sx: { flexGrow: 1 }, children: [
2143
- typeof title === "string" ? /* @__PURE__ */ jsx16(
2144
- Typography8,
2145
- {
2146
- variant: "subtitle1",
2147
- sx: { fontWeight: 600, color: "error.main", mb: 0.5 },
2148
- children: /* @__PURE__ */ jsx16(TranslateText, { overrideNamespace, children: title })
2149
- }
2150
- ) : title,
2151
- typeof message === "string" ? /* @__PURE__ */ jsx16(Typography8, { variant: "body2", color: "text.secondary", children: /* @__PURE__ */ jsx16(TranslateText, { overrideNamespace, children: message }) }) : message
2152
- ] }),
2153
- onRetry && /* @__PURE__ */ jsx16(
2154
- Box9,
2155
- {
2156
- sx: {
2157
- alignSelf: { xs: "flex-end", sm: "center" },
2158
- mt: { xs: 1, sm: 0 }
2159
- },
2160
- children: /* @__PURE__ */ jsx16(
2161
- Button4,
2162
- {
2163
- variant: "outlined",
2164
- color: "error",
2165
- size: "small",
2166
- disabled: isRetrying,
2167
- onClick: onRetry,
2168
- startIcon: /* @__PURE__ */ jsx16(
2169
- ReplayIcon,
2170
- {
2171
- sx: {
2172
- animation: isRetrying ? "spin 1s linear infinite" : "none",
2173
- "@keyframes spin": {
2174
- "0%": { transform: "rotate(0deg)" },
2175
- "100%": { transform: "rotate(360deg)" }
2176
- }
2177
- }
2178
- }
2179
- ),
2180
- sx: {
2181
- //borderRadius: 2,
2182
- textTransform: "none",
2183
- fontWeight: 600,
2184
- px: 2,
2185
- py: 0.75,
2186
- whiteSpace: "nowrap"
2187
- },
2188
- children: retryText
2189
- }
2190
- )
2191
- }
2192
- )
2193
- ]
2194
- }
2195
- )
2196
- }
2197
- );
2198
- };
2199
-
2200
- // src/UI/components/buttons/ButtonComponent.tsx
2201
- import { forwardRef } from "react";
2202
- import { Button as Button5 } from "@mui/material";
2203
- import { jsx as jsx17 } from "react/jsx-runtime";
2204
- var ButtonComponent = forwardRef(
2205
- ({ label, children, overrideNamespace, ...props }, ref) => {
2206
- const renderContent = (content) => {
2207
- if (typeof content === "string") {
2208
- return /* @__PURE__ */ jsx17(TranslateText, { overrideNamespace, children: content });
2209
- }
2210
- return content;
2211
- };
2212
- const contentToRender = label !== void 0 ? label : children;
2213
- return /* @__PURE__ */ jsx17(Button5, { ref, ...props, children: renderContent(contentToRender) });
2214
- }
2215
- );
2216
- ButtonComponent.displayName = "ButtonComponent";
2267
+ "aria-expanded": expanded
2268
+ }
2269
+ ) }) })
2270
+ ]
2271
+ }
2272
+ ),
2273
+ /* @__PURE__ */ jsxs12(Collapse, { in: expanded, timeout: "auto", children: [
2274
+ /* @__PURE__ */ jsx18(Divider3, { variant: "middle" }),
2275
+ /* @__PURE__ */ jsx18(CardContent2, { children: props.children })
2276
+ ] })
2277
+ ] });
2278
+ };
2217
2279
 
2218
- // src/UI/components/layout/PageComponent.tsx
2219
- import React12, { useState as useState13 } from "react";
2280
+ // src/i18n/LanguageSelector.tsx
2281
+ import { useEffect as useEffect5, useState as useState13 } from "react";
2282
+ import { useTranslation as useTranslation3 } from "react-i18next";
2220
2283
  import {
2221
2284
  Box as Box10,
2222
2285
  Typography as Typography9,
2223
- Button as Button6,
2286
+ CircularProgress,
2224
2287
  IconButton as IconButton8,
2225
2288
  Menu as Menu2,
2226
2289
  MenuItem as MenuItem3,
2227
- ListItemIcon as ListItemIcon2,
2228
- ListItemText as ListItemText3,
2229
- Divider as Divider3,
2230
- Tooltip as Tooltip8,
2231
- useTheme as useTheme2,
2232
- useMediaQuery,
2233
- Stack,
2234
- Fab as Fab2
2290
+ Tooltip as Tooltip8
2235
2291
  } from "@mui/material";
2236
- import MoreVertIcon from "@mui/icons-material/MoreVert";
2237
- import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
2238
- import { Refresh as RefreshIcon } from "@mui/icons-material";
2239
- import { Fragment as Fragment10, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
2240
- var getTruncateStyles = (mode = "truncate") => {
2241
- switch (mode) {
2242
- case "truncate":
2243
- return { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", display: "block" };
2244
- case "clamp-2":
2245
- return { display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "normal" };
2246
- case "wrap":
2247
- default:
2248
- return { whiteSpace: "normal", wordBreak: "break-word" };
2292
+ import { Fragment as Fragment10, jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
2293
+ var LanguageSelector = () => {
2294
+ const supabase = useSupabase();
2295
+ const { i18n } = useTranslation3();
2296
+ const [languages, setLanguages] = useState13([]);
2297
+ const [loading, setLoading] = useState13(true);
2298
+ const { changeLanguage } = useLocalization();
2299
+ const { settings: userSettings, setLanguage } = useUserSettings();
2300
+ const [anchorEl, setAnchorEl] = useState13(null);
2301
+ const open = Boolean(anchorEl);
2302
+ useEffect5(() => {
2303
+ const fetchLanguages = async () => {
2304
+ try {
2305
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
2306
+ if (error) throw error;
2307
+ setLanguages(data || []);
2308
+ if (userSettings.language) changeLanguage(userSettings.language);
2309
+ } catch (err) {
2310
+ 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);
2311
+ } finally {
2312
+ setLoading(false);
2313
+ }
2314
+ };
2315
+ fetchLanguages();
2316
+ }, []);
2317
+ const handleClick = (event) => {
2318
+ setAnchorEl(event.currentTarget);
2319
+ };
2320
+ const handleClose = () => {
2321
+ setAnchorEl(null);
2322
+ };
2323
+ const handleSelectLanguage = (langCode) => {
2324
+ changeLanguage(langCode);
2325
+ setLanguage(langCode);
2326
+ handleClose();
2327
+ };
2328
+ if (loading) {
2329
+ return /* @__PURE__ */ jsx19(CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
2249
2330
  }
2331
+ const rawCurrentLang = i18n.language || "uk";
2332
+ const currentLangCode = rawCurrentLang.split("-")[0];
2333
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
2334
+ return /* @__PURE__ */ jsxs13(Fragment10, { children: [
2335
+ /* @__PURE__ */ jsx19(Tooltip8, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ jsx19(
2336
+ IconButton8,
2337
+ {
2338
+ onClick: handleClick,
2339
+ size: "small",
2340
+ "aria-controls": open ? "language-menu" : void 0,
2341
+ "aria-haspopup": "true",
2342
+ "aria-expanded": open ? "true" : void 0,
2343
+ sx: {
2344
+ p: 1,
2345
+ borderRadius: 2,
2346
+ transition: "background-color 0.2s",
2347
+ "&:hover": {
2348
+ backgroundColor: "action.hover"
2349
+ }
2350
+ },
2351
+ children: currentLang?.svg_flag && /* @__PURE__ */ jsx19(
2352
+ Box10,
2353
+ {
2354
+ sx: {
2355
+ width: 24,
2356
+ height: 16,
2357
+ borderRadius: "3px",
2358
+ overflow: "hidden",
2359
+ flexShrink: 0,
2360
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
2361
+ display: "flex",
2362
+ alignItems: "center",
2363
+ justifyContent: "center",
2364
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
2365
+ },
2366
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
2367
+ }
2368
+ )
2369
+ }
2370
+ ) }),
2371
+ /* @__PURE__ */ jsx19(
2372
+ Menu2,
2373
+ {
2374
+ id: "language-menu",
2375
+ anchorEl,
2376
+ open,
2377
+ onClose: handleClose,
2378
+ slotProps: {
2379
+ paper: {
2380
+ elevation: 3,
2381
+ sx: {
2382
+ mt: 1,
2383
+ minWidth: 150,
2384
+ borderRadius: 2
2385
+ }
2386
+ }
2387
+ },
2388
+ transformOrigin: { horizontal: "right", vertical: "top" },
2389
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
2390
+ children: languages.map((lang) => {
2391
+ const isSelected = lang.code === currentLangCode;
2392
+ return /* @__PURE__ */ jsxs13(
2393
+ MenuItem3,
2394
+ {
2395
+ selected: isSelected,
2396
+ onClick: () => handleSelectLanguage(lang.code),
2397
+ sx: {
2398
+ display: "flex",
2399
+ alignItems: "center",
2400
+ gap: 1.5,
2401
+ py: 1,
2402
+ px: 2
2403
+ },
2404
+ children: [
2405
+ /* @__PURE__ */ jsx19(
2406
+ Box10,
2407
+ {
2408
+ sx: {
2409
+ width: 22,
2410
+ height: 15,
2411
+ borderRadius: "2px",
2412
+ overflow: "hidden",
2413
+ flexShrink: 0,
2414
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
2415
+ "& svg": { width: "100%", height: "100%", display: "block" }
2416
+ },
2417
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
2418
+ }
2419
+ ),
2420
+ /* @__PURE__ */ jsx19(Typography9, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
2421
+ ]
2422
+ },
2423
+ lang.code
2424
+ );
2425
+ })
2426
+ }
2427
+ )
2428
+ ] });
2250
2429
  };
2251
- var PageHeader = ({
2252
- overrideNamespace,
2253
- icon,
2254
- title,
2255
- subtitle,
2256
- tag,
2257
- titleTruncateMode = "truncate",
2258
- subtitleTruncateMode = "truncate",
2259
- customFragment,
2260
- primaryAction,
2261
- secondaryActions = [],
2262
- refreshAction,
2263
- mobileBreakpoint = "sm",
2264
- forceMobileView,
2265
- sx = []
2266
- }) => {
2267
- const theme = useTheme2();
2268
- const mediaIsMobile = useMediaQuery(theme.breakpoints.down(mobileBreakpoint));
2269
- const isMobile = forceMobileView ?? mediaIsMobile;
2430
+ var PublicLanguageSelector = () => {
2431
+ const supabase = useSupabase();
2432
+ const { i18n } = useTranslation3();
2433
+ const { changeLanguage } = useLocalization();
2434
+ const [languages, setLanguages] = useState13([]);
2435
+ const [loading, setLoading] = useState13(true);
2270
2436
  const [anchorEl, setAnchorEl] = useState13(null);
2271
- const isMenuOpen = Boolean(anchorEl);
2272
- const handleOpenMenu = (e) => setAnchorEl(e.currentTarget);
2273
- const handleCloseMenu = () => setAnchorEl(null);
2274
- const handleMenuAction = (cb) => {
2275
- handleCloseMenu();
2276
- cb();
2437
+ const open = Boolean(anchorEl);
2438
+ useEffect5(() => {
2439
+ const fetchLanguages = async () => {
2440
+ try {
2441
+ const { data, error } = await supabase.from("languages").select("code, name, svg_flag").eq("enabled", true);
2442
+ if (error) throw error;
2443
+ setLanguages(data || []);
2444
+ } catch (err) {
2445
+ 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);
2446
+ } finally {
2447
+ setLoading(false);
2448
+ }
2449
+ };
2450
+ fetchLanguages();
2451
+ }, []);
2452
+ const handleClick = (event) => {
2453
+ setAnchorEl(event.currentTarget);
2277
2454
  };
2278
- const hasSecondaryActions = secondaryActions.length > 0;
2279
- const hasActions = Boolean(primaryAction || hasSecondaryActions || refreshAction);
2280
- return /* @__PURE__ */ jsxs13(
2281
- Box10,
2282
- {
2283
- sx: [
2284
- {
2285
- display: "flex",
2286
- alignItems: "center",
2287
- justifyContent: "space-between",
2288
- width: "100%",
2289
- gap: { xs: 1.5, sm: 2.5 },
2290
- py: 1.5,
2291
- px: { xs: 1.5, sm: 2 },
2455
+ const handleClose = () => {
2456
+ setAnchorEl(null);
2457
+ };
2458
+ const handleSelectLanguage = (langCode) => {
2459
+ changeLanguage(langCode);
2460
+ handleClose();
2461
+ };
2462
+ if (loading) {
2463
+ return /* @__PURE__ */ jsx19(CircularProgress, { size: 20, color: "inherit", sx: { mx: 1 } });
2464
+ }
2465
+ const rawCurrentLang = i18n.language || "uk";
2466
+ const currentLangCode = rawCurrentLang.split("-")[0];
2467
+ const currentLang = languages.find((l) => l.code === currentLangCode) || languages[0];
2468
+ return /* @__PURE__ */ jsxs13(Fragment10, { children: [
2469
+ /* @__PURE__ */ jsx19(Tooltip8, { title: currentLang ? currentLang.name : "\u041C\u043E\u0432\u0430", arrow: true, placement: "bottom", children: /* @__PURE__ */ jsx19(
2470
+ IconButton8,
2471
+ {
2472
+ onClick: handleClick,
2473
+ size: "small",
2474
+ "aria-controls": open ? "language-menu" : void 0,
2475
+ "aria-haspopup": "true",
2476
+ "aria-expanded": open ? "true" : void 0,
2477
+ sx: {
2478
+ p: 1,
2292
2479
  borderRadius: 2,
2293
- backgroundColor: "background.paper",
2294
- boxShadow: "0 1px 3px rgba(0,0,0,0.05)"
2480
+ transition: "background-color 0.2s",
2481
+ "&:hover": {
2482
+ backgroundColor: "action.hover"
2483
+ }
2484
+ },
2485
+ children: currentLang?.svg_flag && /* @__PURE__ */ jsx19(
2486
+ Box10,
2487
+ {
2488
+ sx: {
2489
+ width: 24,
2490
+ height: 16,
2491
+ borderRadius: "3px",
2492
+ overflow: "hidden",
2493
+ flexShrink: 0,
2494
+ boxShadow: "0 0 2px rgba(0,0,0,0.3)",
2495
+ display: "flex",
2496
+ alignItems: "center",
2497
+ justifyContent: "center",
2498
+ "& svg": { width: "100%", height: "100%", display: "block", objectFit: "cover" }
2499
+ },
2500
+ dangerouslySetInnerHTML: { __html: currentLang.svg_flag }
2501
+ }
2502
+ )
2503
+ }
2504
+ ) }),
2505
+ /* @__PURE__ */ jsx19(
2506
+ Menu2,
2507
+ {
2508
+ id: "language-menu",
2509
+ anchorEl,
2510
+ open,
2511
+ onClose: handleClose,
2512
+ slotProps: {
2513
+ paper: {
2514
+ elevation: 3,
2515
+ sx: {
2516
+ mt: 1,
2517
+ minWidth: 150,
2518
+ borderRadius: 2
2519
+ }
2520
+ }
2295
2521
  },
2296
- ...Array.isArray(sx) ? sx : [sx]
2297
- ],
2298
- children: [
2299
- /* @__PURE__ */ jsxs13(Box10, { sx: { display: "flex", alignItems: "center", gap: { xs: 1.5, sm: 2 }, minWidth: 0, flex: 1 }, children: [
2300
- icon && /* @__PURE__ */ jsx18(
2301
- Box10,
2522
+ transformOrigin: { horizontal: "right", vertical: "top" },
2523
+ anchorOrigin: { horizontal: "right", vertical: "bottom" },
2524
+ children: languages.map((lang) => {
2525
+ const isSelected = lang.code === currentLangCode;
2526
+ return /* @__PURE__ */ jsxs13(
2527
+ MenuItem3,
2302
2528
  {
2529
+ selected: isSelected,
2530
+ onClick: () => handleSelectLanguage(lang.code),
2303
2531
  sx: {
2304
2532
  display: "flex",
2305
2533
  alignItems: "center",
2306
- justifyContent: "center",
2307
- width: { xs: 40, sm: 48 },
2308
- height: { xs: 40, sm: 48 },
2309
- borderRadius: 2.5,
2310
- backgroundColor: "primary.50",
2311
- color: "primary.main",
2312
- flexShrink: 0,
2313
- border: "1px solid",
2314
- borderColor: "primary.100",
2315
- "& svg": { fontSize: { xs: 22, sm: 26 } }
2534
+ gap: 1.5,
2535
+ py: 1,
2536
+ px: 2
2316
2537
  },
2317
- children: icon
2318
- }
2319
- ),
2320
- /* @__PURE__ */ jsxs13(Box10, { sx: { minWidth: 0, flex: 1 }, children: [
2321
- tag && /* @__PURE__ */ jsx18(Box10, { sx: { mb: 0.5, display: "flex", alignItems: "center" }, children: tag }),
2322
- /* @__PURE__ */ jsx18(Tooltip8, { title: titleTruncateMode === "truncate" ? /* @__PURE__ */ jsx18(TranslateText, { children: title }) : void 0, arrow: true, placement: "top", children: /* @__PURE__ */ jsx18(
2323
- Typography9,
2324
- {
2325
- variant: "h5",
2326
- component: "h1",
2327
- sx: {
2328
- fontWeight: 700,
2329
- color: "text.primary",
2330
- fontSize: { xs: "1.125rem", sm: "1.35rem" },
2331
- lineHeight: 1.3,
2332
- ...getTruncateStyles(titleTruncateMode)
2333
- },
2334
- children: /* @__PURE__ */ jsx18(TranslateText, { children: title })
2335
- }
2336
- ) }),
2337
- subtitle && /* @__PURE__ */ jsx18(Tooltip8, { title: subtitleTruncateMode === "truncate" ? /* @__PURE__ */ jsx18(TranslateText, { children: subtitle }) : void 0, arrow: true, placement: "top", children: /* @__PURE__ */ jsx18(
2338
- Typography9,
2339
- {
2340
- variant: "body2",
2341
- sx: {
2342
- color: "text.secondary",
2343
- mt: 0.25,
2344
- fontSize: { xs: "0.8125rem", sm: "0.875rem" },
2345
- lineHeight: 1.4,
2346
- ...getTruncateStyles(subtitleTruncateMode)
2347
- },
2348
- children: /* @__PURE__ */ jsx18(TranslateText, { children: subtitle })
2349
- }
2350
- ) })
2351
- ] })
2352
- ] }),
2353
- hasActions && /* @__PURE__ */ jsx18(Box10, { sx: { flexShrink: 0, display: "flex", alignItems: "center", gap: 1 }, children: isMobile ? (
2354
- /* MOBILE: IconButton with MoreVertIcon showing ALL actions inside Menu */
2355
- /* @__PURE__ */ jsxs13(Fragment10, { children: [
2356
- /* @__PURE__ */ jsx18(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Actions" }), children: /* @__PURE__ */ jsx18(
2357
- IconButton8,
2358
- {
2359
- onClick: handleOpenMenu,
2360
- sx: { border: "1px solid", borderColor: "divider", borderRadius: 2, p: 1 },
2361
- children: /* @__PURE__ */ jsx18(MoreVertIcon, {})
2362
- }
2363
- ) }),
2364
- /* @__PURE__ */ jsxs13(
2365
- Menu2,
2366
- {
2367
- anchorEl,
2368
- open: isMenuOpen,
2369
- onClose: handleCloseMenu,
2370
- transformOrigin: { horizontal: "right", vertical: "top" },
2371
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
2372
- slotProps: { paper: { elevation: 4, sx: { minWidth: 200, borderRadius: 2, mt: 1, p: 0.5 } } },
2373
- children: [
2374
- primaryAction && /* @__PURE__ */ jsxs13(Fragment10, { children: [
2375
- /* @__PURE__ */ jsxs13(
2376
- MenuItem3,
2377
- {
2378
- onClick: () => handleMenuAction(primaryAction.onClick),
2379
- disabled: primaryAction.disabled,
2380
- sx: {
2381
- borderRadius: 1.5,
2382
- fontWeight: 700,
2383
- backgroundColor: "primary.50",
2384
- color: primaryAction.color ? `${primaryAction.color}.main` : "primary.main",
2385
- py: 1.2,
2386
- px: 1.5
2387
- },
2388
- children: [
2389
- primaryAction.icon && /* @__PURE__ */ jsx18(ListItemIcon2, { sx: { color: "inherit", minWidth: 32 }, children: primaryAction.icon }),
2390
- /* @__PURE__ */ jsx18(ListItemText3, { primary: /* @__PURE__ */ jsx18(TranslateText, { children: primaryAction.label }), slotProps: { primary: { sx: { fontWeight: 700, fontSize: "0.9rem" } } } })
2391
- ]
2392
- }
2393
- ),
2394
- hasSecondaryActions && /* @__PURE__ */ jsx18(Divider3, { sx: { my: 0.75 } })
2395
- ] }),
2396
- secondaryActions.map((action) => /* @__PURE__ */ jsxs13(React12.Fragment, { children: [
2397
- action.divider && /* @__PURE__ */ jsx18(Divider3, { sx: { my: 0.5 } }),
2398
- /* @__PURE__ */ jsxs13(
2399
- MenuItem3,
2400
- {
2401
- onClick: () => handleMenuAction(action.onClick),
2402
- disabled: action.disabled,
2403
- sx: { borderRadius: 1, py: 1, px: 1.5, color: action.color ? `${action.color}.main` : "text.primary" },
2404
- children: [
2405
- action.icon && /* @__PURE__ */ jsx18(ListItemIcon2, { sx: { color: action.color ? `${action.color}.main` : "text.secondary", minWidth: 32 }, children: action.icon }),
2406
- /* @__PURE__ */ jsx18(ListItemText3, { primary: action.label, slotProps: { primary: { sx: { fontSize: "0.875rem" } } } })
2407
- ]
2408
- }
2409
- )
2410
- ] }, action.id)),
2411
- refreshAction && /* @__PURE__ */ jsxs13(Fragment10, { children: [
2412
- /* @__PURE__ */ jsx18(Divider3, { sx: { my: 0.5 } }),
2413
- /* @__PURE__ */ jsxs13(
2414
- MenuItem3,
2415
- {
2416
- onClick: () => handleMenuAction(refreshAction.onClick),
2417
- disabled: refreshAction.disabled,
2418
- sx: {
2419
- borderRadius: 1.5,
2420
- fontWeight: 700,
2421
- backgroundColor: "primary.50",
2422
- py: 1.2,
2423
- px: 1.5
2424
- },
2425
- children: [
2426
- /* @__PURE__ */ jsx18(ListItemIcon2, { sx: { color: "inherit", minWidth: 32 }, children: /* @__PURE__ */ jsx18(RefreshIcon, {}) }),
2427
- /* @__PURE__ */ jsx18(ListItemText3, { primary: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), slotProps: { primary: { sx: { fontWeight: 700, fontSize: "0.9rem" } } } })
2428
- ]
2429
- }
2430
- )
2431
- ] })
2432
- ]
2433
- }
2434
- )
2435
- ] })
2436
- ) : (
2437
- /* DESKTOP: Primary Action Button + Secondary Actions Dropdown Button */
2438
- /* @__PURE__ */ jsxs13(Box10, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
2439
- (primaryAction || refreshAction) && /* @__PURE__ */ jsxs13(Stack, { direction: "row", spacing: 2, children: [
2440
- primaryAction && /* @__PURE__ */ jsx18(
2441
- Button6,
2442
- {
2443
- variant: primaryAction.variant || "contained",
2444
- color: primaryAction.color || "primary",
2445
- onClick: primaryAction.onClick,
2446
- disabled: primaryAction.disabled,
2447
- startIcon: primaryAction.icon,
2448
- sx: { borderRadius: 2, textTransform: "none", fontWeight: 600, px: 2, py: 0.85 },
2449
- children: /* @__PURE__ */ jsx18(TranslateText, { children: primaryAction.label })
2450
- }
2451
- ),
2452
- refreshAction && /* @__PURE__ */ jsx18(TranslatableTooltipComponent, { title: /* @__PURE__ */ jsx18(TranslateText, { overrideNamespace: overrideNamespace || "form_components", children: "Refresh" }), children: /* @__PURE__ */ jsx18(
2453
- Fab2,
2454
- {
2455
- color: "default",
2456
- onClick: refreshAction.onClick,
2457
- disabled: refreshAction.disabled,
2458
- "aria-label": "refresh",
2459
- size: "small",
2460
- children: /* @__PURE__ */ jsx18(RefreshIcon, {})
2461
- }
2462
- ) })
2463
- ] }),
2464
- hasSecondaryActions && /* @__PURE__ */ jsxs13(Fragment10, { children: [
2465
- /* @__PURE__ */ jsx18(
2466
- IconButton8,
2467
- {
2468
- onClick: handleOpenMenu,
2469
- sx: { border: "1px solid", borderColor: "divider", borderRadius: 2, p: 1 },
2470
- children: /* @__PURE__ */ jsx18(KeyboardArrowDownIcon, {})
2471
- }
2472
- ),
2473
- /* @__PURE__ */ jsx18(
2474
- Menu2,
2475
- {
2476
- anchorEl,
2477
- open: isMenuOpen,
2478
- onClose: handleCloseMenu,
2479
- transformOrigin: { horizontal: "right", vertical: "top" },
2480
- anchorOrigin: { horizontal: "right", vertical: "bottom" },
2481
- slotProps: { paper: { elevation: 4, sx: { minWidth: 180, borderRadius: 2, mt: 1, p: 0.5 } } },
2482
- children: secondaryActions.map((action) => /* @__PURE__ */ jsxs13(React12.Fragment, { children: [
2483
- action.divider && /* @__PURE__ */ jsx18(Divider3, { sx: { my: 0.5 } }),
2484
- /* @__PURE__ */ jsxs13(
2485
- MenuItem3,
2486
- {
2487
- onClick: () => handleMenuAction(action.onClick),
2488
- disabled: action.disabled,
2489
- sx: { borderRadius: 1, py: 0.85, color: action.color ? `${action.color}.main` : "text.primary" },
2490
- children: [
2491
- action.icon && /* @__PURE__ */ jsx18(ListItemIcon2, { sx: { color: action.color ? `${action.color}.main` : "text.secondary", minWidth: 32 }, children: action.icon }),
2492
- /* @__PURE__ */ jsx18(ListItemText3, { primary: action.label, slotProps: { primary: { sx: { fontSize: "0.875rem" } } } })
2493
- ]
2494
- }
2495
- )
2496
- ] }, action.id))
2497
- }
2498
- )
2499
- ] })
2500
- ] })
2501
- ) }),
2502
- customFragment && /* @__PURE__ */ jsx18(Fragment10, { children: customFragment })
2503
- ]
2504
- }
2505
- );
2506
- };
2507
- var PageContainer = ({ children }) => {
2508
- return /* @__PURE__ */ jsx18(
2509
- Box10,
2510
- {
2511
- sx: {
2512
- width: "100%",
2513
- boxSizing: "border-box",
2514
- p: { xs: 1.5, sm: 3 },
2515
- backgroundColor: "background.paper"
2516
- },
2517
- children
2518
- }
2519
- );
2520
- };
2521
- var PageComponent = ({
2522
- header,
2523
- children
2524
- }) => {
2525
- return /* @__PURE__ */ jsx18(
2526
- Box10,
2527
- {
2528
- sx: {
2529
- //pt: 2,
2530
- flexGrow: 1,
2531
- minHeight: 0,
2532
- overflowY: "auto",
2533
- boxSizing: "border-box"
2534
- },
2535
- children: /* @__PURE__ */ jsxs13(PageContainer, { children: [
2536
- header && /* @__PURE__ */ jsx18(PageHeader, { ...header }),
2537
- children
2538
- ] })
2539
- }
2540
- );
2541
- };
2542
-
2543
- // src/UI/widgets/page/FilterContainerWidget.tsx
2544
- import React13 from "react";
2545
- import { Grid, Paper } from "@mui/material";
2546
- import { jsx as jsx19 } from "react/jsx-runtime";
2547
- var widthToGridColumns = (width) => {
2548
- switch (width) {
2549
- case "25%":
2550
- return 3;
2551
- case "33%":
2552
- return 4;
2553
- case "50%":
2554
- return 6;
2555
- case "66%":
2556
- return 8;
2557
- case "75%":
2558
- return 9;
2559
- case "100%":
2560
- default:
2561
- return 12;
2562
- }
2563
- };
2564
- var createGridSize = (desktopWidth, mobileWidth = "100%") => {
2565
- return {
2566
- xs: widthToGridColumns(mobileWidth),
2567
- md: widthToGridColumns(desktopWidth)
2568
- };
2569
- };
2570
- var FilterSection = ({
2571
- width = "100%",
2572
- mobileWidth = "100%",
2573
- itemWidth = "50%",
2574
- itemMobileWidth = "100%",
2575
- children
2576
- }) => {
2577
- const sectionGridSize = createGridSize(width, mobileWidth);
2578
- const itemGridSize = createGridSize(itemWidth, itemMobileWidth);
2579
- return /* @__PURE__ */ jsx19(Grid, { size: sectionGridSize, children: /* @__PURE__ */ jsx19(Grid, { container: true, spacing: 2, sx: { alignItems: "center" }, children: React13.Children.map(children, (child) => {
2580
- if (!child) return null;
2581
- return (
2582
- /* Автоматическая обертка каждого дочернего элемента в Grid size */
2583
- /* @__PURE__ */ jsx19(Grid, { size: itemGridSize, children: child })
2584
- );
2585
- }) }) });
2586
- };
2587
- var FilterContainerWidget = ({
2588
- sections,
2589
- children,
2590
- sx
2591
- }) => {
2592
- return /* @__PURE__ */ jsx19(
2593
- Paper,
2594
- {
2595
- variant: "outlined",
2596
- sx: [
2597
- { p: 2, mb: 3 },
2598
- ...Array.isArray(sx) ? sx : [sx]
2599
- ],
2600
- children: /* @__PURE__ */ jsx19(Grid, { container: true, spacing: 2, sx: { alignItems: "center" }, children: sections ? sections.map((sec, idx) => /* @__PURE__ */ jsx19(React13.Fragment, { children: sec }, idx)) : children })
2601
- }
2602
- );
2603
- };
2604
-
2605
- // src/UI/index.ts
2606
- var UI = {
2607
- Inputs: {
2608
- TextField: TextFieldComponent,
2609
- NumberField: NumberInputComponent,
2610
- EmailField: EmailInputComponent,
2611
- Search: SearchComponent,
2612
- Select: SelectComponent,
2613
- Checkbox: CheckboxComponent,
2614
- Switch: SwitchComponent,
2615
- Url: UrlComponent
2616
- },
2617
- Buttons: {
2618
- Button: ButtonComponent,
2619
- CopyClipboardButton: CopyClipboardButtonComponent,
2620
- RefreshButton: RefreshButtonComponent
2621
- },
2622
- DataDisplay: {
2623
- TranslatableTooltip: TranslatableTooltipComponent,
2624
- UserAvatar: UserAvatarComponent,
2625
- UserPopover: UserPopoverComponent_default,
2626
- UserRoleChip: UserRoleChipComponent,
2627
- UserStatusChip: UserStatusChipComponent,
2628
- MyAvatar: MyAvatarComponent,
2629
- ExpandableNote: ExpandableNoteComponent
2630
- },
2631
- Layout: {
2632
- Page: PageComponent
2633
- },
2634
- Widgets: {
2635
- Locales: {
2636
- ProtectedLanguageSelector: LanguageSelector,
2637
- PublicLanguageSelector
2638
- },
2639
- Pages: {
2640
- PageLinkWidget,
2641
- CollapsedWidgetContainer,
2642
- FilterContainerWidget,
2643
- FilterSection
2644
- },
2645
- Misc: {
2646
- ErrorAlertWidget
2647
- }
2648
- }
2538
+ children: [
2539
+ /* @__PURE__ */ jsx19(
2540
+ Box10,
2541
+ {
2542
+ sx: {
2543
+ width: 22,
2544
+ height: 15,
2545
+ borderRadius: "2px",
2546
+ overflow: "hidden",
2547
+ flexShrink: 0,
2548
+ boxShadow: "0 0 1px rgba(0,0,0,0.4)",
2549
+ "& svg": { width: "100%", height: "100%", display: "block" }
2550
+ },
2551
+ dangerouslySetInnerHTML: { __html: lang.svg_flag }
2552
+ }
2553
+ ),
2554
+ /* @__PURE__ */ jsx19(Typography9, { variant: "body2", sx: { fontWeight: isSelected ? 600 : 400 }, children: lang.name })
2555
+ ]
2556
+ },
2557
+ lang.code
2558
+ );
2559
+ })
2560
+ }
2561
+ )
2562
+ ] });
2649
2563
  };
2650
2564
 
2651
2565
  // src/services/index.ts
@@ -2787,19 +2701,43 @@ export {
2787
2701
  AppSettingsProvider,
2788
2702
  AuthProvider,
2789
2703
  BreadcrumbProvider,
2704
+ ButtonComponent,
2705
+ CheckboxComponent,
2706
+ CollapsedContainerComponent,
2790
2707
  ConfirmationProvider,
2708
+ CopyClipboardButtonComponent,
2709
+ EmailInputComponent,
2710
+ ErrorAlertComponent,
2711
+ ExpandableNoteComponent,
2712
+ FilterContainerComponent,
2791
2713
  Hooks,
2792
2714
  LocalizationProvider,
2715
+ MyAvatarComponent,
2716
+ NumberInputComponent,
2717
+ PageComponent,
2718
+ PageLinkComponent,
2719
+ LanguageSelector as ProtectedLanguageSelector,
2793
2720
  Providers,
2721
+ PublicLanguageSelector,
2722
+ RefreshButtonComponent,
2723
+ SearchComponent,
2724
+ SelectComponent,
2794
2725
  Services,
2795
2726
  SupabaseProvider,
2727
+ SwitchComponent,
2728
+ TextFieldComponent,
2796
2729
  ThemeProvider,
2797
2730
  ToastProvider,
2731
+ TranslatableTooltipComponent,
2798
2732
  TranslateProvider,
2799
2733
  TranslateText,
2800
2734
  TranslationEditProvider,
2801
- UI,
2735
+ UrlComponent,
2736
+ UserAvatarComponent,
2737
+ UserPopoverComponent,
2738
+ UserRoleChipComponent,
2802
2739
  UserSettingsProvider,
2740
+ UserStatusChipComponent,
2803
2741
  Utils,
2804
2742
  defaultUserSettings,
2805
2743
  initI18n,