@griddo/ax 11.14.2-rc.0 → 11.14.2
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/config/jest/reactEasyCropMock.js +15 -0
- package/config/jest/reactTimezoneMock.js +13 -0
- package/package.json +221 -219
- package/public/img/welcome.svg +127 -0
- package/src/__tests__/components/Browser/Browser.test.tsx +27 -51
- package/src/__tests__/components/CategoryCell/CategoryCell.test.tsx +10 -5
- package/src/__tests__/components/ElementsTooltip/ElementsTooltip.test.tsx +27 -14
- package/src/__tests__/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/ErrorItem.test.tsx +2 -0
- package/src/__tests__/components/HeadingsPreviewModal/HeadingsPreviewModal.utils.test.tsx +138 -1
- package/src/__tests__/components/ImageDragAndDrop/CropStep/CropStep.test.tsx +84 -0
- package/src/__tests__/components/ImageDragAndDrop/ImageDragAndDrop.test.tsx +173 -0
- package/src/__tests__/components/KeywordsPreviewModal/KeywordsPreviewModal.test.tsx +3 -4
- package/src/__tests__/components/ProfileImage/ProfileImage.test.tsx +120 -0
- package/src/__tests__/components/ResizePanel/ResizePanel.test.tsx +8 -0
- package/src/__tests__/components/UserRolesAndSites/RoleItem/RoleItem.test.tsx +190 -0
- package/src/__tests__/components/UserRolesAndSites/UserRolesAndSites.test.tsx +471 -0
- package/src/__tests__/modules/FramePreview/HeadingsOverlay/HeadingsOverlay.test.tsx +15 -2
- package/src/__tests__/modules/Sites/Sites.test.tsx +68 -224
- package/src/__tests__/modules/Sites/SitesList/ListView/BulkHeader/BulkHeader.test.tsx +21 -17
- package/src/__tests__/modules/Sites/SitesList/SitesList.test.tsx +65 -565
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/DataStep/DataStep.test.tsx +109 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/FinalStep/FinalStep.test.tsx +157 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/ImageStep/CropView/CropView.test.tsx +51 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/ImageStep/ImageStep.test.tsx +70 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/ImageStep/UploadView/UploadView.test.tsx +92 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/TimezoneStep/TimezoneStep.test.tsx +94 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/WelcomeModal.test.tsx +78 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/WelcomeStep/WelcomeStep.test.tsx +39 -0
- package/src/__tests__/modules/Sites/SitesList/WelcomeModal/utils.test.ts +55 -0
- package/src/api/sites.tsx +4 -4
- package/src/components/Avatar/index.tsx +26 -5
- package/src/components/Avatar/style.tsx +20 -10
- package/src/components/Browser/index.tsx +7 -1
- package/src/components/ConfigPanel/index.tsx +11 -7
- package/src/components/ElementsTooltip/index.tsx +96 -34
- package/src/components/ElementsTooltip/style.tsx +12 -1
- package/src/components/Fields/FileField/index.tsx +16 -18
- package/src/components/Fields/HeadingField/index.tsx +1 -1
- package/src/components/Fields/ImageField/index.tsx +9 -38
- package/src/components/Fields/ImageField/style.tsx +12 -1
- package/src/components/Fields/ToggleField/index.tsx +1 -1
- package/src/components/Fields/Wysiwyg/index.tsx +25 -20
- package/src/components/FileGallery/GalleryPanel/index.tsx +15 -7
- package/src/components/FileGallery/index.tsx +33 -28
- package/src/components/Gallery/GalleryPanel/index.tsx +5 -16
- package/src/components/Gallery/index.tsx +0 -2
- package/src/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/index.tsx +11 -2
- package/src/components/HeadingsPreviewModal/ErrorsBanner/index.tsx +21 -3
- package/src/components/HeadingsPreviewModal/ErrorsBanner/style.tsx +2 -2
- package/src/components/HeadingsPreviewModal/index.tsx +13 -3
- package/src/components/HeadingsPreviewModal/style.tsx +18 -0
- package/src/components/HeadingsPreviewModal/utils.tsx +31 -3
- package/src/components/Image/index.tsx +2 -2
- package/src/components/ImageDragAndDrop/CropStep/index.tsx +95 -0
- package/src/components/ImageDragAndDrop/CropStep/style.tsx +101 -0
- package/src/{modules/MediaGallery → components}/ImageDragAndDrop/index.tsx +103 -40
- package/src/{modules/MediaGallery → components}/ImageDragAndDrop/style.tsx +14 -2
- package/src/components/KeywordsPreviewModal/atoms.tsx +2 -2
- package/src/components/KeywordsPreviewModal/index.tsx +6 -6
- package/src/components/KeywordsPreviewModal/utils.tsx +2 -2
- package/src/components/ProfileImage/index.tsx +55 -0
- package/src/components/ProfileImage/style.tsx +58 -0
- package/src/components/ResizePanel/ResizeHandle/index.tsx +44 -6
- package/src/components/ResizePanel/ResizeHandle/style.tsx +7 -0
- package/src/components/ResizePanel/index.tsx +25 -4
- package/src/components/Tabs/style.tsx +1 -1
- package/src/components/Tag/index.tsx +0 -1
- package/src/components/UserRolesAndSites/RoleItem/index.tsx +42 -0
- package/src/components/UserRolesAndSites/RoleItem/style.tsx +29 -0
- package/src/components/UserRolesAndSites/index.tsx +102 -0
- package/src/components/UserRolesAndSites/style.tsx +67 -0
- package/src/components/index.tsx +6 -0
- package/src/constants/index.ts +13 -1
- package/src/containers/App/actions.tsx +8 -1
- package/src/containers/Sites/actions.tsx +26 -0
- package/src/containers/Sites/constants.tsx +1 -0
- package/src/containers/Sites/interfaces.tsx +6 -0
- package/src/containers/Sites/reducer.tsx +5 -1
- package/src/containers/Users/reducer.tsx +6 -5
- package/src/guards/routeLeaving/index.tsx +9 -11
- package/src/helpers/images.tsx +50 -3
- package/src/helpers/index.tsx +2 -1
- package/src/hooks/forms.tsx +45 -48
- package/src/hooks/index.tsx +2 -1
- package/src/hooks/modals.tsx +4 -3
- package/src/hooks/window.ts +50 -2
- package/src/modules/ActivityLog/ItemLogUser/UserItem/index.tsx +1 -1
- package/src/modules/App/Routing/Logout/index.tsx +3 -5
- package/src/modules/App/Routing/NavMenu/NavItem/index.tsx +73 -52
- package/src/modules/App/Routing/NavMenu/NavItem/style.tsx +21 -7
- package/src/modules/App/Routing/NavMenu/index.tsx +59 -54
- package/src/modules/App/Routing/NavMenu/style.tsx +13 -11
- package/src/modules/CreatePass/index.tsx +1 -1
- package/src/modules/FileDrive/FileDragAndDrop/index.tsx +11 -8
- package/src/modules/FileDrive/FileModal/index.tsx +8 -9
- package/src/modules/FileDrive/index.tsx +1 -18
- package/src/modules/Forms/FormEditor/index.tsx +1 -1
- package/src/modules/FramePreview/HeadingsOverlay/index.tsx +22 -11
- package/src/modules/FramePreview/HeadingsOverlay/style.tsx +1 -1
- package/src/modules/MediaGallery/ImageModal/index.tsx +1 -5
- package/src/modules/MediaGallery/index.tsx +1 -3
- package/src/modules/Settings/Globals/constants.tsx +942 -106
- package/src/modules/Sites/SitesList/AllSitesHeader/index.tsx +33 -0
- package/src/modules/Sites/SitesList/AllSitesHeader/style.tsx +35 -0
- package/src/modules/Sites/SitesList/GridView/GridHeaderFilter/index.tsx +5 -5
- package/src/modules/Sites/SitesList/GridView/GridSiteItem/index.tsx +23 -119
- package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/index.tsx +4 -4
- package/src/modules/Sites/SitesList/ListView/BulkHeader/index.tsx +4 -3
- package/src/modules/Sites/SitesList/ListView/ListSiteItem/index.tsx +23 -120
- package/src/modules/Sites/SitesList/{RecentSiteItem → RecentSites/RecentSiteItem}/index.tsx +4 -5
- package/src/modules/Sites/SitesList/RecentSites/index.tsx +49 -0
- package/src/modules/Sites/SitesList/RecentSites/style.tsx +92 -0
- package/src/modules/Sites/SitesList/SiteModal/index.tsx +8 -7
- package/src/modules/Sites/SitesList/WelcomeModal/DataStep/index.tsx +72 -0
- package/src/modules/Sites/SitesList/WelcomeModal/DataStep/style.tsx +59 -0
- package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/constants.tsx +78 -0
- package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/index.tsx +78 -0
- package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/style.tsx +141 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/CropView/index.tsx +93 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/CropView/style.tsx +77 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/UploadView/index.tsx +100 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/UploadView/style.tsx +94 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/index.tsx +44 -0
- package/src/modules/Sites/SitesList/WelcomeModal/ImageStep/style.tsx +31 -0
- package/src/modules/Sites/SitesList/WelcomeModal/TimezoneStep/index.tsx +51 -0
- package/src/modules/Sites/SitesList/WelcomeModal/TimezoneStep/style.tsx +52 -0
- package/src/modules/Sites/SitesList/WelcomeModal/WelcomeStep/index.tsx +40 -0
- package/src/modules/Sites/SitesList/WelcomeModal/WelcomeStep/style.tsx +53 -0
- package/src/modules/Sites/SitesList/WelcomeModal/index.tsx +215 -0
- package/src/modules/Sites/SitesList/WelcomeModal/style.tsx +12 -0
- package/src/modules/Sites/SitesList/WelcomeModal/utils.ts +26 -0
- package/src/modules/Sites/SitesList/atoms.tsx +4 -4
- package/src/modules/Sites/SitesList/hooks.tsx +149 -16
- package/src/modules/Sites/SitesList/index.tsx +127 -125
- package/src/modules/Sites/SitesList/style.tsx +1 -117
- package/src/modules/Sites/SitesList/utils.tsx +9 -2
- package/src/modules/Sites/index.tsx +19 -8
- package/src/modules/Users/Profile/index.tsx +169 -31
- package/src/modules/Users/Profile/style.tsx +81 -1
- package/src/modules/Users/Roles/RoleItem/index.tsx +2 -2
- package/src/modules/Users/UserCreate/SiteItem/index.tsx +11 -14
- package/src/modules/Users/UserForm/atoms.tsx +3 -3
- package/src/modules/Users/UserForm/index.tsx +25 -29
- package/src/modules/Users/UserForm/style.tsx +15 -2
- package/src/modules/Users/UserList/UserItem/index.tsx +4 -4
- package/src/routes/index.tsx +1 -0
- package/src/types/index.tsx +2 -0
- /package/src/modules/Sites/SitesList/{RecentSiteItem → RecentSites/RecentSiteItem}/style.tsx +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from "react";
|
|
1
|
+
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import ResizeHandle from "./ResizeHandle";
|
|
4
4
|
|
|
@@ -10,12 +10,19 @@ const ResizePanel = (props: IResizePanelProps): JSX.Element => {
|
|
|
10
10
|
const { leftPanel, rightPanel, fixed = true, full = false, disabled } = props;
|
|
11
11
|
|
|
12
12
|
const [rwidth, setRwidth] = useState(MIN_WIDTH);
|
|
13
|
+
const [containerWidth, setContainerWidth] = useState(0);
|
|
13
14
|
const rightPanelRef = useRef<HTMLDivElement>(null);
|
|
14
15
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
15
16
|
|
|
17
|
+
useLayoutEffect(() => {
|
|
18
|
+
if (containerRef.current) {
|
|
19
|
+
setContainerWidth(containerRef.current.offsetWidth);
|
|
20
|
+
}
|
|
21
|
+
}, []);
|
|
22
|
+
|
|
16
23
|
const calculateFixedPanelMinWidth = (currentWidth: number) => {
|
|
17
|
-
const
|
|
18
|
-
const minWidth = Math.max(500,
|
|
24
|
+
const width = containerWidth || window.innerWidth;
|
|
25
|
+
const minWidth = Math.max(500, width - currentWidth - 32);
|
|
19
26
|
return `${minWidth}px`;
|
|
20
27
|
};
|
|
21
28
|
|
|
@@ -34,6 +41,20 @@ const ResizePanel = (props: IResizePanelProps): JSX.Element => {
|
|
|
34
41
|
return () => window.removeEventListener("resize", updateWidth);
|
|
35
42
|
}, []);
|
|
36
43
|
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
46
|
+
if (containerRef.current) {
|
|
47
|
+
setContainerWidth(containerRef.current.offsetWidth);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (containerRef.current) {
|
|
52
|
+
resizeObserver.observe(containerRef.current);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return () => resizeObserver.disconnect();
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
37
58
|
const resize = (value: number) => {
|
|
38
59
|
if (value > MIN_WIDTH) setRwidth(value);
|
|
39
60
|
};
|
|
@@ -53,7 +74,7 @@ const ResizePanel = (props: IResizePanelProps): JSX.Element => {
|
|
|
53
74
|
leftPanel
|
|
54
75
|
)}
|
|
55
76
|
</S.LeftPanel>
|
|
56
|
-
{!disabled && <ResizeHandle onMouseMove={resize} />}
|
|
77
|
+
{!disabled && <ResizeHandle onMouseMove={resize} currentWidth={rwidth} />}
|
|
57
78
|
<S.RightPanel ref={rightPanelRef} data-testid="right-panel" style={{ width: rwidth ? `${rwidth}px` : "auto" }}>
|
|
58
79
|
{rightPanel}
|
|
59
80
|
</S.RightPanel>
|
|
@@ -9,7 +9,7 @@ const TabsRow = styled.div<{ icons?: boolean; isInAppBar?: boolean; noMargins?:
|
|
|
9
9
|
`;
|
|
10
10
|
|
|
11
11
|
const TabItem = styled.button<{ active: boolean; isInAppBar?: boolean; inversed?: boolean; isDisabled?: boolean }>`
|
|
12
|
-
flex
|
|
12
|
+
flex: 1;
|
|
13
13
|
${(p) => p.theme.textStyle.headingXS};
|
|
14
14
|
border: none;
|
|
15
15
|
border-bottom: ${(p) => (p.active ? "4px solid" : "none")};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ElementsTooltip } from "@ax/components";
|
|
2
|
+
import type { IRole } from "@ax/types";
|
|
3
|
+
|
|
4
|
+
import * as S from "./style";
|
|
5
|
+
|
|
6
|
+
const RoleItem = ({ title, description, roles, isSuperAdmin = false }: IProps) => {
|
|
7
|
+
const rolesString = isSuperAdmin ? ["Super-admin"] : roles.map((role: IRole) => role.name);
|
|
8
|
+
|
|
9
|
+
const colors = isSuperAdmin
|
|
10
|
+
? { "Super-admin": "#E7CBFE" }
|
|
11
|
+
: rolesString?.reduce((prev: Record<string, string | undefined>, current) => {
|
|
12
|
+
const color: IRole | undefined = roles.find((role: IRole) => role.name === current);
|
|
13
|
+
prev[current] = color?.hex;
|
|
14
|
+
return prev;
|
|
15
|
+
}, {});
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<S.Wrapper>
|
|
19
|
+
<S.Title>{title}</S.Title>
|
|
20
|
+
<S.Description>{description}</S.Description>
|
|
21
|
+
<S.TagWrapper>
|
|
22
|
+
<ElementsTooltip
|
|
23
|
+
elements={rolesString}
|
|
24
|
+
maxChar={30}
|
|
25
|
+
rounded={true}
|
|
26
|
+
defaultElements={1}
|
|
27
|
+
elementsPerRow={2}
|
|
28
|
+
colors={colors}
|
|
29
|
+
/>
|
|
30
|
+
</S.TagWrapper>
|
|
31
|
+
</S.Wrapper>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
interface IProps {
|
|
36
|
+
title: string;
|
|
37
|
+
description: string;
|
|
38
|
+
roles: IRole[];
|
|
39
|
+
isSuperAdmin?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default RoleItem;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const Wrapper = styled.div`
|
|
4
|
+
display: flex;
|
|
5
|
+
position: relative;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
background-color: ${(p) => p.theme.color.uiBackground02};
|
|
8
|
+
border-radius: ${(p) => p.theme.radii.s};
|
|
9
|
+
border: 1px solid ${(p) => p.theme.color.uiLine};
|
|
10
|
+
padding: ${(p) => p.theme.spacing.s};
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
const Title = styled.div`
|
|
14
|
+
${(p) => p.theme.textStyle.uiL};
|
|
15
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
const Description = styled.div`
|
|
19
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
20
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const TagWrapper = styled.div`
|
|
24
|
+
position: absolute;
|
|
25
|
+
right: ${(p) => p.theme.spacing.s};
|
|
26
|
+
top: ${(p) => p.theme.spacing.s};
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
export { Wrapper, Title, Description, TagWrapper };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ElementsTooltip } from "@ax/components";
|
|
2
|
+
import type { IRole, ISite, ISiteRoles } from "@ax/types";
|
|
3
|
+
|
|
4
|
+
import RoleItem from "./RoleItem";
|
|
5
|
+
|
|
6
|
+
import * as S from "./style";
|
|
7
|
+
|
|
8
|
+
const UserRolesAndSites = (props: IUserRolesAndSitesProps): JSX.Element => {
|
|
9
|
+
const { isSuperAdmin, userRoles, sites, roles, showRows: showRowsProp } = props;
|
|
10
|
+
|
|
11
|
+
const globalSiteRole = userRoles.find((ur) => ur.siteId === "global");
|
|
12
|
+
const globalRoles = globalSiteRole ? roles.filter((r) => globalSiteRole.roles.includes(r.id)) : [];
|
|
13
|
+
|
|
14
|
+
const allSiteRole = userRoles.find((ur) => ur.siteId === "all");
|
|
15
|
+
const allRoles = allSiteRole ? roles.filter((r) => allSiteRole.roles.includes(r.id)) : [];
|
|
16
|
+
|
|
17
|
+
const siteRoles = userRoles.filter((ur) => ur.siteId !== "global" && ur.siteId !== "all");
|
|
18
|
+
|
|
19
|
+
const showRows = showRowsProp !== undefined ? showRowsProp : isSuperAdmin || (!!allSiteRole && !globalSiteRole);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<S.RolesContent>
|
|
24
|
+
{isSuperAdmin && (
|
|
25
|
+
<div data-testid="final-step-super-admin">
|
|
26
|
+
<RoleItem
|
|
27
|
+
title="You are a Super admin"
|
|
28
|
+
description="You have full access to all features and their configuration. You have access to all sites."
|
|
29
|
+
roles={[]}
|
|
30
|
+
isSuperAdmin={isSuperAdmin}
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
)}
|
|
34
|
+
{globalRoles.length > 0 && (
|
|
35
|
+
<div data-testid="final-step-global-role">
|
|
36
|
+
<RoleItem
|
|
37
|
+
title="Global data permissions"
|
|
38
|
+
description="You can access to Global data based on the permissions assigned to the role."
|
|
39
|
+
roles={globalRoles}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
)}
|
|
43
|
+
</S.RolesContent>
|
|
44
|
+
{(siteRoles.length > 0 || allRoles.length > 0) && !isSuperAdmin && (
|
|
45
|
+
<S.SitesContent data-testid="final-step-sites-content">
|
|
46
|
+
{!showRows && <S.SitesHeader>Access to Sites</S.SitesHeader>}
|
|
47
|
+
{allRoles.length > 0 && (
|
|
48
|
+
<RoleItem
|
|
49
|
+
title="Access to All Sites"
|
|
50
|
+
description="You can access to all existing and future sites depending on the permissions assigned to the role."
|
|
51
|
+
roles={allRoles}
|
|
52
|
+
/>
|
|
53
|
+
)}
|
|
54
|
+
<S.SitesGrid>
|
|
55
|
+
{siteRoles.map((ur) => {
|
|
56
|
+
const site = sites.find((s) => s.id === ur.siteId);
|
|
57
|
+
if (!site) return null;
|
|
58
|
+
|
|
59
|
+
const rolesString = roles
|
|
60
|
+
?.filter((role: IRole) => ur.roles?.includes(role.id))
|
|
61
|
+
.map((role: IRole) => role.name);
|
|
62
|
+
|
|
63
|
+
const colors = rolesString?.reduce((prev: Record<string, string | undefined>, current) => {
|
|
64
|
+
const color: IRole | undefined = roles.find((role: IRole) => role.name === current);
|
|
65
|
+
prev[current] = color?.hex;
|
|
66
|
+
return prev;
|
|
67
|
+
}, {});
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<S.SiteCard key={site.id}>
|
|
71
|
+
<S.SiteCardHeader>
|
|
72
|
+
<S.SiteName>{site.name}</S.SiteName>
|
|
73
|
+
</S.SiteCardHeader>
|
|
74
|
+
<S.TagsRow>
|
|
75
|
+
<ElementsTooltip
|
|
76
|
+
elements={rolesString}
|
|
77
|
+
maxChar={30}
|
|
78
|
+
rounded={true}
|
|
79
|
+
defaultElements={1}
|
|
80
|
+
elementsPerRow={2}
|
|
81
|
+
colors={colors}
|
|
82
|
+
/>
|
|
83
|
+
</S.TagsRow>
|
|
84
|
+
</S.SiteCard>
|
|
85
|
+
);
|
|
86
|
+
})}
|
|
87
|
+
</S.SitesGrid>
|
|
88
|
+
</S.SitesContent>
|
|
89
|
+
)}
|
|
90
|
+
</>
|
|
91
|
+
);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
interface IUserRolesAndSitesProps {
|
|
95
|
+
isSuperAdmin: boolean;
|
|
96
|
+
userRoles: ISiteRoles[];
|
|
97
|
+
sites: ISite[];
|
|
98
|
+
roles: IRole[];
|
|
99
|
+
showRows?: boolean;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export default UserRolesAndSites;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const SitesContent = styled.div`
|
|
4
|
+
padding-top: ${(p) => p.theme.spacing.s};
|
|
5
|
+
`;
|
|
6
|
+
|
|
7
|
+
const RolesContent = styled.div`
|
|
8
|
+
padding-top: ${(p) => p.theme.spacing.s};
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
const SitesHeader = styled.div`
|
|
12
|
+
${(p) => p.theme.textStyle.headingXS};
|
|
13
|
+
margin-bottom: ${(p) => p.theme.spacing.s};
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
const SitesGrid = styled.div`
|
|
17
|
+
display: grid;
|
|
18
|
+
grid-template-columns: repeat(3, 1fr);
|
|
19
|
+
gap: ${(p) => p.theme.spacing.xs};
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
const SiteCard = styled.div`
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
gap: ${(p) => p.theme.spacing.xxs};
|
|
26
|
+
background-color: ${(p) => p.theme.color.uiBackground02};
|
|
27
|
+
border: 1px solid ${(p) => p.theme.color.uiLine};
|
|
28
|
+
border-radius: ${(p) => p.theme.radii.s};
|
|
29
|
+
padding: ${(p) => p.theme.spacing.s};
|
|
30
|
+
height: 96px;
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
const SiteCardHeader = styled.div`
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: ${(p) => p.theme.spacing.xxs};
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
const SiteAvatar = styled.img`
|
|
40
|
+
width: 32px;
|
|
41
|
+
height: 32px;
|
|
42
|
+
border-radius: ${(p) => p.theme.radii.xs};
|
|
43
|
+
object-fit: cover;
|
|
44
|
+
flex-shrink: 0;
|
|
45
|
+
margin-right: ${(p) => p.theme.spacing.xxs};
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
const SiteName = styled.div`
|
|
49
|
+
${(p) => p.theme.textStyle.uiL};
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
text-overflow: ellipsis;
|
|
52
|
+
white-space: nowrap;
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const TagsRow = styled.div`
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: ${(p) => p.theme.spacing.xxs};
|
|
59
|
+
flex-wrap: wrap;
|
|
60
|
+
margin-top: auto;
|
|
61
|
+
|
|
62
|
+
& > div {
|
|
63
|
+
margin-bottom: 0;
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
export { RolesContent, SitesContent, SitesHeader, SitesGrid, SiteCard, SiteCardHeader, SiteAvatar, SiteName, TagsRow };
|
package/src/components/index.tsx
CHANGED
|
@@ -73,6 +73,7 @@ import HeadingsPreviewModal from "./HeadingsPreviewModal";
|
|
|
73
73
|
import Icon from "./Icon";
|
|
74
74
|
import IconAction from "./IconAction";
|
|
75
75
|
import Image from "./Image";
|
|
76
|
+
import ImageDragAndDrop from "./ImageDragAndDrop";
|
|
76
77
|
import InformativeMenu from "./InformativeMenu";
|
|
77
78
|
import KeywordsPreviewModal from "./KeywordsPreviewModal";
|
|
78
79
|
import LanguageMenu from "./LanguageMenu";
|
|
@@ -89,6 +90,7 @@ import Notification from "./Notification";
|
|
|
89
90
|
import OcassionalToast from "./OcassionalToast";
|
|
90
91
|
import PageFinder from "./PageFinder";
|
|
91
92
|
import Pagination from "./Pagination";
|
|
93
|
+
import ProfileImage from "./ProfileImage";
|
|
92
94
|
import ProgressBar from "./ProgressBar";
|
|
93
95
|
import ReorderArrows from "./ReorderArrows";
|
|
94
96
|
import ResizePanel from "./ResizePanel";
|
|
@@ -123,6 +125,7 @@ import Tabs from "./Tabs";
|
|
|
123
125
|
import Tag from "./Tag";
|
|
124
126
|
import Toast from "./Toast";
|
|
125
127
|
import Tooltip from "./Tooltip";
|
|
128
|
+
import UserRolesAndSites from "./UserRolesAndSites";
|
|
126
129
|
|
|
127
130
|
export {
|
|
128
131
|
ActionMenu,
|
|
@@ -181,6 +184,7 @@ export {
|
|
|
181
184
|
Icon,
|
|
182
185
|
IconAction,
|
|
183
186
|
Image,
|
|
187
|
+
ImageDragAndDrop,
|
|
184
188
|
ImageField,
|
|
185
189
|
InformativeMenu,
|
|
186
190
|
KeywordsPreviewModal,
|
|
@@ -206,6 +210,7 @@ export {
|
|
|
206
210
|
OcassionalToast,
|
|
207
211
|
PageFinder,
|
|
208
212
|
Pagination,
|
|
213
|
+
ProfileImage,
|
|
209
214
|
PermissionsFilter,
|
|
210
215
|
ProgressBar,
|
|
211
216
|
RadioField,
|
|
@@ -245,6 +250,7 @@ export {
|
|
|
245
250
|
UniqueCheck,
|
|
246
251
|
UrlField,
|
|
247
252
|
UsersFilter,
|
|
253
|
+
UserRolesAndSites,
|
|
248
254
|
VisualOption,
|
|
249
255
|
VisualUniqueSelection,
|
|
250
256
|
Wysiwyg,
|
package/src/constants/index.ts
CHANGED
|
@@ -24,4 +24,16 @@ const itemLabel = {
|
|
|
24
24
|
|
|
25
25
|
type ItemLabel = ValueOf<typeof itemLabel>;
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
const VALID_IMAGE_FORMATS = ["jpeg", "jpg", "png", "svg", "gif", "webp"];
|
|
28
|
+
const VALID_DOCUMENT_FORMATS = ["pdf", "doc", "docx", "xls", "xlsx", "zip", "csv", "txt"];
|
|
29
|
+
const VALID_VIDEO_FORMATS = ["mov", "mp4", "wmv", "avi", "webm", "mkv"];
|
|
30
|
+
const VALID_FILE_FORMATS = [...VALID_DOCUMENT_FORMATS, ...VALID_VIDEO_FORMATS];
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
itemLabel,
|
|
34
|
+
type ItemLabel,
|
|
35
|
+
VALID_IMAGE_FORMATS,
|
|
36
|
+
VALID_DOCUMENT_FORMATS,
|
|
37
|
+
VALID_VIDEO_FORMATS,
|
|
38
|
+
VALID_FILE_FORMATS,
|
|
39
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { global, languages } from "@ax/api";
|
|
2
|
+
import { usersActions } from "@ax/containers/Users";
|
|
2
3
|
import { isReqOk } from "@ax/helpers";
|
|
3
4
|
import type { IRootState } from "@ax/types";
|
|
4
|
-
import { usersActions } from "@ax/containers/Users";
|
|
5
5
|
|
|
6
6
|
import type { AxiosResponse } from "axios";
|
|
7
7
|
import differenceInSeconds from "date-fns/differenceInSeconds";
|
|
@@ -89,6 +89,12 @@ function logout(): ILogoutAction {
|
|
|
89
89
|
return { type: LOGOUT, payload: { token: "" } };
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
function logoutAndNavigate(): (dispatch: Dispatch) => Promise<void> {
|
|
93
|
+
return async (dispatch) => {
|
|
94
|
+
await setHistoryPush("/logout")(dispatch);
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
92
98
|
function setLanguage(lang: { locale: string; id: number }): ISetLanguageAction {
|
|
93
99
|
localStorage.setItem("langID", JSON.stringify(lang.id));
|
|
94
100
|
return { type: SET_LANGUAGE, payload: { lang } };
|
|
@@ -267,6 +273,7 @@ export {
|
|
|
267
273
|
login,
|
|
268
274
|
loginSSO,
|
|
269
275
|
logout,
|
|
276
|
+
logoutAndNavigate,
|
|
270
277
|
resetError,
|
|
271
278
|
setError,
|
|
272
279
|
setGlobalLanguages,
|
|
@@ -27,6 +27,7 @@ import type { Dispatch } from "redux";
|
|
|
27
27
|
import {
|
|
28
28
|
DEFAULT_PARAMS,
|
|
29
29
|
SET_ALL_SITE_PAGES,
|
|
30
|
+
SET_ALL_SITES,
|
|
30
31
|
SET_CONFIG,
|
|
31
32
|
SET_CONTENT_FILTERS,
|
|
32
33
|
SET_CURRENT_SEARCH,
|
|
@@ -46,6 +47,7 @@ import {
|
|
|
46
47
|
} from "./constants";
|
|
47
48
|
import type {
|
|
48
49
|
ISetAllSitePagesAction,
|
|
50
|
+
ISetAllSitesAction,
|
|
49
51
|
ISetConfig,
|
|
50
52
|
ISetContentFilters,
|
|
51
53
|
ISetCurrentSearch,
|
|
@@ -87,6 +89,10 @@ function setSitesByLang(sitesList: ISite[]): ISetSitesByLangAction {
|
|
|
87
89
|
return { type: SET_SITES_BY_LANG, payload: { sitesByLang: sitesList } };
|
|
88
90
|
}
|
|
89
91
|
|
|
92
|
+
function setAllSites(allSites: ISite[]): ISetAllSitesAction {
|
|
93
|
+
return { type: SET_ALL_SITES, payload: { allSites } };
|
|
94
|
+
}
|
|
95
|
+
|
|
90
96
|
function setCurrentSiteInfo(currentSiteInfo: ISite | null): ISetCurrentSiteInfoAction {
|
|
91
97
|
localStorage.setItem("siteID", JSON.stringify(currentSiteInfo?.id || "global"));
|
|
92
98
|
return { type: SET_CURRENT_SITE_INFO, payload: { currentSiteInfo } };
|
|
@@ -203,6 +209,25 @@ function getSitesByLang(params: IGetSitesParams): (dispatch: Dispatch) => Promis
|
|
|
203
209
|
};
|
|
204
210
|
}
|
|
205
211
|
|
|
212
|
+
function getAllSites(): (dispatch: Dispatch) => Promise<void> {
|
|
213
|
+
return async (dispatch) => {
|
|
214
|
+
try {
|
|
215
|
+
const responseActions = {
|
|
216
|
+
handleSuccess: (data: any) => {
|
|
217
|
+
dispatch(setAllSites(data.allSites));
|
|
218
|
+
},
|
|
219
|
+
handleError: (response: any) => appActions.handleError(response)(dispatch),
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const callback = async () => sites.getAllSites({ pagination: false });
|
|
223
|
+
|
|
224
|
+
await handleRequest(callback, responseActions, [])(dispatch);
|
|
225
|
+
} catch (e) {
|
|
226
|
+
console.log(e);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
206
231
|
function saveSettings(form: ISettingsForm): (dispatch: Dispatch, getState: () => IRootState) => Promise<boolean> {
|
|
207
232
|
return async (dispatch, getState) => {
|
|
208
233
|
try {
|
|
@@ -817,4 +842,5 @@ export {
|
|
|
817
842
|
getSite,
|
|
818
843
|
updateCurrentSearch,
|
|
819
844
|
setIsSitesLoading,
|
|
845
|
+
getAllSites,
|
|
820
846
|
};
|
|
@@ -18,6 +18,7 @@ export const SET_CONFIG = `${NAME}/SET_CONFIG`;
|
|
|
18
18
|
export const SET_CURRENT_SEARCH = `${NAME}/SET_CURRENT_SEARCH`;
|
|
19
19
|
export const SET_THEME_ELEMENTS = `${NAME}/SET_THEME_ELEMENTS`;
|
|
20
20
|
export const SET_IS_SITES_LOADING = `${NAME}/SET_IS_SITES_LOADING`;
|
|
21
|
+
export const SET_ALL_SITES = `${NAME}/SET_ALL_SITES`;
|
|
21
22
|
|
|
22
23
|
export const ITEMS_PER_PAGE = 50;
|
|
23
24
|
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
SET_CURRENT_SEARCH,
|
|
18
18
|
SET_THEME_ELEMENTS,
|
|
19
19
|
SET_IS_SITES_LOADING,
|
|
20
|
+
SET_ALL_SITES,
|
|
20
21
|
} from "./constants";
|
|
21
22
|
import { IQueryValue, ISite, ISiteListConfig, IThemeElements } from "@ax/types";
|
|
22
23
|
|
|
@@ -110,4 +111,9 @@ export interface ISetIsSitesLoading {
|
|
|
110
111
|
payload: { isSitesLoading: boolean };
|
|
111
112
|
}
|
|
112
113
|
|
|
114
|
+
export interface ISetAllSitesAction {
|
|
115
|
+
type: typeof SET_ALL_SITES;
|
|
116
|
+
payload: { allSites: ISite[] };
|
|
117
|
+
}
|
|
118
|
+
|
|
113
119
|
export type SitesActionsCreators = ISetSitesAction & ISetCurrentSiteInfoAction;
|
|
@@ -17,9 +17,10 @@ import {
|
|
|
17
17
|
SET_CURRENT_SEARCH,
|
|
18
18
|
SET_THEME_ELEMENTS,
|
|
19
19
|
SET_IS_SITES_LOADING,
|
|
20
|
+
SET_ALL_SITES,
|
|
20
21
|
} from "./constants";
|
|
21
22
|
|
|
22
|
-
import { ISite, IPage, ILanguage, ISiteListConfig, IQueryValue, IThemeElements } from "@ax/types";
|
|
23
|
+
import type { ISite, IPage, ILanguage, ISiteListConfig, IQueryValue, IThemeElements } from "@ax/types";
|
|
23
24
|
|
|
24
25
|
import { SitesActionsCreators } from "./interfaces";
|
|
25
26
|
|
|
@@ -30,6 +31,7 @@ export interface ISitesState {
|
|
|
30
31
|
sites: ISite[];
|
|
31
32
|
recentSites: ISite[];
|
|
32
33
|
sitesTotalItems: number;
|
|
34
|
+
allSites: ISite[];
|
|
33
35
|
sitesByLang: ISite[];
|
|
34
36
|
currentSiteInfo: ISite | null;
|
|
35
37
|
currentFilter: string | null;
|
|
@@ -65,6 +67,7 @@ export const initialState = {
|
|
|
65
67
|
currentSitePages: [],
|
|
66
68
|
allSitePages: [],
|
|
67
69
|
sites: [],
|
|
70
|
+
allSites: [],
|
|
68
71
|
recentSites: [],
|
|
69
72
|
sitesByLang: [],
|
|
70
73
|
currentSiteInfo: null,
|
|
@@ -101,6 +104,7 @@ export function reducer(state = initialState, action: any): ISitesState {
|
|
|
101
104
|
case SET_CURRENT_SEARCH:
|
|
102
105
|
case SET_THEME_ELEMENTS:
|
|
103
106
|
case SET_IS_SITES_LOADING:
|
|
107
|
+
case SET_ALL_SITES:
|
|
104
108
|
return { ...state, ...action.payload };
|
|
105
109
|
default:
|
|
106
110
|
return state;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { IRole, IUser } from "@ax/types";
|
|
1
|
+
import type { IRole, IUser } from "@ax/types";
|
|
2
|
+
|
|
2
3
|
import {
|
|
3
|
-
SET_USERS,
|
|
4
|
-
SET_USER_FORM,
|
|
5
|
-
SET_CURRENT_USER,
|
|
6
|
-
SET_ROLES,
|
|
7
4
|
SET_CURRENT_PERMISSIONS,
|
|
5
|
+
SET_CURRENT_USER,
|
|
8
6
|
SET_GLOBAL_PERMISSIONS,
|
|
7
|
+
SET_ROLES,
|
|
8
|
+
SET_USER_FORM,
|
|
9
|
+
SET_USERS,
|
|
9
10
|
} from "./constants";
|
|
10
11
|
|
|
11
12
|
export interface IUsersState {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type ReactNode, useEffect, useState } from "react";
|
|
2
2
|
import { Prompt } from "react-router-dom";
|
|
3
3
|
|
|
4
|
-
import { useModal } from "@ax/hooks";
|
|
5
4
|
import { Modal } from "@ax/components";
|
|
5
|
+
import { useModal } from "@ax/hooks";
|
|
6
6
|
|
|
7
7
|
import * as S from "./style";
|
|
8
8
|
|
|
@@ -13,8 +13,8 @@ const RouteLeavingGuard = (props: IProps) => {
|
|
|
13
13
|
const [lastLocation, setLastLocation] = useState<Location | null>(null);
|
|
14
14
|
const [confirmedNavigation, setConfirmedNavigation] = useState(false);
|
|
15
15
|
|
|
16
|
-
const handleBlockedNavigation = (nextLocation:
|
|
17
|
-
const isAllowedNavigation = allowedRoutes
|
|
16
|
+
const handleBlockedNavigation = (nextLocation: Location): boolean => {
|
|
17
|
+
const isAllowedNavigation = allowedRoutes?.includes(nextLocation.pathname);
|
|
18
18
|
if (!confirmedNavigation && !isAllowedNavigation) {
|
|
19
19
|
toggleModal();
|
|
20
20
|
setLastLocation(nextLocation);
|
|
@@ -55,11 +55,9 @@ const RouteLeavingGuard = (props: IProps) => {
|
|
|
55
55
|
mainAction={mainAction}
|
|
56
56
|
secondaryAction={secondaryAction}
|
|
57
57
|
>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
</S.ModalContent>
|
|
62
|
-
}
|
|
58
|
+
<S.ModalContent>
|
|
59
|
+
{text} If you exit without saving it, it will be lost. Do you want to discard your changes?
|
|
60
|
+
</S.ModalContent>
|
|
63
61
|
</Modal>
|
|
64
62
|
</>
|
|
65
63
|
);
|
|
@@ -68,8 +66,8 @@ const RouteLeavingGuard = (props: IProps) => {
|
|
|
68
66
|
interface IRouterLeavingProps {
|
|
69
67
|
when: boolean;
|
|
70
68
|
action(path: string): void;
|
|
71
|
-
text:
|
|
72
|
-
allowedRoutes?:
|
|
69
|
+
text: ReactNode;
|
|
70
|
+
allowedRoutes?: string[];
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
type IProps = IRouterLeavingProps;
|
package/src/helpers/images.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Area } from "react-easy-crop";
|
|
2
|
+
|
|
1
3
|
import { toBlob } from "html-to-image";
|
|
2
4
|
|
|
3
5
|
const formatBytes = (bytes: number | null, decimals = 2) => {
|
|
@@ -9,7 +11,7 @@ const formatBytes = (bytes: number | null, decimals = 2) => {
|
|
|
9
11
|
|
|
10
12
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
11
13
|
|
|
12
|
-
return parseFloat((bytes /
|
|
14
|
+
return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
const imageToBase64 = (file: any): Promise<string> => {
|
|
@@ -35,7 +37,7 @@ const getImageFromHtml = async (html: HTMLDivElement, fileName: string): Promise
|
|
|
35
37
|
|
|
36
38
|
const elChildren = browserContent.querySelectorAll("*");
|
|
37
39
|
let maxAbsoluteElementHeight = 0;
|
|
38
|
-
[].forEach.call(elChildren,
|
|
40
|
+
[].forEach.call(elChildren, (element: HTMLElement) => {
|
|
39
41
|
const isAbsolutePosition = getComputedStyle(element).position === "absolute";
|
|
40
42
|
const isMaxAbsolutePositionHeight = element.clientHeight > maxAbsoluteElementHeight;
|
|
41
43
|
if (isAbsolutePosition && isMaxAbsolutePositionHeight) {
|
|
@@ -90,4 +92,49 @@ const getImageFromIFrame = async (html: HTMLDivElement, fileName: string): Promi
|
|
|
90
92
|
});
|
|
91
93
|
};
|
|
92
94
|
|
|
93
|
-
|
|
95
|
+
const createImage = (url: string): Promise<HTMLImageElement> =>
|
|
96
|
+
new Promise((resolve, reject) => {
|
|
97
|
+
const image = new Image();
|
|
98
|
+
image.addEventListener("load", () => resolve(image));
|
|
99
|
+
image.addEventListener("error", (error) => reject(error));
|
|
100
|
+
image.setAttribute("crossOrigin", "anonymous");
|
|
101
|
+
image.src = url;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const getCroppedImg = async (imageSrc: string, pixelCrop: Area): Promise<File> => {
|
|
105
|
+
const image = await createImage(imageSrc);
|
|
106
|
+
const canvas = document.createElement("canvas");
|
|
107
|
+
canvas.width = pixelCrop.width;
|
|
108
|
+
canvas.height = pixelCrop.height;
|
|
109
|
+
const ctx = canvas.getContext("2d");
|
|
110
|
+
|
|
111
|
+
if (!ctx) throw new Error("Could not get canvas context");
|
|
112
|
+
|
|
113
|
+
ctx.drawImage(
|
|
114
|
+
image,
|
|
115
|
+
pixelCrop.x,
|
|
116
|
+
pixelCrop.y,
|
|
117
|
+
pixelCrop.width,
|
|
118
|
+
pixelCrop.height,
|
|
119
|
+
0,
|
|
120
|
+
0,
|
|
121
|
+
pixelCrop.width,
|
|
122
|
+
pixelCrop.height,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
canvas.toBlob(
|
|
127
|
+
(blob) => {
|
|
128
|
+
if (!blob) {
|
|
129
|
+
reject(new Error("Canvas is empty"));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
resolve(new File([blob], "avatar.jpg", { type: "image/jpeg" }));
|
|
133
|
+
},
|
|
134
|
+
"image/jpeg",
|
|
135
|
+
0.9,
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export { formatBytes, imageToBase64, getImageFromHtml, getImageFromIFrame, createImage, getCroppedImg };
|