init
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { useCallback } from 'react';
|
||||
import { sessionStorageGet, sessionStorageDelete } from '@/utils/sessionStorage';
|
||||
import { useAppStore } from '../store';
|
||||
|
||||
/**
|
||||
* Hook to detect is current user authenticated or not
|
||||
* @returns {boolean} true if user is authenticated, false otherwise
|
||||
*/
|
||||
export function useIsAuthenticated() {
|
||||
const [state] = useAppStore();
|
||||
let result = state.isAuthenticated;
|
||||
|
||||
// TODO: AUTH: replace next line with access token verification
|
||||
result = Boolean(sessionStorageGet('access_token', ''));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns event handler to Logout current user
|
||||
* @returns {function} calling this event logs out current user
|
||||
*/
|
||||
export function useEventLogout() {
|
||||
const [, dispatch] = useAppStore();
|
||||
|
||||
return useCallback(() => {
|
||||
// TODO: AUTH: replace next line with access token saving
|
||||
sessionStorageDelete('access_token');
|
||||
|
||||
dispatch({ type: 'LOG_OUT' });
|
||||
}, [dispatch]);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useAppStore } from '../store';
|
||||
|
||||
/**
|
||||
* Returns event handler to toggle Dark/Light modes
|
||||
* @returns {function} calling this event toggles dark/light mode
|
||||
*/
|
||||
export function useEventSwitchDarkMode() {
|
||||
const [state, dispatch] = useAppStore();
|
||||
|
||||
return useCallback(() => {
|
||||
dispatch({
|
||||
type: 'DARK_MODE',
|
||||
payload: !state.darkMode,
|
||||
});
|
||||
}, [state, dispatch]);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './auth';
|
||||
export * from './event';
|
||||
export * from './layout';
|
||||
@@ -0,0 +1,76 @@
|
||||
'use client';
|
||||
import { useEffect, useState } from 'react';
|
||||
import useWindowsSize from './useWindowSize';
|
||||
import { useMediaQuery, useTheme } from '@mui/material';
|
||||
import { IS_SERVER } from '@/utils';
|
||||
|
||||
export const MOBILE_SCREEN_MAX_WIDTH = 600; // Sync with https://mui.com/material-ui/customization/breakpoints/
|
||||
export const SERVER_SIDE_MOBILE_FIRST = true; // true - for mobile, false - for desktop
|
||||
|
||||
/**
|
||||
* Hook to detect onMobile vs. onDesktop using "resize" event listener
|
||||
* @returns {boolean} true when on onMobile, false when on onDesktop
|
||||
*/
|
||||
export function useIsMobileByWindowsResizing() {
|
||||
const theme = useTheme();
|
||||
const { width } = useWindowsSize();
|
||||
const onMobile = width <= theme.breakpoints?.values?.sm ?? MOBILE_SCREEN_MAX_WIDTH;
|
||||
return onMobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to detect onMobile vs. onDesktop using Media Query
|
||||
* @returns {boolean} true when on onMobile, false when on onDesktop
|
||||
*/
|
||||
function useIsMobileByMediaQuery() {
|
||||
// const onMobile = useMediaQuery({ maxWidth: MOBILE_SCREEN_MAX_WIDTH });
|
||||
const theme = useTheme();
|
||||
const onMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
return onMobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to detect onMobile vs. onDesktop with Next.js workaround
|
||||
* @returns {boolean} true when on onMobile, false when on onDesktop
|
||||
*/
|
||||
function useIsMobileForNextJs() {
|
||||
// const onMobile = useOnMobileByWindowsResizing();
|
||||
const onMobile = useIsMobileByMediaQuery();
|
||||
const [onMobileDelayed, setOnMobileDelayed] = useState(SERVER_SIDE_MOBILE_FIRST);
|
||||
|
||||
useEffect(() => {
|
||||
setOnMobileDelayed(onMobile); // Next.js don't allow to use useOnMobileXxx() directly, so we need to use this workaround
|
||||
}, [onMobile]);
|
||||
|
||||
return onMobileDelayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to apply "onMobile" vs. "onDesktop" class to document.body depending on screen size.
|
||||
* Due to SSR/SSG we can not set 'app-layout onMobile' or 'app-layout onDesktop' on the server
|
||||
* If we modify className using JS, we will got Warning: Prop `className` did not match. Server: "app-layout" Client: "app-layout onDesktop"
|
||||
* So we have to apply document.body.class using the hook :)
|
||||
* Note: Use this hook one time only! In main App or Layout component
|
||||
*/
|
||||
function useMobileOrDesktopByChangingBodyClass() {
|
||||
// const onMobile = useOnMobileByWindowsResizing();
|
||||
const onMobile = useIsMobileByMediaQuery();
|
||||
|
||||
useEffect(() => {
|
||||
if (onMobile) {
|
||||
document.body.classList.remove('onDesktop');
|
||||
document.body.classList.add('onMobile');
|
||||
} else {
|
||||
document.body.classList.remove('onMobile');
|
||||
document.body.classList.add('onDesktop');
|
||||
}
|
||||
}, [onMobile]);
|
||||
}
|
||||
|
||||
/**
|
||||
* We need a "smart export wrappers", because we can not use hooks on the server side
|
||||
*/
|
||||
// export const useOnMobile = IS_SERVER ? () => SERVER_SIDE_IS_MOBILE_VALUE : useOnMobileByWindowsResizing;
|
||||
// export const useOnMobile = IS_SERVER ? () => SERVER_SIDE_IS_MOBILE_VALUE : useOnMobileByMediaQuery;
|
||||
export const useIsMobile = IS_SERVER ? () => SERVER_SIDE_MOBILE_FIRST : useIsMobileForNextJs;
|
||||
export const useBodyClassForMobileOrDesktop = IS_SERVER ? () => undefined : useMobileOrDesktopByChangingBodyClass;
|
||||
@@ -0,0 +1,40 @@
|
||||
import { useLayoutEffect, useState } from 'react';
|
||||
import { IS_SERVER } from '@/utils';
|
||||
|
||||
const MOBILE_WINDOWS_SIZE = { width: 720, height: 1280 };
|
||||
const DESKTOP_WINDOWS_SIZE = { width: 1920, height: 1080 };
|
||||
const DEFAULT_WINDOWS_SIZE = MOBILE_WINDOWS_SIZE ?? DESKTOP_WINDOWS_SIZE; // Mobile-First by default
|
||||
|
||||
type WindowSize = {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to monitor Window (actually Browser) Size using "resize" event listener
|
||||
* @returns {WindowSize} current window size as {width, height} object
|
||||
*/
|
||||
const useWindowSize = (): WindowSize => {
|
||||
const [windowSize, setWindowSize] = useState<WindowSize>(DEFAULT_WINDOWS_SIZE);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
function handleResize() {
|
||||
setWindowSize({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('resize', handleResize);
|
||||
handleResize(); // Get initial/current window size
|
||||
|
||||
return () => window.removeEventListener('resize', handleResize);
|
||||
}, []);
|
||||
|
||||
return windowSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* The hook will really work in Browser only, so or Server Side Rendering (SSR) we just return DEFAULT_WINDOWS_SIZE
|
||||
*/
|
||||
export default IS_SERVER ? () => DEFAULT_WINDOWS_SIZE : useWindowSize;
|
||||
Reference in New Issue
Block a user