@kodiak-finance/orderly-ui-scaffold 2.8.19-rc.0 → 2.8.20

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
@@ -1,18 +1,18 @@
1
1
  import React6, { forwardRef, createContext, useCallback, useRef, useEffect, useMemo, useState, cloneElement, useContext, isValidElement } from 'react';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { useTranslation, i18n, useLocaleContext, Trans } from '@kodiak-finance/orderly-i18n';
4
- import { installExtension, ExtensionPositionEnum, tv, Flex, Text, Tooltip, useScreen, Button, cn, modal, toast, DropdownMenuRoot, DropdownMenuTrigger, DropdownMenuPortal, DropdownMenuContent, DropdownMenuGroup, EVMAvatar, Divider, DropdownMenuItem, ChevronDownIcon, Box, PopoverRoot, PopoverAnchor, PopoverContent, SimpleDialog, Checkbox, useObserverElement, SimpleSheet, Logo, VectorIcon, PeopleIcon, SwapHorizIcon, Sheet, SheetContent, ChevronLeftIcon, Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, Spinner, ChainIcon, ScrollArea, formatAddress, Popover, Grid, CopyIcon, TextField, inputFormatter, ExtensionSlot, EyeIcon, EyeCloseIcon, SimpleDialogFooter, TooltipProvider, TooltipRoot, TooltipTrigger, BellIcon, TooltipContent, ChevronRightIcon, Icon, PopoverTrigger, PopupUnionIcon, CloseRoundFillIcon, SpotIcon, PerpsIcon, SelectedChoicesFillIcon } from '@kodiak-finance/orderly-ui';
5
- import { useWalletConnector, useAccount, useChains, useLocalStorage, useConfig, useTrack, useIndexPricesStream, WsNetworkStatus, useSubAccountQuery, useWsStatus, OrderlyContext, useMemoizedFn, useCollateral, usePositionStream, useMarginRatio, useLeverage, useMaintenanceStatus, useOrderlyContext, useEventEmitter, useWS, useQuery, MaintenanceStatus } from '@kodiak-finance/orderly-hooks';
4
+ import { installExtension, ExtensionPositionEnum, tv, Flex, Text, Tooltip, useScreen, Button, cn, modal, toast, DropdownMenuRoot, DropdownMenuTrigger, DropdownMenuPortal, DropdownMenuContent, DropdownMenuGroup, EVMAvatar, Divider, DropdownMenuItem, ChevronDownIcon, Box, PopoverRoot, PopoverAnchor, PopoverContent, SimpleDialog, Checkbox, useObserverElement, SimpleSheet, Logo, VectorIcon, PeopleIcon, SwapHorizIcon, Sheet, SheetContent, ChevronLeftIcon, Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, Spinner, ChainIcon, ScrollArea, formatAddress, Popover, Grid, CopyIcon, TextField, inputFormatter, ExtensionSlot, EyeIcon, EyeCloseIcon, SimpleDialogFooter, TooltipProvider, TooltipRoot, TooltipTrigger, BellIcon, TooltipContent, PopoverTrigger, PopupUnionIcon, CloseRoundFillIcon, SpotIcon, PerpsIcon, SelectedChoicesFillIcon } from '@kodiak-finance/orderly-ui';
5
+ import { useWalletConnector, useAccount, useChains, useLocalStorage, useConfig, useTrack, useIndexPricesStream, WsNetworkStatus, useSubAccountQuery, useWsStatus, OrderlyContext, useMemoizedFn, useCollateral, usePositionStream, useMarginRatio, useLeverage, useMaintenanceStatus, useEventEmitter } from '@kodiak-finance/orderly-hooks';
6
6
  import { useAppContext, useAppConfig } from '@kodiak-finance/orderly-react-app';
7
- import { AccountStatusEnum, ABSTRACT_CHAIN_ID_MAP, EMPTY_LIST, TrackerEventName, EMPTY_OBJECT, AnnouncementType } from '@kodiak-finance/orderly-types';
7
+ import { AccountStatusEnum, ABSTRACT_CHAIN_ID_MAP, EMPTY_LIST, TrackerEventName, EMPTY_OBJECT } from '@kodiak-finance/orderly-types';
8
8
  import { ChainSelectorSheetId, ChainSelectorDialogId, ChainSelectorWidget } from '@kodiak-finance/orderly-ui-chain-selector';
9
9
  import { WalletConnectorSheetId, WalletConnectorModalId } from '@kodiak-finance/orderly-ui-connector';
10
10
  import { Decimal, getTimestamp, windowGuard } from '@kodiak-finance/orderly-utils';
11
11
  import jsQR from 'jsqr';
12
12
  import { qrcode } from '@akamfoad/qr';
13
- import { UTCDateMini, UTCDate } from '@date-fns/utc';
14
- import { format, differenceInHours, differenceInMinutes } from 'date-fns';
15
- import { produce } from 'immer';
13
+ import { useAnnouncement, NotificationUI as NotificationUI$1, AnnouncementCenterUI } from '@kodiak-finance/orderly-ui-notification';
14
+ import { format } from 'date-fns';
15
+ import { UTCDateMini } from '@date-fns/utc';
16
16
 
17
17
  var __defProp = Object.defineProperty;
