diff --git a/frontend/src/static/js/pages/HistoryPage.tsx b/frontend/src/static/js/pages/HistoryPage.tsx index adeba699..923ac3c2 100644 --- a/frontend/src/static/js/pages/HistoryPage.tsx +++ b/frontend/src/static/js/pages/HistoryPage.tsx @@ -55,7 +55,7 @@ export const HistoryPage: React.FC = () => { const anonymousPage = isAnonymous || !PageStore.get('config-options').pages.profile.includeHistory; if (!anonymousPage) { - addClassname(document.getElementById('page-history'), 'profile-page-history'); + addClassname(document.getElementById('page-history')!, 'profile-page-history'); window.MediaCMS.profileId = username; } diff --git a/frontend/src/static/js/pages/HomePage.tsx b/frontend/src/static/js/pages/HomePage.tsx index b0179dfc..007705b1 100755 --- a/frontend/src/static/js/pages/HomePage.tsx +++ b/frontend/src/static/js/pages/HomePage.tsx @@ -76,7 +76,7 @@ export const HomePage: React.FC = ({ = ({ = ({ { const anonymousPage = isAnonymous || !PageStore.get('config-options').pages.profile.includeLikedMedia; if (!anonymousPage) { - addClassname(document.getElementById('page-liked'), 'profile-page-liked'); + addClassname(document.getElementById('page-liked')!, 'profile-page-liked'); window.MediaCMS.profileId = username; } diff --git a/frontend/src/static/js/utils/contexts/ApiUrlContext.js b/frontend/src/static/js/utils/contexts/ApiUrlContext.js deleted file mode 100644 index 8a9a99f8..00000000 --- a/frontend/src/static/js/utils/contexts/ApiUrlContext.js +++ /dev/null @@ -1,5 +0,0 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; - -export const ApiUrlContext = createContext(mediacmsConfig(window.MediaCMS).api); -export const ApiUrlConsumer = ApiUrlContext.Consumer; \ No newline at end of file diff --git a/frontend/src/static/js/utils/contexts/ApiUrlContext.ts b/frontend/src/static/js/utils/contexts/ApiUrlContext.ts new file mode 100644 index 00000000..2b15b32b --- /dev/null +++ b/frontend/src/static/js/utils/contexts/ApiUrlContext.ts @@ -0,0 +1,5 @@ +import { createContext } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; + +export const ApiUrlContext = createContext(mediacmsConfig(window.MediaCMS).api); +export const ApiUrlConsumer = ApiUrlContext.Consumer; diff --git a/frontend/src/static/js/utils/contexts/HeaderContext.js b/frontend/src/static/js/utils/contexts/HeaderContext.js deleted file mode 100644 index 2717b351..00000000 --- a/frontend/src/static/js/utils/contexts/HeaderContext.js +++ /dev/null @@ -1,130 +0,0 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; -import { translateString } from '../../utils/helpers/'; - -const config = mediacmsConfig(window.MediaCMS); - -const links = config.url; -const theme = config.theme; -const user = config.member; - -const hasThemeSwitcher = theme.switch.enabled && 'header' === theme.switch.position; - -function popupTopNavItems() { - const items = []; - - if (!user.is.anonymous) { - if (user.can.addMedia) { - items.push({ - link: links.user.addMedia, - icon: 'video_call', - text: translateString('Upload media'), - itemAttr: { - className: 'visible-only-in-small', - }, - }); - - if (user.pages.media) { - items.push({ - link: user.pages.media, - icon: 'video_library', - text: translateString('My media'), - }); - } - } - - items.push({ - link: links.signout, - icon: 'exit_to_app', - text: translateString('Sign out'), - }); - } - - return items; -} - -function popupMiddleNavItems() { - const items = []; - - if (hasThemeSwitcher) { - items.push({ - itemType: 'open-subpage', - icon: 'brightness_4', - iconPos: 'left', - text: 'Switch theme', - buttonAttr: { - className: 'change-page', - 'data-page-id': 'switch-theme', - }, - }); - } - - if (user.is.anonymous) { - if (user.can.login) { - items.push({ - itemType: 'link', - icon: 'login', - iconPos: 'left', - text: translateString('Sign in'), - link: links.signin, - linkAttr: { - className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small', - }, - }); - } - - if (user.can.register) { - items.push({ - itemType: 'link', - icon: 'person_add', - iconPos: 'left', - text: translateString('Register'), - link: links.register, - linkAttr: { - className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small', - }, - }); - } - } else { - items.push({ - link: links.user.editProfile, - icon: 'brush', - text: translateString('Edit profile'), - }); - - if (user.can.changePassword) { - items.push({ - link: links.changePassword, - icon: 'lock', - text: translateString('Change password'), - }); - } - } - - return items; -} - -function popupBottomNavItems() { - const items = []; - - if (user.is.admin) { - items.push({ - link: links.admin, - icon: 'admin_panel_settings', - text: 'MediaCMS administration', - }); - } - - return items; -} - -export const HeaderContext = createContext({ - hasThemeSwitcher, - popupNavItems: { - top: popupTopNavItems(), - middle: popupMiddleNavItems(), - bottom: popupBottomNavItems(), - }, -}); - -export const HeaderConsumer = HeaderContext.Consumer; \ No newline at end of file diff --git a/frontend/src/static/js/utils/contexts/HeaderContext.ts b/frontend/src/static/js/utils/contexts/HeaderContext.ts new file mode 100644 index 00000000..0d3084c7 --- /dev/null +++ b/frontend/src/static/js/utils/contexts/HeaderContext.ts @@ -0,0 +1,130 @@ +import { createContext } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; +import { translateString } from '../helpers'; + +const config = mediacmsConfig(window.MediaCMS); + +const links = config.url; +const theme = config.theme; +const user = config.member; + +const hasThemeSwitcher = theme.switch.enabled && 'header' === theme.switch.position; + +function popupTopNavItems() { + const items = []; + + if (!user.is.anonymous) { + if (user.can.addMedia) { + items.push({ + link: links.user.addMedia, + icon: 'video_call', + text: translateString('Upload media'), + itemAttr: { + className: 'visible-only-in-small', + }, + }); + + if (user.pages.media) { + items.push({ + link: user.pages.media, + icon: 'video_library', + text: translateString('My media'), + }); + } + } + + items.push({ + link: links.signout, + icon: 'exit_to_app', + text: translateString('Sign out'), + }); + } + + return items; +} + +function popupMiddleNavItems() { + const items = []; + + if (hasThemeSwitcher) { + items.push({ + itemType: 'open-subpage', + icon: 'brightness_4', + iconPos: 'left', + text: 'Switch theme', + buttonAttr: { + className: 'change-page', + 'data-page-id': 'switch-theme', + }, + }); + } + + if (user.is.anonymous) { + if (user.can.login) { + items.push({ + itemType: 'link', + icon: 'login', + iconPos: 'left', + text: translateString('Sign in'), + link: links.signin, + linkAttr: { + className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small', + }, + }); + } + + if (user.can.register) { + items.push({ + itemType: 'link', + icon: 'person_add', + iconPos: 'left', + text: translateString('Register'), + link: links.register, + linkAttr: { + className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small', + }, + }); + } + } else { + items.push({ + link: links.user.editProfile, + icon: 'brush', + text: translateString('Edit profile'), + }); + + if (user.can.changePassword) { + items.push({ + link: links.changePassword, + icon: 'lock', + text: translateString('Change password'), + }); + } + } + + return items; +} + +function popupBottomNavItems() { + const items = []; + + if (user.is.admin) { + items.push({ + link: links.admin, + icon: 'admin_panel_settings', + text: 'MediaCMS administration', + }); + } + + return items; +} + +export const HeaderContext = createContext({ + hasThemeSwitcher, + popupNavItems: { + top: popupTopNavItems(), + middle: popupMiddleNavItems(), + bottom: popupBottomNavItems(), + }, +}); + +export const HeaderConsumer = HeaderContext.Consumer; diff --git a/frontend/src/static/js/utils/contexts/LayoutContext.js b/frontend/src/static/js/utils/contexts/LayoutContext.tsx similarity index 72% rename from frontend/src/static/js/utils/contexts/LayoutContext.js rename to frontend/src/static/js/utils/contexts/LayoutContext.tsx index 813fc80b..f7561342 100644 --- a/frontend/src/static/js/utils/contexts/LayoutContext.js +++ b/frontend/src/static/js/utils/contexts/LayoutContext.tsx @@ -1,13 +1,15 @@ -import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; -import { BrowserCache } from '../classes/'; -import { PageStore } from '../stores/'; -import { addClassname, removeClassname, inEmbeddedApp } from '../helpers/'; +import React, { createContext, ReactNode, useContext, useEffect, useMemo, useState } from 'react'; +import { BrowserCache } from '../classes'; +import { PageStore } from '../stores'; +import { addClassname, removeClassname, inEmbeddedApp } from '../helpers'; import SiteContext from './SiteContext'; -let slidingSidebarTimeout; +let slidingSidebarTimeout: NodeJS.Timeout | null = null; -function onSidebarVisibilityChange(visibleSidebar) { - clearTimeout(slidingSidebarTimeout); +function onSidebarVisibilityChange(visibleSidebar: boolean) { + if (slidingSidebarTimeout) { + clearTimeout(slidingSidebarTimeout); + } addClassname(document.body, 'sliding-sidebar'); @@ -39,18 +41,29 @@ function onSidebarVisibilityChange(visibleSidebar) { }, 20); } -export const LayoutContext = createContext(); +export const LayoutContext = createContext({ + enabledSidebar: true, + visibleSidebar: true, + setVisibleSidebar: (_: boolean) => {}, + visibleMobileSearch: false, + toggleMobileSearch: () => {}, + toggleSidebar: () => {}, +}); -export const LayoutProvider = ({ children }) => { +export const LayoutProvider = ({ children }: { children: ReactNode }) => { const site = useContext(SiteContext); - const cache = new BrowserCache('MediaCMS[' + site.id + '][layout]', 86400); + const cache = BrowserCache('MediaCMS[' + site.id + '][layout]', 86400); const isMediaPage = useMemo(() => PageStore.get('current-page') === 'media', []); const isEmbeddedApp = useMemo(() => inEmbeddedApp(), []); const enabledSidebar = Boolean(document.getElementById('app-sidebar') || document.querySelector('.page-sidebar')); - const [visibleSidebar, setVisibleSidebar] = useState(cache.get('visible-sidebar')); + const [visibleSidebar, setVisibleSidebar] = useState( + cache instanceof Error + ? true // @todo: Check this again + : cache.get('visible-sidebar') + ); const [visibleMobileSearch, setVisibleMobileSearch] = useState(false); const toggleMobileSearch = () => { @@ -71,7 +84,9 @@ export const LayoutProvider = ({ children }) => { } if (!isEmbeddedApp && !isMediaPage && 1023 < window.innerWidth) { - cache.set('visible-sidebar', visibleSidebar); + if (!(cache instanceof Error)) { + cache.set('visible-sidebar', visibleSidebar); + } } }, [isEmbeddedApp, isMediaPage, visibleSidebar]); diff --git a/frontend/src/static/js/utils/contexts/LinksContext.js b/frontend/src/static/js/utils/contexts/LinksContext.ts similarity index 54% rename from frontend/src/static/js/utils/contexts/LinksContext.js rename to frontend/src/static/js/utils/contexts/LinksContext.ts index eea1cddf..4991914a 100644 --- a/frontend/src/static/js/utils/contexts/LinksContext.js +++ b/frontend/src/static/js/utils/contexts/LinksContext.ts @@ -1,5 +1,5 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; +import { createContext } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; export const LinksContext = createContext(mediacmsConfig(window.MediaCMS).url); export const LinksConsumer = LinksContext.Consumer; diff --git a/frontend/src/static/js/utils/contexts/MemberContext.js b/frontend/src/static/js/utils/contexts/MemberContext.ts similarity index 55% rename from frontend/src/static/js/utils/contexts/MemberContext.js rename to frontend/src/static/js/utils/contexts/MemberContext.ts index 2948a221..f45c1bea 100644 --- a/frontend/src/static/js/utils/contexts/MemberContext.js +++ b/frontend/src/static/js/utils/contexts/MemberContext.ts @@ -1,5 +1,5 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; +import { createContext } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; export const MemberContext = createContext(mediacmsConfig(window.MediaCMS).member); export const MemberConsumer = MemberContext.Consumer; diff --git a/frontend/src/static/js/utils/contexts/PlaylistsContext.js b/frontend/src/static/js/utils/contexts/PlaylistsContext.js deleted file mode 100644 index 12c99eb3..00000000 --- a/frontend/src/static/js/utils/contexts/PlaylistsContext.js +++ /dev/null @@ -1,4 +0,0 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; - -export const PlaylistsContext = createContext(mediacmsConfig(window.MediaCMS).playlists); diff --git a/frontend/src/static/js/utils/contexts/PlaylistsContext.ts b/frontend/src/static/js/utils/contexts/PlaylistsContext.ts new file mode 100644 index 00000000..eae89a2f --- /dev/null +++ b/frontend/src/static/js/utils/contexts/PlaylistsContext.ts @@ -0,0 +1,4 @@ +import { createContext } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; + +export const PlaylistsContext = createContext(mediacmsConfig(window.MediaCMS).playlists); diff --git a/frontend/src/static/js/utils/contexts/ShareOptionsContext.js b/frontend/src/static/js/utils/contexts/ShareOptionsContext.js deleted file mode 100644 index ddc1e9a1..00000000 --- a/frontend/src/static/js/utils/contexts/ShareOptionsContext.js +++ /dev/null @@ -1,5 +0,0 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; - -export const ShareOptionsContext = createContext(mediacmsConfig(window.MediaCMS).media.share.options); - diff --git a/frontend/src/static/js/utils/contexts/ShareOptionsContext.ts b/frontend/src/static/js/utils/contexts/ShareOptionsContext.ts new file mode 100644 index 00000000..ecc43b1c --- /dev/null +++ b/frontend/src/static/js/utils/contexts/ShareOptionsContext.ts @@ -0,0 +1,4 @@ +import { createContext } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; + +export const ShareOptionsContext = createContext(mediacmsConfig(window.MediaCMS).media.share.options); diff --git a/frontend/src/static/js/utils/contexts/SidebarContext.js b/frontend/src/static/js/utils/contexts/SidebarContext.js deleted file mode 100644 index f0a6560e..00000000 --- a/frontend/src/static/js/utils/contexts/SidebarContext.js +++ /dev/null @@ -1,5 +0,0 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; - -export const SidebarContext = createContext(mediacmsConfig(window.MediaCMS).sidebar); -export const SidebarConsumer = SidebarContext.Consumer; \ No newline at end of file diff --git a/frontend/src/static/js/utils/contexts/SidebarContext.ts b/frontend/src/static/js/utils/contexts/SidebarContext.ts new file mode 100644 index 00000000..c7e9592d --- /dev/null +++ b/frontend/src/static/js/utils/contexts/SidebarContext.ts @@ -0,0 +1,5 @@ +import { createContext } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; + +export const SidebarContext = createContext(mediacmsConfig(window.MediaCMS).sidebar); +export const SidebarConsumer = SidebarContext.Consumer; diff --git a/frontend/src/static/js/utils/contexts/SiteContext.js b/frontend/src/static/js/utils/contexts/SiteContext.ts similarity index 58% rename from frontend/src/static/js/utils/contexts/SiteContext.js rename to frontend/src/static/js/utils/contexts/SiteContext.ts index 5680cfb5..6c38c539 100644 --- a/frontend/src/static/js/utils/contexts/SiteContext.js +++ b/frontend/src/static/js/utils/contexts/SiteContext.ts @@ -1,5 +1,5 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; +import { createContext } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; export const SiteContext = createContext(mediacmsConfig(window.MediaCMS).site); export const SiteConsumer = SiteContext.Consumer; diff --git a/frontend/src/static/js/utils/contexts/TextsContext.js b/frontend/src/static/js/utils/contexts/TextsContext.ts similarity index 61% rename from frontend/src/static/js/utils/contexts/TextsContext.js rename to frontend/src/static/js/utils/contexts/TextsContext.ts index c32cab20..986388b5 100644 --- a/frontend/src/static/js/utils/contexts/TextsContext.js +++ b/frontend/src/static/js/utils/contexts/TextsContext.ts @@ -1,10 +1,10 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; +import { createContext } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; const notifications = mediacmsConfig(window.MediaCMS).notifications.messages; const texts = { - notifications, + notifications, }; export const TextsContext = createContext(texts); diff --git a/frontend/src/static/js/utils/contexts/ThemeContext.js b/frontend/src/static/js/utils/contexts/ThemeContext.js deleted file mode 100644 index 337df79a..00000000 --- a/frontend/src/static/js/utils/contexts/ThemeContext.js +++ /dev/null @@ -1,80 +0,0 @@ -import React, { createContext, useContext, useEffect, useState } from 'react'; -import { BrowserCache } from '../classes/'; -import { addClassname, removeClassname, supportsSvgAsImg } from '../helpers/'; -import { config as mediacmsConfig } from '../settings/config.js'; -import SiteContext from './SiteContext'; - -const config = mediacmsConfig(window.MediaCMS); - -function initLogo(logo) { - let light = null; - let dark = null; - - if (void 0 !== logo.darkMode) { - if (supportsSvgAsImg() && void 0 !== logo.darkMode.svg && '' !== logo.darkMode.svg) { - dark = logo.darkMode.svg; - } else if (void 0 !== logo.darkMode.img && '' !== logo.darkMode.img) { - dark = logo.darkMode.img; - } - } - - if (void 0 !== logo.lightMode) { - if (supportsSvgAsImg() && void 0 !== logo.lightMode.svg && '' !== logo.lightMode.svg) { - light = logo.lightMode.svg; - } else if (void 0 !== logo.lightMode.img && '' !== logo.lightMode.img) { - light = logo.lightMode.img; - } - } - - if (null !== light || null !== dark) { - if (null === light) { - light = dark; - } else if (null === dark) { - dark = light; - } - } - - return { - light, - dark, - }; -} - -function initMode(cachedValue, defaultValue) { - return 'light' === cachedValue || 'dark' === cachedValue ? cachedValue : defaultValue; -} - -export const ThemeContext = createContext(); - -export const ThemeProvider = ({ children }) => { - const site = useContext(SiteContext); - const cache = new BrowserCache('MediaCMS[' + site.id + '][theme]', 86400); - const [themeMode, setThemeMode] = useState(initMode(cache.get('mode'), config.theme.mode)); - const logos = initLogo(config.theme.logo); - const [logo, setLogo] = useState(logos[themeMode]); - - const changeMode = () => { - setThemeMode('light' === themeMode ? 'dark' : 'light'); - }; - - useEffect(() => { - if ('dark' === themeMode) { - addClassname(document.body, 'dark_theme'); - } else { - removeClassname(document.body, 'dark_theme'); - } - cache.set('mode', themeMode); - setLogo(logos[themeMode]); - }, [themeMode]); - - const value = { - logo, - currentThemeMode: themeMode, - changeThemeMode: changeMode, - themeModeSwitcher: config.theme.switch, - }; - - return {children}; -}; - -export const ThemeConsumer = ThemeContext.Consumer; diff --git a/frontend/src/static/js/utils/contexts/ThemeContext.tsx b/frontend/src/static/js/utils/contexts/ThemeContext.tsx new file mode 100644 index 00000000..949fc122 --- /dev/null +++ b/frontend/src/static/js/utils/contexts/ThemeContext.tsx @@ -0,0 +1,95 @@ +import React, { createContext, ReactNode, useContext, useEffect, useState } from 'react'; +import { GlobalMediaCMS } from '../../types'; +import { BrowserCache } from '../classes'; +import { addClassname, removeClassname, supportsSvgAsImg } from '../helpers'; +import { config as mediacmsConfig } from '../settings/config'; +import SiteContext from './SiteContext'; + +const config = mediacmsConfig(window.MediaCMS); + +function initLogo(logo: GlobalMediaCMS['site']['logo']) { + let light = null; + let dark = null; + + if (void 0 !== logo.darkMode) { + if (supportsSvgAsImg() && void 0 !== logo.darkMode.svg && '' !== logo.darkMode.svg) { + dark = logo.darkMode.svg; + } else if (void 0 !== logo.darkMode.img && '' !== logo.darkMode.img) { + dark = logo.darkMode.img; + } + } + + if (void 0 !== logo.lightMode) { + if (supportsSvgAsImg() && void 0 !== logo.lightMode.svg && '' !== logo.lightMode.svg) { + light = logo.lightMode.svg; + } else if (void 0 !== logo.lightMode.img && '' !== logo.lightMode.img) { + light = logo.lightMode.img; + } + } + + if (null !== light || null !== dark) { + if (null === light) { + light = dark; + } else if (null === dark) { + dark = light; + } + } + + return { + light, + dark, + }; +} + +function initMode(cachedValue: string | undefined, defaultValue: GlobalMediaCMS['site']['theme']['mode']) { + return 'light' === cachedValue || 'dark' === cachedValue ? cachedValue : defaultValue; +} + +export const ThemeContext = createContext({ + logo: initLogo(config.theme.logo)[config.theme.mode], + currentThemeMode: config.theme.mode, + changeThemeMode: () => {}, + themeModeSwitcher: config.theme.switch, +}); + +export const ThemeProvider = ({ children }: { children: ReactNode }) => { + const site = useContext(SiteContext); + + const cache = BrowserCache('MediaCMS[' + site.id + '][theme]', 86400); + + const [themeMode, setThemeMode] = useState( + initMode(cache instanceof Error ? undefined : cache.get('mode'), config.theme.mode) + ); + + const logos = initLogo(config.theme.logo); + const [logo, setLogo] = useState(logos[themeMode]); + + const changeMode = () => { + setThemeMode('light' === themeMode ? 'dark' : 'light'); + }; + + useEffect(() => { + if ('dark' === themeMode) { + addClassname(document.body, 'dark_theme'); + } else { + removeClassname(document.body, 'dark_theme'); + } + + if (!(cache instanceof Error)) { + cache.set('mode', themeMode); + } + + setLogo(logos[themeMode]); + }, [themeMode]); + + const value = { + logo, + currentThemeMode: themeMode, + changeThemeMode: changeMode, + themeModeSwitcher: config.theme.switch, + }; + + return {children}; +}; + +export const ThemeConsumer = ThemeContext.Consumer; diff --git a/frontend/src/static/js/utils/contexts/UserContext.js b/frontend/src/static/js/utils/contexts/UserContext.js deleted file mode 100644 index d6ac143b..00000000 --- a/frontend/src/static/js/utils/contexts/UserContext.js +++ /dev/null @@ -1,22 +0,0 @@ -import React, { createContext } from 'react'; -import { config as mediacmsConfig } from '../settings/config.js'; - -export const UserContext = createContext(); - -const member = mediacmsConfig(window.MediaCMS).member; - -export const UserProvider = ({ children }) => { - const value = { - isAnonymous: member.is.anonymous, - username: member.username, - thumbnail: member.thumbnail, - userCan: member.can, - pages: member.pages, - }; - - return {children}; -}; - -export const UserConsumer = UserContext.Consumer; - -export default UserContext; \ No newline at end of file diff --git a/frontend/src/static/js/utils/contexts/UserContext.tsx b/frontend/src/static/js/utils/contexts/UserContext.tsx new file mode 100644 index 00000000..dd06979f --- /dev/null +++ b/frontend/src/static/js/utils/contexts/UserContext.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { createContext, ReactNode } from 'react'; +import { config as mediacmsConfig } from '../settings/config'; + +const member = mediacmsConfig(window.MediaCMS).member; +export const UserContext = createContext({ + isAnonymous: member.is.anonymous, + username: member.username, + thumbnail: member.thumbnail, + userCan: member.can, + pages: member.pages, +}); + +export function UserProvider({ children }: { children: ReactNode }) { + const value = { + isAnonymous: member.is.anonymous, + username: member.username, + thumbnail: member.thumbnail, + userCan: member.can, + pages: member.pages, + }; + + return {children}; +} + +export const UserConsumer = UserContext.Consumer; + +export default UserContext; diff --git a/frontend/src/static/js/utils/hoc/withBulkActions.jsx b/frontend/src/static/js/utils/hoc/withBulkActions.jsx deleted file mode 100644 index cdcc12bf..00000000 --- a/frontend/src/static/js/utils/hoc/withBulkActions.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import { useBulkActions } from '../hooks/useBulkActions'; - -/** - * Higher-Order Component that provides bulk actions functionality - * to class components via props - */ -export function withBulkActions(WrappedComponent) { - return function WithBulkActionsComponent(props) { - const bulkActions = useBulkActions(); - - return ( - - ); - }; -} diff --git a/frontend/src/static/js/utils/hoc/withBulkActions.tsx b/frontend/src/static/js/utils/hoc/withBulkActions.tsx new file mode 100644 index 00000000..15e13000 --- /dev/null +++ b/frontend/src/static/js/utils/hoc/withBulkActions.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { useBulkActions } from '../hooks/useBulkActions'; + +/** + * Higher-Order Component that provides bulk actions functionality + * to class components via props + */ +export function withBulkActions

}>( + WrappedComponent: React.ComponentType

+) { + return function WithBulkActionsComponent(props: Omit) { + const bulkActions = useBulkActions(); + return ; + }; +} diff --git a/frontend/tests/utils/hooks/useLayout.test.tsx b/frontend/tests/utils/hooks/useLayout.test.tsx index eb18d249..9cc3affc 100644 --- a/frontend/tests/utils/hooks/useLayout.test.tsx +++ b/frontend/tests/utils/hooks/useLayout.test.tsx @@ -18,10 +18,6 @@ jest.mock('../../../src/static/js/utils/classes/', () => ({ })), })); -jest.mock('../../../src/static/js/utils/dispatcher.js', () => ({ - register: jest.fn(), -})); - jest.mock('../../../src/static/js/utils/settings/config', () => ({ config: jest.fn(() => jest.requireActual('../../tests-constants').sampleMediaCMSConfig), })); @@ -54,7 +50,7 @@ describe('utils/hooks', () => { }); }); - test('Returns undefined value when used without a Provider', () => { + test('Returns default context value when used without a Provider', () => { let received: any = 'init'; const Comp: React.FC = () => { @@ -64,7 +60,14 @@ describe('utils/hooks', () => { render(); - expect(received).toBe(undefined); + expect(received).toStrictEqual({ + enabledSidebar: true, + visibleSidebar: true, + visibleMobileSearch: false, + setVisibleSidebar: expect.any(Function), + toggleMobileSearch: expect.any(Function), + toggleSidebar: expect.any(Function), + }); }); test('Toggle sidebar', () => { diff --git a/frontend/tests/utils/hooks/useTheme.test.tsx b/frontend/tests/utils/hooks/useTheme.test.tsx index b3d44065..8f320fa0 100644 --- a/frontend/tests/utils/hooks/useTheme.test.tsx +++ b/frontend/tests/utils/hooks/useTheme.test.tsx @@ -12,10 +12,6 @@ jest.mock('../../../src/static/js/utils/classes/', () => ({ })), })); -jest.mock('../../../src/static/js/utils/dispatcher.js', () => ({ - register: jest.fn(), -})); - function getRenderers(ThemeProvider: React.FC<{ children: React.ReactNode }>, useTheme: typeof useThemeHook) { const data: { current: any } = { current: undefined };