From 564de5e5ccc9ae7a5230d9af016cd9cbaf63584e Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Mon, 21 Nov 2022 15:56:28 +0600 Subject: [PATCH 01/46] fixed swiper version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e79a5ab7..37c66c71 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "react-router-dom": "^5.1.2", "react-sticky-box": "^1.0.2", "sass": "^1.49.0", - "swiper": "^8.0.7", + "swiper": "^8.4.4", "swr": "^1.0.1", "throttle-debounce": "^2.1.0", "typescript": "^4.0.5", From ed9694c246e98c68bf3125f0e10a1c1fa622eac8 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Mon, 21 Nov 2022 15:56:35 +0600 Subject: [PATCH 02/46] fixed theme memoization --- src/utils/providers/ThemeProvider.tsx | 34 +++++++++++++++------------ 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/utils/providers/ThemeProvider.tsx b/src/utils/providers/ThemeProvider.tsx index 68930c3d..6869a8aa 100644 --- a/src/utils/providers/ThemeProvider.tsx +++ b/src/utils/providers/ThemeProvider.tsx @@ -1,6 +1,7 @@ import React, { createContext, FC, + useCallback, useContext, useEffect, useMemo, @@ -23,8 +24,23 @@ const themeClass: Record = { }; const ThemeProvider: FC = ({ children }) => { - const [theme, setTheme] = useState(Theme.Default); - const value = useMemo(() => ({ theme, setTheme }), [theme, setTheme]); + const [theme, setThemeValue] = useState(Theme.Default); + + const setTheme = useCallback( + (val: Theme) => { + if (themeClass[theme]) { + document.documentElement.classList.remove(themeClass[theme]); + } + + localStorage.setItem('vault__theme', val); + setThemeValue(val); + + if (themeClass[val]) { + document.documentElement.classList.add(themeClass[val]); + } + }, + [theme], + ); useEffect(() => { const stored = localStorage.getItem('vault__theme'); @@ -34,19 +50,7 @@ const ThemeProvider: FC = ({ children }) => { setTheme(stored as Theme); }, []); - useEffect(() => { - if (!themeClass[theme]) { - return; - } - - document.documentElement.classList.add(themeClass[theme]); - - try { - localStorage.setItem('vault__theme', theme); - } catch {} - - return () => document.documentElement.classList.remove(themeClass[theme]); - }, [theme]); + const value = useMemo(() => ({ theme, setTheme }), [theme, setTheme]); return ( {children} From 75dc20ca0b5f6737074f11d59a3a591aa6d89d24 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Tue, 22 Nov 2022 10:46:41 +0600 Subject: [PATCH 03/46] fixed user hydration --- .../comment/CommentContent/index.tsx | 75 ++++++++++++++----- .../containers/Authorized/index.tsx | 15 ++-- src/components/flow/FlowGrid/index.tsx | 60 +++++++++------ src/components/menu/SeparatedMenu/index.tsx | 4 +- src/components/node/NodeTitle/index.tsx | 61 ++++++++------- src/containers/main/Header/index.tsx | 12 ++- src/containers/main/Header/styles.module.scss | 10 ++- src/hooks/auth/useAuth.ts | 1 + src/hooks/auth/useUser.ts | 20 +++-- src/hooks/node/useNodePermissions.ts | 18 ++++- src/layouts/NodeLayout/index.tsx | 6 +- src/store/auth/AuthStore.ts | 5 ++ src/utils/providers/AuthProvider.tsx | 2 + 13 files changed, 194 insertions(+), 95 deletions(-) diff --git a/src/components/comment/CommentContent/index.tsx b/src/components/comment/CommentContent/index.tsx index 51c9f96e..17f1eac1 100644 --- a/src/components/comment/CommentContent/index.tsx +++ b/src/components/comment/CommentContent/index.tsx @@ -1,9 +1,19 @@ -import React, { createElement, FC, Fragment, memo, ReactNode, useCallback, useMemo, useState } from 'react'; +import React, { + createElement, + FC, + Fragment, + memo, + ReactNode, + useCallback, + useMemo, + useState, +} from 'react'; import classnames from 'classnames'; import classNames from 'classnames'; import { CommentForm } from '~/components/comment/CommentForm'; +import { Authorized } from '~/components/containers/Authorized'; import { Group } from '~/components/containers/Group'; import { AudioPlayer } from '~/components/media/AudioPlayer'; import { COMMENT_BLOCK_RENDERERS } from '~/constants/comment'; @@ -28,7 +38,15 @@ interface IProps { } const CommentContent: FC = memo( - ({ comment, canEdit, nodeId, saveComment, onDelete, onShowImageModal, prefix }) => { + ({ + comment, + canEdit, + nodeId, + saveComment, + onDelete, + onShowImageModal, + prefix, + }) => { const [isEditing, setIsEditing] = useState(false); const startEditing = useCallback(() => setIsEditing(true), [setIsEditing]); @@ -38,11 +56,13 @@ const CommentContent: FC = memo( () => reduce( (group, file) => - file.type ? assocPath([file.type], append(file, group[file.type]), group) : group, + file.type + ? assocPath([file.type], append(file, group[file.type]), group) + : group, {} as Record, - comment.files + comment.files, ), - [comment] + [comment], ); const onLockClick = useCallback(() => { @@ -50,8 +70,9 @@ const CommentContent: FC = memo( }, [comment, onDelete]); const menu = useMemo( - () => canEdit && , - [canEdit, startEditing, onLockClick] + () => + canEdit && , + [canEdit, startEditing, onLockClick], ); const blocks = useMemo( @@ -59,7 +80,7 @@ const CommentContent: FC = memo( !!comment.text.trim() ? formatCommentText(path(['user', 'username'], comment), comment.text) : [], - [comment] + [comment], ); if (isEditing) { @@ -78,17 +99,22 @@ const CommentContent: FC = memo( {!!prefix &&
{prefix}
} {comment.text.trim() && ( - {menu} + {menu} {blocks.map( (block, key) => COMMENT_BLOCK_RENDERERS[block.type] && - createElement(COMMENT_BLOCK_RENDERERS[block.type], { block, key }) + createElement(COMMENT_BLOCK_RENDERERS[block.type], { + block, + key, + }), )} -
{getPrettyDate(comment.created_at)}
+
+ {getPrettyDate(comment.created_at)} +
)} @@ -102,32 +128,45 @@ const CommentContent: FC = memo( })} > {groupped.image.map((file, index) => ( -
onShowImageModal(groupped.image, index)}> - {file.name} +
onShowImageModal(groupped.image, index)} + > + {file.name}
))}
-
{getPrettyDate(comment.created_at)}
+
+ {getPrettyDate(comment.created_at)} +
)} {groupped.audio && groupped.audio.length > 0 && ( - {groupped.audio.map(file => ( -
+ {groupped.audio.map((file) => ( +
{menu} -
{getPrettyDate(comment.created_at)}
+
+ {getPrettyDate(comment.created_at)} +
))} )}
); - } + }, ); export { CommentContent }; diff --git a/src/components/containers/Authorized/index.tsx b/src/components/containers/Authorized/index.tsx index 739e1ec8..d38a9ea6 100644 --- a/src/components/containers/Authorized/index.tsx +++ b/src/components/containers/Authorized/index.tsx @@ -1,15 +1,20 @@ import React, { FC } from 'react'; +import { observer } from 'mobx-react-lite'; + import { useAuth } from '~/hooks/auth/useAuth'; -interface IProps {} +interface IProps { + // don't wait for user refetch, trust hydration + hydratedOnly?: boolean; +} -const Authorized: FC = ({ children }) => { - const { isUser } = useAuth(); +const Authorized: FC = observer(({ children, hydratedOnly }) => { + const { isUser, fetched } = useAuth(); - if (!isUser) return null; + if (!isUser || (!hydratedOnly && !fetched)) return null; return <>{children}; -}; +}); export { Authorized }; diff --git a/src/components/flow/FlowGrid/index.tsx b/src/components/flow/FlowGrid/index.tsx index 3d451b54..5aac50b5 100644 --- a/src/components/flow/FlowGrid/index.tsx +++ b/src/components/flow/FlowGrid/index.tsx @@ -1,9 +1,11 @@ import React, { FC, Fragment } from 'react'; import classNames from 'classnames'; +import { observer } from 'mobx-react-lite'; import { FlowCell } from '~/components/flow/FlowCell'; import { flowDisplayToPreset, URLS } from '~/constants/urls'; +import { useAuth } from '~/hooks/auth/useAuth'; import { FlowDisplay, IFlowNode, INode } from '~/types'; import { IUser } from '~/types/auth'; import { getURLFromString } from '~/utils/dom'; @@ -17,28 +19,38 @@ interface Props { onChangeCellView: (id: INode['id'], flow: FlowDisplay) => void; } -export const FlowGrid: FC = ({ user, nodes, onChangeCellView }) => { - if (!nodes) { - return null; - } +export const FlowGrid: FC = observer( + ({ user, nodes, onChangeCellView }) => { + const { fetched, isUser } = useAuth(); - return ( - - {nodes.map(node => ( -
- -
- ))} -
- ); -}; + if (!nodes) { + return null; + } + + return ( + + {nodes.map((node) => ( +
+ +
+ ))} +
+ ); + }, +); diff --git a/src/components/menu/SeparatedMenu/index.tsx b/src/components/menu/SeparatedMenu/index.tsx index 19a4c9e3..c030220b 100644 --- a/src/components/menu/SeparatedMenu/index.tsx +++ b/src/components/menu/SeparatedMenu/index.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames'; import styles from './styles.module.scss'; -interface SeparatedMenuProps { +export interface SeparatedMenuProps { className?: string; } @@ -14,7 +14,7 @@ const SeparatedMenu: FC = ({ children, className }) => { return []; } - return (Array.isArray(children) ? children : [children]).filter(it => it); + return (Array.isArray(children) ? children : [children]).filter((it) => it); }, [children]); return ( diff --git a/src/components/node/NodeTitle/index.tsx b/src/components/node/NodeTitle/index.tsx index d33a4bab..99ae85ae 100644 --- a/src/components/node/NodeTitle/index.tsx +++ b/src/components/node/NodeTitle/index.tsx @@ -2,6 +2,7 @@ import React, { memo, VFC } from 'react'; import classNames from 'classnames'; +import { Authorized } from '~/components/containers/Authorized'; import { Icon } from '~/components/input/Icon'; import { SeparatedMenu } from '~/components/menu/SeparatedMenu'; import { NodeEditMenu } from '~/components/node/NodeEditMenu'; @@ -76,37 +77,39 @@ const NodeTitle: VFC = memo( )} - - {canEdit && ( - - )} + + + {canEdit && ( + + )} - {canLike && ( -
- {isLiked ? ( - - ) : ( - - )} + {canLike && ( +
+ {isLiked ? ( + + ) : ( + + )} - {!!likeCount && likeCount > 0 && ( -
{likeCount}
- )} -
- )} - + {!!likeCount && likeCount > 0 && ( +
{likeCount}
+ )} +
+ )} +
+
); diff --git a/src/containers/main/Header/index.tsx b/src/containers/main/Header/index.tsx index 893737d3..113409f3 100644 --- a/src/containers/main/Header/index.tsx +++ b/src/containers/main/Header/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import classNames from 'classnames'; import isBefore from 'date-fns/isBefore'; @@ -16,7 +16,6 @@ import { URLS } from '~/constants/urls'; import { useAuth } from '~/hooks/auth/useAuth'; import { useScrollTop } from '~/hooks/dom/useScrollTop'; import { useFlow } from '~/hooks/flow/useFlow'; -import { useGetLabStats } from '~/hooks/lab/useGetLabStats'; import { useModal } from '~/hooks/modal/useModal'; import { useUpdates } from '~/hooks/updates/useUpdates'; import { useSidebar } from '~/utils/providers/SidebarProvider'; @@ -66,8 +65,13 @@ const Header: FC = observer(() => { -