18
18
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -3637,790 +3637,20 @@ var ScaffoldContext = createContext(
3637
3637
  var useScaffoldContext = () => {
3638
3638
  return useContext(ScaffoldContext);
3639
3639
  };
3640
- var BattleIcon = (props) => {
3641
- return /* @__PURE__ */ jsxs(Icon, { size: 18, viewBox: "0 0 18 18", ...props, children: [
3642
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
3643
- "linearGradient",
3644
- {
3645
- id: "paint0_linear_555_7374",
3646
- x1: "17.0157",
3647
- y1: "9.26513",
3648
- x2: "0.969849",
3649
- y2: "9.26513",
3650
- gradientUnits: "userSpaceOnUse",
3651
- children: [
3652
- /* @__PURE__ */ jsx("stop", { stopColor: "rgb(var(--oui-gradient-brand-end))" }),
3653
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "rgb(var(--oui-gradient-brand-start))" })
3654
- ]
3655
- }
3656
- ) }),
3657
- /* @__PURE__ */ jsx(
3658
- "path",
3659
- {
3660
- fill: "url(#paint0_linear_555_7374)",
3661
- fillOpacity: 1,
3662
- d: "m1.5 1.5.75 3 4.843 4.56-1.808 1.919-.63-.633-1.06 1.06.665.665-1.88 1.996-.35-.346-1.06 1.06 2.25 2.25 1.06-1.06-.348-.349 1.998-1.878.665.662 1.06-1.06-.63-.63L9 10.852l1.969 1.854-.639.639 1.06 1.06.672-.67 1.998 1.877-.358.358 1.064 1.06 2.25-2.25-1.06-1.06-.34.34-1.881-1.998.656-.657-1.06-1.06-.625.624-1.799-1.91.003-.003L9 7.03 4.5 2.25zm15 0-3 .75-3.636 3.861 2.022 2.025L15.75 4.5z"
3663
- }
3664
- )
3665
- ] });
3666
- };
3667
- var CampaignIcon = (props) => {
3668
- return /* @__PURE__ */ jsx(Icon, { size: 18, viewBox: "0 0 18 18", ...props, children: /* @__PURE__ */ jsx(
3669
- "path",
3670
- {
3671
- fill: "currentcolor",
3672
- fillOpacity: 1,
3673
- d: "m1.5 1.5.75 3 4.843 4.56-1.808 1.919-.63-.633-1.06 1.06.665.665-1.88 1.996-.35-.346-1.06 1.06 2.25 2.25 1.06-1.06-.348-.349 1.998-1.878.665.662 1.06-1.06-.63-.63L9 10.852l1.969 1.854-.639.639 1.06 1.06.672-.67 1.998 1.877-.358.358 1.064 1.06 2.25-2.25-1.06-1.06-.34.34-1.881-1.998.656-.657-1.06-1.06-.625.624-1.799-1.91.003-.003L9 7.03 4.5 2.25zm15 0-3 .75-3.636 3.861 2.022 2.025L15.75 4.5z"
3674
- }
3675
- ) });
3676
- };
3677
- var ArrowRightShortIcon = (props) => {
3678
- return /* @__PURE__ */ jsxs(Icon, { size: 18, viewBox: "0 0 18 18", ...props, children: [
3679
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
3680
- "linearGradient",
3681
- {
3682
- id: "paint0_linear_555_7374",
3683
- x1: "17.0157",
3684
- y1: "9.26513",
3685
- x2: "0.969849",
3686
- y2: "9.26513",
3687
- gradientUnits: "userSpaceOnUse",
3688
- children: [
3689
- /* @__PURE__ */ jsx("stop", { stopColor: "rgb(var(--oui-gradient-brand-end))" }),
3690
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "rgb(var(--oui-gradient-brand-start))" })
3691
- ]
3692
- }
3693
- ) }),
3694
- /* @__PURE__ */ jsx(
3695
- "path",
3696
- {
3697
- fill: "url(#paint0_linear_555_7374)",
3698
- fillOpacity: 1,
3699
- d: "M4.509 8.995a.75.75 0 0 1 .75-.75h5.666L8.7 5.998l1.054-1.054 3.535 3.512c.147.146.22.343.22.54a.76.76 0 0 1-.22.537l-3.535 3.512L8.7 11.992l2.225-2.248H5.258a.75.75 0 0 1-.749-.75"
3700
- }
3701
- )
3702
- ] });
3703
- };
3704
- var FundIcon = (props) => {
3705
- return /* @__PURE__ */ jsx(Icon, { size: 18, viewBox: "0 0 18 18", ...props, children: /* @__PURE__ */ jsx(
3706
- "path",
3707
- {
3708
- fill: "currentcolor",
3709
- fillOpacity: 0.8,
3710
- d: "M15.694 7.087c-.788-.393-1.857-.618-2.925-.618-1.125 0-2.138.225-2.925.618-.056 0-.113.057-.113.057V3.769c0-.9-.731-1.575-1.462-1.913-.788-.394-1.857-.619-2.925-.619-1.069 0-2.25.225-3.038.62C1.575 2.193.844 2.868.844 3.768v10.519c0 .9.731 1.575 1.462 1.912.788.394 1.856.619 2.925.619s2.138-.225 2.925-.619c.281-.169.563-.337.788-.562.225.225.506.393.787.562.788.394 1.857.619 2.925.619 1.125 0 2.138-.225 2.925-.619.732-.394 1.463-1.012 1.463-1.912V9c.112-.9-.619-1.519-1.35-1.913m-7.369 7.144c0 .113-.112.45-.731.732-.563.28-1.407.506-2.363.506s-1.8-.169-2.362-.506c-.619-.282-.731-.62-.731-.732V13.5c.056 0 .112 0 .168.056.788.394 1.856.619 2.925.619s2.138-.225 2.925-.619c.056 0 .113-.056.113-.056v.731zm0-2.587c0 .112-.112.45-.731.731-.563.281-1.407.506-2.363.506s-1.8-.168-2.362-.506c-.619-.281-.731-.619-.731-.731v-.788c.056 0 .112.056.112.056.788.394 1.856.62 2.925.62s2.138-.226 2.925-.62c.056 0 .113-.056.113-.056v.788zm0-2.644c0 .112-.112.45-.731.731-.563.281-1.407.507-2.363.507s-1.8-.17-2.362-.507C2.25 9.45 2.138 9.112 2.138 9v-.788c.056 0 .112.057.112.057.788.393 1.856.618 2.925.618S7.313 8.662 8.1 8.27c.056 0 .113-.057.113-.057V9zm0-2.644c0 .113-.112.45-.731.731-.563.282-1.407.507-2.363.507s-1.8-.169-2.362-.507c-.619-.28-.731-.618-.731-.73v-.732c.056 0 .112 0 .168.056.788.394 1.856.619 2.925.619s2.138-.225 2.925-.619c.056 0 .113-.056.113-.056v.731zM7.594 4.5c-.563.281-1.407.506-2.363.506S3.488 4.781 2.925 4.5c-.619-.338-.731-.619-.731-.731 0-.113.112-.45.731-.732.563-.28 1.406-.506 2.363-.506.956 0 1.8.169 2.362.506.619.282.731.62.731.732-.056.112-.168.393-.787.731m8.212 9.731c0 .113-.112.45-.731.732-.562.28-1.406.506-2.362.506s-1.8-.169-2.363-.506c-.619-.282-.731-.62-.731-.732V13.5c.056 0 .112.056.112.056.788.394 1.857.619 2.925.619 1.125 0 2.138-.225 2.925-.619.056 0 .113-.056.113-.056v.731zm0-2.587c0 .112-.112.45-.731.731-.562.281-1.406.506-2.362.506s-1.8-.168-2.363-.506c-.619-.281-.731-.619-.731-.731v-.788c.056 0 .112.056.112.056.788.394 1.857.62 2.925.62 1.125 0 2.138-.226 2.925-.62.056 0 .113-.056.113-.056v.788zm-.675-1.913c-.562.281-1.406.507-2.362.507s-1.8-.17-2.363-.507c-.619-.281-.731-.619-.731-.731 0-.113.112-.45.731-.731.563-.282 1.406-.507 2.363-.507.956 0 1.8.17 2.362.507.619.281.732.618.732.731-.057.112-.17.45-.732.731"
3711
- }
3712
- ) });
3713
- };
3714
- var AnnouncementIcon = (props) => {
3715
- return /* @__PURE__ */ jsx(Icon, { size: 18, viewBox: "0 0 18 18", ...props, children: /* @__PURE__ */ jsx(
3716
- "path",
3717
- {
3718
- fill: "currentcolor",
3719
- fillOpacity: 0.8,
3720
- d: "M11.53 2.255a.745.745 0 0 0-.82.165c-.525.524-1.188.959-1.947 1.284-.77.33-2.353.757-3.508.75-2.248-.015-3.756 1.259-3.756 3.726 0 2.163 1.228 3.42 2.994 3.703l.006 1.565a2.25 2.25 0 0 0 2.25 2.247c1.142 0 2.083-.883 2.228-1.988.007-.053.022-.26.022-1.01.674.315 1.232.812 1.711 1.29.473.472 1.29.13 1.29-.538 0-.678-.004-1.906-.004-3.13.884-.327 1.503-1.165 1.503-2.115s-.585-1.81-1.496-2.129c0-1.225-.004-2.439-.004-3.117a.76.76 0 0 0-.469-.703m1.805 1.335a.73.73 0 0 0-.445.351.75.75 0 0 0 .258 1.03 3.74 3.74 0 0 1 1.851 3.233 3.74 3.74 0 0 1-1.851 3.231.76.76 0 0 0-.282 1.03.754.754 0 0 0 1.032.258 5.24 5.24 0 0 0 2.601-4.52 5.24 5.24 0 0 0-2.601-4.519.74.74 0 0 0-.563-.094m-2.832.884c0 .694-.004 1.417-.004 2.231v2.997c0 .815.003 1.508.003 2.202-1.52-.896-3.085-1.294-4.501-1.421 0-1.144-.004-3.406-.004-4.584.147-.007.318-.026.565-.06a11.2 11.2 0 0 0 2.812-.773c.43-.184.75-.35 1.129-.592m-6.005 1.55-.001 4.34c-.976-.27-1.498-.959-1.498-2.184 0-1.21.47-1.928 1.499-2.155M6 11.998c.238.008 1.098.161 1.493.261l.007 1.19a.75.75 0 0 1-1.5 0z"
3721
- }
3722
- ) });
3723
- };
3724
- var SecurityIcon = (props) => {
3725
- return /* @__PURE__ */ jsxs(Icon, { size: 18, viewBox: "0 0 18 18", ...props, children: [
3726
- /* @__PURE__ */ jsx(
3727
- "path",
3728
- {
3729
- d: "M6.563 7.678V6.603c0-1.153 1.09-2.088 2.437-2.088s2.438.935 2.438 2.088v1.075c.448 0 .812.311.812.696v3.479c0 .384-.364.696-.812.696H6.563c-.449 0-.813-.312-.813-.696v-3.48c0-.384.364-.695.813-.695m1.187-.006 1.431.006h1.07V6.564c0-.64-.504-1.104-1.25-1.104-.748 0-1.25.465-1.25 1.104zm1.956 2.14c0-.335-.317-.605-.706-.605-.39 0-.706.27-.706.604v.77c0 .335.316.605.706.605s.706-.27.706-.604z",
3730
- fill: "currentcolor",
3731
- fillOpacity: ".8"
3732
- }
3733
- ),
3734
- /* @__PURE__ */ jsx(
3735
- "path",
3736
- {
3737
- d: "M2 3.607c.003 5.606.146 11.651 6.879 13.378.078.02.164.02.242 0C15.854 15.258 15.997 9.213 16 3.607c0-.217-.14-.41-.345-.477L9.31 1.05a1 1 0 0 0-.62 0L2.345 3.13A.5.5 0 0 0 2 3.607m2.326 7.63c-.707-1.954-.81-4.33-.824-6.902L9 2.532l5.498 1.803c-.014 2.573-.117 4.948-.824 6.901-.697 1.93-1.987 3.463-4.674 4.222-2.687-.759-3.977-2.293-4.674-4.222",
3738
- fill: "currentcolor",
3739
- fillOpacity: ".8"
3740
- }
3741
- )
3742
- ] });
3743
- };
3744
- var AnnouncementItem = (props) => {
3745
- const { t } = useTranslation();
3746
- const Icon2 = useMemo(() => {
3747
- switch (props.type) {
3748
- case AnnouncementType.Campaign:
3749
- return CampaignIcon;
3750
- case AnnouncementType.Listing:
3751
- return FundIcon;
3752
- case AnnouncementType.Maintenance:
3753
- return SecurityIcon;
3754
- case AnnouncementType.Delisting:
3755
- default:
3756
- return AnnouncementIcon;
3757
- }
3758
- }, [props.type]);
3759
- const title = useMemo(() => {
3760
- switch (props.type) {
3761
- case AnnouncementType.Campaign:
3762
- return t("notification.campaign");
3763
- case AnnouncementType.Delisting:
3764
- return t("notification.delisting");
3765
- case AnnouncementType.Listing:
3766
- return t("notification.listing");
3767
- case AnnouncementType.Maintenance:
3768
- return t("notification.maintenance");
3769
- default:
3770
- return t("notification.general");
3771
- }
3772
- }, [props.type, t]);
3773
- const action = useMemo(() => {
3774
- if (props.type === AnnouncementType.Campaign && typeof props.url === "string" && props.url !== "" && typeof props.onItemClick === "function") {
3775
- return /* @__PURE__ */ jsxs(
3776
- Flex,
3777
- {
3778
- gap: 1,
3779
- itemAlign: "center",
3780
- className: "oui-cursor-pointer",
3781
- onClick: (event) => {
3782
- event.stopPropagation();
3783
- props.onItemClick(props.url);
3784
- },
3785
- children: [
3786
- /* @__PURE__ */ jsx(
3787
- Text,
3788
- {
3789
- size: "xs",
3790
- color: "buy",
3791
- className: "oui-bg-clip-text oui-text-transparent oui-gradient-brand",
3792
- children: t("notification.joinNow")
3793
- }
3794
- ),
3795
- /* @__PURE__ */ jsx(ArrowRightShortIcon, { size: 18 })
3796
- ]
3797
- }
3798
- );
3799
- }
3800
- return null;
3801
- }, [props.type, props.url, t]);
3802
- const updateTime = useMemo(() => {
3803
- if (props.type === AnnouncementType.Maintenance) {
3804
- return /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 36, children: t("notification.recentlyUpdated") });
3805
- }
3806
- return /* @__PURE__ */ jsx(
3807
- Text.formatted,
3808
- {
3809
- size: "2xs",
3810
- intensity: 36,
3811
- rule: "date",
3812
- formatString: "yyyy-MM-dd HH:mm:ss",
3813
- children: props.updatedTime
3814
- }
3815
- );
3816
- }, [props.updatedTime, props.type, t]);
3817
- return /* @__PURE__ */ jsxs(
3818
- Flex,
3819
- {
3820
- gap: 2,
3821
- itemAlign: "start",
3822
- className: cn(
3823
- "oui-px-2 oui-py-[6px] oui-text-base-contrast-80",
3824
- !props.showDivider && "oui-rounded-md hover:oui-bg-base-6",
3825
- !props.showDivider && props.expanded && "oui-bg-base-6",
3826
- props.className
3827
- ),
3828
- onClick: () => {
3829
- props.onExpandToggle?.();
3830
- },
3831
- children: [
3832
- /* @__PURE__ */ jsx(Icon2, { color: "white", className: "oui-mt-3 oui-shrink-0" }),
3833
- /* @__PURE__ */ jsxs(Flex, { direction: "column", itemAlign: "start", grow: true, children: [
3834
- /* @__PURE__ */ jsx(Text, { size: "xs", intensity: 80, weight: "bold", children: title }),
3835
- updateTime,
3836
- /* @__PURE__ */ jsx(
3837
- "div",
3838
- {
3839
- className: "oui-grid oui-transition-all oui-duration-300 oui-ease-in-out",
3840
- style: {
3841
- gridTemplateRows: props.expanded ? "1fr" : "0fr"
3842
- },
3843
- children: /* @__PURE__ */ jsxs("div", { className: "oui-flex oui-flex-col oui-gap-2 oui-overflow-hidden", children: [
3844
- /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 80, as: "div", className: "oui-pt-2", children: props.message }),
3845
- action
3846
- ] })
3847
- }
3848
- )
3849
- ] }),
3850
- /* @__PURE__ */ jsx("div", { className: "oui-pt-3", children: /* @__PURE__ */ jsx(
3851
- ChevronDownIcon,
3852
- {
3853
- color: "white",
3854
- size: 18,
3855
- className: `oui-transition-transform oui-duration-300 oui-ease-in-out ${props.expanded ? "oui-rotate-180" : "oui-rotate-0"}`
3856
- }
3857
- ) })
3858
- ]
3859
- }
3860
- );
3861
- };
3862
- var AnnouncementContent = (props) => {
3863
- const { dataSource, current, onExpandToggle, onItemClick } = props;
3864
- const { t } = useTranslation();
3865
- if (!Array.isArray(dataSource) || dataSource.length === 0) {
3866
- return /* @__PURE__ */ jsx("div", { className: "oui-flex oui-h-[160px] oui-items-center oui-justify-center", children: /* @__PURE__ */ jsx(
3867
- ExtensionSlot,
3868
- {
3869
- position: ExtensionPositionEnum.EmptyDataIdentifier,
3870
- title: t("notification.empty")
3871
- }
3872
- ) });
3640
+
3641
+ // src/utils/link.ts
3642
+ var isExternalUrl = (href) => {
3643
+ try {
3644
+ const origin = typeof window !== "undefined" && window.location?.origin ? window.location.origin : void 0;
3645
+ const target = new URL(href, origin ?? "http://localhost");
3646
+ if (!origin)
3647
+ return false;
3648
+ return target.origin !== origin;
3649
+ } catch {
3650
+ return false;
3873
3651
  }
3874
- return /* @__PURE__ */ jsx(
3875
- "div",
3876
- {
3877
- className: cn(
3878
- "oui-flex oui-flex-col oui-space-y-1",
3879
- props.showDivider && "[&>*:not(:first-child)]:oui-border-t [&>*:not(:first-child)]:oui-border-line-12 [&>*:not(:first-child)]:oui-pt-1"
3880
- ),
3881
- children: dataSource.map((item) => /* @__PURE__ */ jsx(
3882
- AnnouncementItem,
3883
- {
3884
- url: item.url,
3885
- onItemClick,
3886
- message: item.message,
3887
- updatedTime: item.updated_time ?? 0,
3888
- expanded: current === item.announcement_id,
3889
- type: item.type,
3890
- showDivider: props.showDivider,
3891
- onExpandToggle: () => {
3892
- if (current === item.announcement_id) {
3893
- onExpandToggle(null);
3894
- } else {
3895
- onExpandToggle(item.announcement_id);
3896
- }
3897
- }
3898
- },
3899
- item.announcement_id
3900
- ))
3901
- }
3902
- );
3903
- };
3904
- var AnnouncementCenterUI = (props) => {
3905
- const { t } = useTranslation();
3906
- const [expanded, setExpanded] = useState(null);
3907
- return /* @__PURE__ */ jsxs(Fragment, { children: [
3908
- /* @__PURE__ */ jsx("div", { className: "oui-px-5 oui-pt-4", children: /* @__PURE__ */ jsx(Text, { intensity: 80, weight: "bold", children: t("notification.title") }) }),
3909
- /* @__PURE__ */ jsx(ScrollArea, { className: "oui-flex oui-h-[300px] oui-flex-col oui-space-y-1 oui-p-3", children: /* @__PURE__ */ jsx(
3910
- AnnouncementContent,
3911
- {
3912
- dataSource: props.dataSource,
3913
- current: expanded,
3914
- onExpandToggle: setExpanded,
3915
- onItemClick: props.onItemClick
3916
- }
3917
- ) })
3918
- ] });
3919
- };
3920
- var CampaignContentCard = ({ message, coverImage, url, onItemClick }) => {
3921
- const { t } = useTranslation();
3922
- return /* @__PURE__ */ jsxs("div", { className: "oui-flex oui-flex-col oui-gap-5", children: [
3923
- /* @__PURE__ */ jsx(Text, { size: "sm", weight: "bold", children: message }),
3924
- /* @__PURE__ */ jsx(
3925
- "div",
3926
- {
3927
- className: "oui-rounded-xl oui-bg-base-9 oui-bg-cover oui-bg-center oui-bg-no-repeat",
3928
- style: {
3929
- backgroundImage: `url(${coverImage})`,
3930
- height: "100px"
3931
- }
3932
- }
3933
- ),
3934
- typeof url === "string" && url !== "" && typeof onItemClick === "function" && /* @__PURE__ */ jsxs(
3935
- "button",
3936
- {
3937
- className: "oui-flex oui-items-center oui-gap-1",
3938
- onClick: () => onItemClick(url),
3939
- children: [
3940
- /* @__PURE__ */ jsx(
3941
- Text,
3942
- {
3943
- size: "xs",
3944
- color: "buy",
3945
- className: "oui-bg-clip-text oui-text-transparent oui-gradient-brand",
3946
- children: t("notification.joinNow")
3947
- }
3948
- ),
3949
- /* @__PURE__ */ jsx(ArrowRightShortIcon, { size: 18, color: "success" })
3950
- ]
3951
- }
3952
- )
3953
- ] });
3954
- };
3955
- var MaintenanceContentCard = ({ message, startTime, endTime }) => {
3956
- const { t } = useTranslation();
3957
- const formattedMessage = useMemo(() => {
3958
- const hours = differenceInHours(endTime, startTime);
3959
- const minutes = differenceInMinutes(endTime, startTime) - hours * 60;
3960
- const startUtc = new UTCDate(startTime);
3961
- const endUtc = new UTCDate(endTime);
3962
- const startTimeFormatted = format(startUtc, "HH:mm");
3963
- const endTimeFormatted = format(endUtc, "hh:mm a");
3964
- if (hours > 0) {
3965
- return t("notification.maintenanceDuration.hours", {
3966
- hours: minutes > 0 ? (hours + minutes / 60).toFixed(1) : hours,
3967
- startTimeFormatted,
3968
- endTimeFormatted
3969
- });
3970
- }
3971
- return t("notification.maintenanceDuration.minutes", {
3972
- minutes,
3973
- startTimeFormatted,
3974
- endTimeFormatted
3975
- });
3976
- }, [startTime, endTime, t]);
3977
- return /* @__PURE__ */ jsxs("div", { className: "oui-flex oui-flex-col oui-gap-1", children: [
3978
- /* @__PURE__ */ jsx(Text, { size: "xs", intensity: 54, children: t("notification.recentlyUpdated") }),
3979
- /* @__PURE__ */ jsx(Flex, { itemAlign: "center", children: /* @__PURE__ */ jsx(Text, { size: "xs", weight: "bold", children: formattedMessage }) }),
3980
- message && /* @__PURE__ */ jsx(Text, { size: "2xs", intensity: 80, as: "div", className: "oui-mt-2", children: message })
3981
- ] });
3982
- };
3983
- var DelistingContentCard = ({ message, updateTime }) => {
3984
- return /* @__PURE__ */ jsxs("div", { className: "oui-flex oui-flex-col oui-gap-1", children: [
3985
- /* @__PURE__ */ jsx(
3986
- Text.formatted,
3987
- {
3988
- rule: "date",
3989
- intensity: 54,
3990
- formatString: "yyyy-MM-dd HH:mm:ss",
3991
- size: "xs",
3992
- children: updateTime
3993
- }
3994
- ),
3995
- /* @__PURE__ */ jsx(Text, { size: "sm", weight: "bold", children: message })
3996
- ] });
3997
- };
3998
- var ListingContentCard = ({ message, updateTime }) => {
3999
- return /* @__PURE__ */ jsxs("div", { className: "oui-flex oui-flex-col oui-gap-1", children: [
4000
- /* @__PURE__ */ jsx(
4001
- Text.formatted,
4002
- {
4003
- rule: "date",
4004
- intensity: 54,
4005
- formatString: "yyyy-MM-dd HH:mm:ss",
4006
- size: "xs",
4007
- children: updateTime
4008
- }
4009
- ),
4010
- /* @__PURE__ */ jsx(Text, { size: "sm", weight: "bold", children: message })
4011
- ] });
4012
- };
4013
- var NotificationHeader = (props) => {
4014
- const { t } = useTranslation();
4015
- const { expanded } = props;
4016
- const { type } = props.dataSource[props.current];
4017
- const title = useMemo(() => {
4018
- switch (type) {
4019
- case AnnouncementType.Campaign:
4020
- return /* @__PURE__ */ jsx(
4021
- Text,
4022
- {
4023
- size: "sm",
4024
- className: "oui-text-transparent oui-bg-clip-text oui-gradient-brand",
4025
- children: t("notification.campaign")
4026
- }
4027
- );
4028
- case AnnouncementType.Delisting:
4029
- return /* @__PURE__ */ jsx(Text, { size: "sm", children: t("notification.delistingTitle") });
4030
- case AnnouncementType.Listing:
4031
- return /* @__PURE__ */ jsx(Text, { size: "sm", color: "buy", children: t("notification.listing") });
4032
- case AnnouncementType.Maintenance:
4033
- return /* @__PURE__ */ jsx(Text, { size: "sm", color: "warning", children: t("notification.maintenanceTitle") });
4034
- default:
4035
- return /* @__PURE__ */ jsx(Text, { size: "sm", color: "inherit", children: t("notification.generalTitle") });
4036
- }
4037
- }, [type, t]);
4038
- const icon = useMemo(() => {
4039
- switch (type) {
4040
- case AnnouncementType.Campaign:
4041
- return /* @__PURE__ */ jsx(BattleIcon, { color: "white" });
4042
- case AnnouncementType.Listing:
4043
- return /* @__PURE__ */ jsx(FundIcon, { color: "success" });
4044
- case AnnouncementType.Maintenance:
4045
- return /* @__PURE__ */ jsx(SecurityIcon, { color: "warning" });
4046
- case AnnouncementType.Delisting:
4047
- default:
4048
- return /* @__PURE__ */ jsx(AnnouncementIcon, { color: "white" });
4049
- }
4050
- }, [type]);
4051
- return /* @__PURE__ */ jsxs(Flex, { itemAlign: "center", justify: "between", className: "oui-px-4 oui-py-3", children: [
4052
- /* @__PURE__ */ jsxs("div", { className: "orderly-notification-header oui-flex oui-items-center oui-gap-2", children: [
4053
- icon,
4054
- title
4055
- ] }),
4056
- /* @__PURE__ */ jsx(
4057
- "button",
4058
- {
4059
- onClick: props.onExpandToggle,
4060
- className: "oui-transition-transform oui-duration-300",
4061
- style: {
4062
- transform: !expanded ? "rotate(180deg)" : "rotate(0deg)"
4063
- },
4064
- children: /* @__PURE__ */ jsx(ChevronDownIcon, { size: 18, color: "white" })
4065
- }
4066
- )
4067
- ] });
4068
- };
4069
- var NotificationFooter = (props) => {
4070
- const { total, current, onCloseAll, onPrev, onNext } = props;
4071
- const { t } = useTranslation();
4072
- return /* @__PURE__ */ jsxs(
4073
- Flex,
4074
- {
4075
- className: "orderly-notification-footer oui-px-4 oui-py-2",
4076
- itemAlign: "center",
4077
- justify: "between",
4078
- children: [
4079
- /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
4080
- /* @__PURE__ */ jsx(
4081
- "button",
4082
- {
4083
- disabled: current - 1 < 0,
4084
- onClick: onPrev,
4085
- className: "oui-flex oui-size-[18px] oui-items-center oui-justify-center oui-rounded-full oui-bg-base-6 hover:oui-bg-base-5 disabled:oui-opacity-50",
4086
- children: /* @__PURE__ */ jsx(ChevronLeftIcon, { size: 14, color: "white" })
4087
- }
4088
- ),
4089
- /* @__PURE__ */ jsxs(Text, { intensity: 54, size: "sm", children: [
4090
- current + 1,
4091
- "/",
4092
- total
4093
- ] }),
4094
- /* @__PURE__ */ jsx(
4095
- "button",
4096
- {
4097
- disabled: current + 1 >= total,
4098
- onClick: onNext,
4099
- className: "oui-flex oui-size-[18px] oui-items-center oui-justify-center oui-rounded-full oui-bg-base-6 hover:oui-bg-base-5 disabled:oui-opacity-50",
4100
- children: /* @__PURE__ */ jsx(ChevronRightIcon, { size: 14, color: "white" })
4101
- }
4102
- )
4103
- ] }),
4104
- /* @__PURE__ */ jsx("button", { onClick: onCloseAll, children: /* @__PURE__ */ jsx(Text, { size: "xs", color: "primary", children: t("notification.closeAll", { total }) }) })
4105
- ]
4106
- }
4107
- );
4108
- };
4109
- var NotificationContent = (props) => {
4110
- const elements = useMemo(() => {
4111
- return props.dataSource.map((message) => {
4112
- const { type } = message;
4113
- switch (type) {
4114
- case AnnouncementType.Campaign:
4115
- return /* @__PURE__ */ jsx(
4116
- CampaignContentCard,
4117
- {
4118
- message: message.message,
4119
- coverImage: message.coverImage ?? "",
4120
- updateTime: message.updated_time ?? 0,
4121
- url: message.url ?? "",
4122
- onItemClick: props.onItemClick
4123
- }
4124
- );
4125
- case AnnouncementType.Maintenance:
4126
- return /* @__PURE__ */ jsx(
4127
- MaintenanceContentCard,
4128
- {
4129
- message: message.message,
4130
- startTime: message.startTime ?? 0,
4131
- endTime: message.endTime ?? 0
4132
- }
4133
- );
4134
- case AnnouncementType.Delisting:
4135
- return /* @__PURE__ */ jsx(
4136
- DelistingContentCard,
4137
- {
4138
- message: message.message,
4139
- updateTime: message.updated_time ?? 0
4140
- }
4141
- );
4142
- default:
4143
- return /* @__PURE__ */ jsx(
4144
- ListingContentCard,
4145
- {
4146
- message: message.message,
4147
- updateTime: message.updated_time ?? 0
4148
- }
4149
- );
4150
- }
4151
- });
4152
- }, [props.dataSource]);
4153
- return /* @__PURE__ */ jsx(Fragment, { children: elements[props.current] });
4154
3652
  };
4155
3653
  var NotificationUI = (props) => {
4156
- const [expanded, setExpanded] = useState(true);
4157
- const [current, setCurrent] = useState(0);
4158
- const len = useMemo(() => props.dataSource?.length ?? 0, [props.dataSource]);
4159
- if (len === 0) {
4160
- return null;
4161
- }
4162
- return /* @__PURE__ */ jsxs("div", { className: "orderly-notification oui-w-full ", children: [
4163
- /* @__PURE__ */ jsx(
4164
- NotificationHeader,
4165
- {
4166
- dataSource: props.dataSource ?? [],
4167
- current,
4168
- expanded,
4169
- onExpandToggle: () => {
4170
- setExpanded(!expanded);
4171
- }
4172
- }
4173
- ),
4174
- /* @__PURE__ */ jsx(Divider, { className: "oui-mx-4" }),
4175
- /* @__PURE__ */ jsx(
4176
- "div",
4177
- {
4178
- className: "oui-grid oui-transition-all oui-duration-300 oui-ease-in-out",
4179
- style: {
4180
- gridTemplateRows: expanded ? "1fr" : "0fr"
4181
- },
4182
- children: /* @__PURE__ */ jsx("div", { className: "oui-min-h-0 oui-overflow-hidden ", children: /* @__PURE__ */ jsx("div", { className: "oui-px-4 oui-py-3", children: /* @__PURE__ */ jsx(
4183
- NotificationContent,
4184
- {
4185
- dataSource: props.dataSource ?? [],
4186
- current,
4187
- onItemClick: props.onItemClick
4188
- }
4189
- ) }) })
4190
- }
4191
- ),
4192
- /* @__PURE__ */ jsx(
4193
- NotificationFooter,
4194
- {
4195
- total: len,
4196
- current,
4197
- onCloseAll: props.onClose ?? (() => {
4198
- }),
4199
- onPrev: () => {
4200
- if (current - 1 < 0) {
4201
- return;
4202
- }
4203
- setCurrent(current - 1);
4204
- },
4205
- onNext: () => {
4206
- if (current + 1 >= len) {
4207
- return;
4208
- }
4209
- setCurrent(current + 1);
4210
- }
4211
- }
4212
- )
4213
- ] });
4214
- };
4215
- var maintentanceId = "-1";
4216
- var ORDERLY_ANNOUNCEMENT_KEY = "orderly_announcement";
4217
- var getTimeString = (timestamp) => {
4218
- const date = format(new UTCDateMini(timestamp), "MMM dd");
4219
- const time = format(new UTCDateMini(timestamp), "h:mm aa");
4220
- return `${time} (UTC) on ${date}`;
4221
- };
4222
- var sortDataByUpdatedTime = (ori) => {
4223
- return produce(ori, (draft) => {
4224
- if (Array.isArray(draft.rows)) {
4225
- draft.rows.sort((a, b) => {
4226
- if (a.updated_time && b.updated_time) {
4227
- return b.updated_time - a.updated_time;
4228
- }
4229
- return 0;
4230
- });
4231
- }
4232
- });
4233
- };
4234
- var useAnnouncementData = () => {
4235
- const ws = useWS();
4236
- const [announcementStore, setStore] = useLocalStorage(
4237
- ORDERLY_ANNOUNCEMENT_KEY,
4238
- {}
4239
- );
4240
- const [tips, setTips] = useState({});
4241
- const [maintenanceDialogInfo, setMaintenanceDialogInfo] = useState();
4242
- const { startTime, endTime, status, brokerName } = useMaintenanceStatus();
4243
- const { t } = useTranslation();
4244
- const { data: announcements } = useQuery(
4245
- `/v2/public/announcement`,
4246
- {
4247
- revalidateOnFocus: false,
4248
- refreshInterval: 60 * 60 * 1e3,
4249
- // refresh every 1 hour
4250
- formatter: (data) => data
4251
- }
4252
- );
4253
- const getMaintentTipsContent = (brokerName2, startDate, endDate) => t("maintenance.tips.description", { brokerName: brokerName2, startDate, endDate });
4254
- const getMaintentDialogContent = (brokerName2, endDate) => t("maintenance.dialog.description", { brokerName: brokerName2, endDate });
4255
- useEffect(() => {
4256
- const unsubscribe = ws.subscribe("announcement", {
4257
- onMessage(message) {
4258
- if (message) {
4259
- setTips((prev) => {
4260
- return produce(prev, (draft) => {
4261
- if (!Array.isArray(draft.rows)) {
4262
- draft.rows = [];
4263
- }
4264
- const idx = draft.rows.findIndex(
4265
- (tip) => tip.announcement_id === message.announcement_id
4266
- );
4267
- if (idx !== -1) {
4268
- draft.rows.splice(idx, 1);
4269
- }
4270
- draft.rows.push({
4271
- announcement_id: message.announcement_id,
4272
- message: message.message,
4273
- url: message.url,
4274
- i18n: message.i18n,
4275
- type: message.type,
4276
- updated_time: message.updated_time
4277
- });
4278
- });
4279
- });
4280
- setStore((prev) => ({ ...prev, show: true }));
4281
- }
4282
- },
4283
- onError(err) {
4284
- }
4285
- });
4286
- return () => {
4287
- unsubscribe?.();
4288
- };
4289
- }, [ws]);
4290
- useEffect(() => {
4291
- if (!announcements?.rows) {
4292
- return;
4293
- }
4294
- const apiTime = announcements.last_updated_time ?? 0;
4295
- const cachedTime = announcementStore.lastUpdateTime ?? 0;
4296
- if (cachedTime < apiTime) {
4297
- setTips((prev) => ({ ...prev, rows: announcements?.rows }));
4298
- setStore({ show: true, lastUpdateTime: apiTime });
4299
- } else {
4300
- setTips((prev) => {
4301
- return produce(prev, (draft) => {
4302
- if (announcements?.rows?.length) {
4303
- const existingIds = new Set(
4304
- prev.rows?.map((tip) => tip.announcement_id)
4305
- );
4306
- const maintenanceTip = prev.rows?.find(
4307
- (tip) => tip.announcement_id === maintentanceId
4308
- );
4309
- draft.rows = [];
4310
- announcements.rows.forEach((item) => {
4311
- if (!existingIds.has(item.announcement_id)) {
4312
- draft.rows?.push(item);
4313
- }
4314
- });
4315
- if (maintenanceTip) {
4316
- draft.rows.unshift(maintenanceTip);
4317
- }
4318
- } else {
4319
- const idx = draft.rows?.findIndex(
4320
- (tip) => tip.announcement_id === maintentanceId
4321
- );
4322
- if (idx !== void 0 && idx !== -1) {
4323
- draft.rows?.splice(idx, 1);
4324
- }
4325
- }
4326
- });
4327
- });
4328
- }
4329
- }, [announcements]);
4330
- useEffect(() => {
4331
- const startDate = startTime ? getTimeString(startTime) : "-";
4332
- const endDate = endTime ? getTimeString(endTime) : "-";
4333
- if (status === MaintenanceStatus.Maintenance) {
4334
- setMaintenanceDialogInfo(getMaintentDialogContent(brokerName, endDate));
4335
- return;
4336
- }
4337
- setMaintenanceDialogInfo(void 0);
4338
- if (startTime && endTime) {
4339
- setTips(
4340
- (prev) => produce(prev, (draft) => {
4341
- if (!Array.isArray(draft.rows)) {
4342
- draft.rows = [];
4343
- }
4344
- draft.rows = [
4345
- {
4346
- announcement_id: maintentanceId,
4347
- type: AnnouncementType.Maintenance,
4348
- /** @ts-ignore */
4349
- startTime,
4350
- /** @ts-ignore */
4351
- endTime,
4352
- message: getMaintentTipsContent(brokerName, startDate, endDate)
4353
- },
4354
- ...draft.rows.filter(
4355
- (tip) => tip.type !== AnnouncementType.Maintenance
4356
- )
4357
- ];
4358
- })
4359
- );
4360
- } else {
4361
- setTips((prev) => {
4362
- return produce(prev, (draft) => {
4363
- const index = draft.rows?.findIndex(
4364
- (tip) => tip.announcement_id === maintentanceId
4365
- );
4366
- if (index !== void 0 && index !== -1) {
4367
- draft.rows?.splice(index, 1);
4368
- }
4369
- });
4370
- });
4371
- }
4372
- }, [startTime, endTime, status, brokerName, t]);
4373
- const { customAnnouncements } = useAppContext();
4374
- const mergedTips = useMemo(() => {
4375
- const tipsCopy = { ...tips };
4376
- if (customAnnouncements && customAnnouncements.length > 0) {
4377
- tipsCopy.rows = [...customAnnouncements, ...tips.rows || []];
4378
- }
4379
- return sortDataByUpdatedTime(tipsCopy);
4380
- }, [tips, customAnnouncements]);
4381
- return {
4382
- tips: mergedTips,
4383
- maintenanceDialogInfo
4384
- };
4385
- };
4386
- var useAnnouncement = (options) => {
4387
- const { showAnnouncement, setShowAnnouncement } = useAppContext();
4388
- const { dataAdapter } = useOrderlyContext();
4389
- const { tips: mergedTips, maintenanceDialogInfo } = useAnnouncementData();
4390
- const memoizedTips = useMemo(() => {
4391
- if (typeof dataAdapter?.announcementList === "function") {
4392
- return dataAdapter.announcementList(
4393
- mergedTips?.rows ?? EMPTY_LIST
4394
- );
4395
- }
4396
- return mergedTips?.rows ?? EMPTY_LIST;
4397
- }, [dataAdapter?.announcementList, mergedTips?.rows]);
4398
- const [announcementStore, setStore] = useLocalStorage(
4399
- ORDERLY_ANNOUNCEMENT_KEY,
4400
- {}
4401
- );
4402
- const closeTips = () => {
4403
- setStore((prev) => ({ ...prev, show: false }));
4404
- };
4405
- useEffect(() => {
4406
- const len = memoizedTips.length;
4407
- setShowAnnouncement(
4408
- Boolean(len) && announcementStore.show && true
4409
- );
4410
- }, [
4411
- memoizedTips,
4412
- announcementStore.show,
4413
- options?.hideTips,
4414
- setShowAnnouncement
4415
- ]);
4416
- return {
4417
- maintenanceDialogInfo,
4418
- tips: memoizedTips,
4419
- closeTips,
4420
- showAnnouncement
4421
- };
4422
- };
4423
- var NotificationUI2 = (props) => {
4424
3654
  const { dataSource, showAnnouncement } = props;
4425
3655
  const { routerAdapter } = useScaffoldContext();
4426
3656
  const onItemClick = (url) => {
@@ -4429,7 +3659,7 @@ var NotificationUI2 = (props) => {
4429
3659
  routerAdapter?.onRouteChange({
4430
3660
  href: url,
4431
3661
  name: url,
4432
- target: "_blank"
3662
+ target: isExternalUrl(url) ? "_blank" : void 0
4433
3663
  });
4434
3664
  };
4435
3665
  const notificationRef = useRef(null);
@@ -4485,7 +3715,7 @@ var NotificationUI2 = (props) => {
4485
3715
  showAnnouncement ? "oui-visible" : "oui-invisible"
4486
3716
  ),
4487
3717
  children: /* @__PURE__ */ jsx(
4488
- NotificationUI,
3718
+ NotificationUI$1,
4489
3719
  {
4490
3720
  dataSource,
4491
3721
  onClose,
@@ -4498,7 +3728,7 @@ var NotificationUI2 = (props) => {
4498
3728
  var NotificationWidget = () => {
4499
3729
  const { announcementState } = useScaffoldContext();
4500
3730
  return /* @__PURE__ */ jsx(
4501
- NotificationUI2,
3731
+ NotificationUI,
4502
3732
  {
4503
3733
  dataSource: announcementState.tips,
4504
3734
  onClose: announcementState.closeTips,
@@ -5916,7 +5146,7 @@ var MessageCenter = (props) => {
5916
5146
  routerAdapter?.onRouteChange({
5917
5147
  href: url,
5918
5148
  name: url,
5919
- target: "_blank"
5149
+ target: isExternalUrl(url) ? "_blank" : void 0
5920
5150
  });
5921
5151
  };
5922
5152
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -6544,7 +5774,7 @@ var MaintenanceTipsUI = (props) => {
6544
5774
  }
6545
5775
  );
6546
5776
  };
6547
- function getTimeString2(timestamp) {
5777
+ function getTimeString(timestamp) {
6548
5778
  const date = format(new UTCDateMini(timestamp), "MMM dd");
6549
5779
  const time = format(new UTCDateMini(timestamp), "h:mm aa");
6550
5780
  return `${time} (UTC) on ${date}`;
@@ -6559,13 +5789,13 @@ var useMaintenanceScript = () => {
6559
5789
  if (!startTime) {
6560
5790
  return "-";
6561
5791
  }
6562
- return getTimeString2(startTime);
5792
+ return getTimeString(startTime);
6563
5793
  }, [startTime]);
6564
5794
  const endDate = useMemo(() => {
6565
5795
  if (!endTime) {
6566
5796
  return "-";
6567
5797
  }
6568
- return getTimeString2(endTime);
5798
+ return getTimeString(endTime);
6569
5799
  }, [endTime]);
6570
5800
  const closeTips = () => {
6571
5801
  window.localStorage.setItem(`Maintenance_${startTime}`, "1");