Skip to content

Commit

Permalink
Decrease zustand usage (#28)
Browse files Browse the repository at this point in the history
* ew

* ew, changing direction gonna keep ~some~ of zustand

* good enough
  • Loading branch information
aaronleopold authored Jul 26, 2022
1 parent 5ddaebf commit f309c15
Show file tree
Hide file tree
Showing 17 changed files with 199 additions and 205 deletions.
21 changes: 2 additions & 19 deletions apps/client/src/components/Layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,20 @@
import React, { useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Navigate, Outlet, useLocation } from 'react-router-dom';
import { getLibraries } from '~api/library';
import Lazy from '~components/Lazy';
import Topbar from '~components/Topbar';
import Sidebar from '~components/Sidebar/Sidebar';
import { useStore } from '~store/store';

import { Box, Flex, useColorModeValue } from '@chakra-ui/react';
import { AxiosError } from 'axios';
import client from '~api/client';
import { useUser } from '~hooks/useUser';
import { useLibraries } from '~hooks/useLibraries';

export default function MainLayout() {
const location = useLocation();

const setLibraries = useStore((state) => state.setLibraries);

const _user = useUser();

const { isLoading, error } = useQuery(['getLibraries'], getLibraries, {
onSuccess(res) {
setLibraries(res.data.data);
},
onError(err: AxiosError) {
// 401 errors will be handled below
if (err.response?.status !== 401) {
throw new Error(err.message);
}
},
// Send all non-401 errors to the error page
useErrorBoundary: (err: AxiosError) => !err || (err.response?.status ?? 500) !== 401,
});
const { isLoading, error } = useLibraries();

const hideSidebar = useMemo(() => {
// hide sidebar when on /books/:id/pages/:page or /epub/
Expand Down
4 changes: 3 additions & 1 deletion apps/client/src/components/Library/LibraryModalForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import TextArea from '~ui/TextArea';
import { TagOption } from '~hooks/useTags';
import { useStore } from '~store/store';
import { Library } from '@stump/core';
import { useLibraries } from '~hooks/useLibraries';

interface Props {
tags: TagOption[];
Expand All @@ -37,7 +38,8 @@ interface Props {
* It is not intended to be used outside of those components.
*/
export default function LibraryModalForm({ tags, onSubmit, fetchingTags, reset, library }: Props) {
const libraries = useStore((state) => state.libraries);
// const libraries = useStore((state) => state.libraries);
const { libraries } = useLibraries();

const schema = z.object({
name: z
Expand Down
2 changes: 1 addition & 1 deletion apps/client/src/components/Library/LibraryOptionsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface Props {
}

export default function LibraryOptionsMenu({ library }: Props) {
const user = useUser();
const { user } = useUser();

const { mutate: scan } = useMutation(['scanLibary'], { mutationFn: scanLibary });

Expand Down
3 changes: 3 additions & 0 deletions apps/client/src/components/Media/LazyEpubReader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ export default function LazyEpubReader({ id, loc }: LazyEpubReaderProps) {
setBook(
new Book(`${baseURL}/media/${id}/file`, {
openAs: 'epub',
// @ts-ignore: more incorrect types >:( I really truly cannot stress enough how much I want to just
// rip out my eyes working with epubjs...
requestCredentials: true,
}),
);
}
Expand Down
13 changes: 7 additions & 6 deletions apps/client/src/components/Settings/General/ProfileForm.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React from 'react';
import { FormControl, FormLabel } from '@chakra-ui/react';
import { zodResolver } from '@hookform/resolvers/zod';
import { FieldValues, useForm } from 'react-hook-form';
import { z } from 'zod';
import { useLocale } from '~hooks/useLocale';
import { useUser } from '~hooks/useUser';
import Button from '~ui/Button';
import Form from '~ui/Form';
import Input, { PasswordInput } from '~ui/Input';
import { useLocale } from '~hooks/useLocale';
import { useUser } from '~hooks/useUser';

import { FormControl, FormLabel } from '@chakra-ui/react';
import { zodResolver } from '@hookform/resolvers/zod';

import SettingsFormContainer from '../SettingsFormContainer';

export default function ProfileForm() {
const user = useUser();
const { user } = useUser();
const { t } = useLocale();

if (!user) {
Expand Down
7 changes: 3 additions & 4 deletions apps/client/src/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import CreateLibraryModal from '~components/Library/CreateLibraryModal';
import Logout from './Logout';
import { useLocale } from '~hooks/useLocale';
import { Library } from '@stump/core';
import { useLibraries } from '~hooks/useLibraries';

interface NavMenuItemProps extends Library {
href: string;
Expand Down Expand Up @@ -127,17 +128,15 @@ export function SidebarContent() {

const { locale, t } = useLocale();

const libraries = useStore((state) => state.libraries, shallow);

// console.log('libraries', libraries);
const { libraries } = useLibraries();

const links: Array<NavItemProps> = useMemo(
() => [
{ name: t('sidebar.buttons.home'), icon: House as any, href: '/' },
{
name: t('sidebar.buttons.libraries'),
icon: Books as any,
items: libraries.map((library) => ({
items: libraries?.map((library) => ({
...library,
href: `/libraries/${library.id}`,
})),
Expand Down
7 changes: 4 additions & 3 deletions apps/client/src/components/Topbar/SortConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { SortAscending, SortDescending } from 'phosphor-react';
import { useState } from 'react';
import Button from '~ui/Button';

import {
ButtonGroup,
Menu,
Expand All @@ -6,9 +10,6 @@ import {
MenuList,
useColorModeValue,
} from '@chakra-ui/react';
import { SortAscending, SortDescending } from 'phosphor-react';
import React, { useState } from 'react';
import Button from '~ui/Button';

interface SortConfigProps {}

Expand Down
31 changes: 31 additions & 0 deletions apps/client/src/hooks/useLibraries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Library, PageInfo } from '@stump/core';
import { useQuery } from '@tanstack/react-query';
import { AxiosError } from 'axios';
import { useMemo } from 'react';
import { getLibraries } from '~api/library';

export function useLibraries() {
const { data, ...rest } = useQuery(['getLibraries'], getLibraries, {
// Send all non-401 errors to the error page
useErrorBoundary: (err: AxiosError) => !err || (err.response?.status ?? 500) !== 401,
});

const { libraries, pageData } = useMemo<{ libraries: Library[]; pageData?: PageInfo }>(() => {
if (data?.data) {
return {
libraries: data.data.data,
pageData: data.data._page,
};
}

return { libraries: [] };
}, [data]);

console.log({ libraries });

return {
libraries,
pageData,
...rest,
};
}
23 changes: 16 additions & 7 deletions apps/client/src/hooks/useLocale.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import '~i18n/config';
import { useTranslation } from 'react-i18next';
import { useStore } from '~store/store';
import shallow from 'zustand/shallow';
import { Locale } from '~util/enums';
import { useUser } from './useUser';

// FIXME: When a user logs out, their locale should be persisted. Right now,
// user.preferences doesn't exist in a logged out state. I think what I should maybe do
// instead of clearing it on logout is set an auth state to false or something? this way,
// preferences remain (mainly for locale) and shows correct language on login.
// Alternatively, I can be lazy and just persist a separate locale state. ~shrug~
export function useLocale() {
const userPreferences = useStore((state) => state.userPreferences, shallow);
const setLocale = useStore((state) => state.setLocale);
const { preferences, updatePreferences } = useUser();

function setLocaleFromStr(localeStr: string) {
let locale = localeStr as Locale;

if (locale) {
setLocale(locale);
if (preferences && locale) {
updatePreferences({ ...preferences, locale });
}
}

const locale: string = userPreferences?.locale || 'en';
function setLocale(locale: Locale) {
if (preferences && locale) {
updatePreferences({ ...preferences, locale });
}
}

const locale: string = preferences?.locale || 'en';

const { t } = useTranslation(locale);

Expand Down
18 changes: 0 additions & 18 deletions apps/client/src/hooks/usePreferences.ts

This file was deleted.

40 changes: 37 additions & 3 deletions apps/client/src/hooks/useUser.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { useQuery } from '@tanstack/react-query';
import toast from 'react-hot-toast';
import shallow from 'zustand/shallow';
import { me } from '~api/auth';
import { updateUserPreferences } from '~api/user';
import { useStore } from '~store/store';

import { UserPreferences } from '@stump/core';
import { useMutation, useQuery } from '@tanstack/react-query';

export function useUser() {
const user = useStore((state) => state.user, shallow);

const { setUser } = useStore((state) => ({ setUser: state.setUserAndPreferences }));
const { setUser, setUserPreferences } = useStore((state) => ({
setUser: state.setUser,
setUserPreferences: state.setUserPreferences,
}));

const _ = useQuery(['getViewer'], me, {
// Do not run query unless there is no user in the store
Expand All @@ -18,7 +25,34 @@ export function useUser() {
},
});

const { mutateAsync } = useMutation(
['updateUserPreferences', user?.id],
(preferences: UserPreferences) => updateUserPreferences(user!.id, preferences),
{
onSuccess(res) {
setUserPreferences(res.data);
},
},
);

function updatePreferences(preferences: UserPreferences, showToast = false) {
if (user?.id && preferences) {
if (showToast) {
toast.promise(mutateAsync(preferences), {
loading: 'Updating...',
success: 'Preferences updated!',
error: 'Failed to update preferences.',
});
} else {
mutateAsync(preferences).catch((err) => {
console.error(err);
toast.error('Failed to update preferences.');
});
}
}
}

// TODO: handle on 401?

return user;
return { user, preferences: user?.preferences, updatePreferences };
}
38 changes: 27 additions & 11 deletions apps/client/src/hooks/useViewMode.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
import { ViewMode } from '@stump/core';
import { useMemo } from 'react';
import { useLocation } from 'react-router-dom';
import shallow from 'zustand/shallow';
import { useStore } from '~store/store';
import { useUser } from './useUser';

export function useViewMode() {
const location = useLocation();

const { userPreferences, setLibraryViewMode, setSeriesViewMode } = useStore(
({ userPreferences, setLibraryViewMode, setSeriesViewMode }) => ({
userPreferences,
setLibraryViewMode,
setSeriesViewMode,
}),
shallow,
);
const { preferences, updatePreferences } = useUser();

function setLibraryViewMode(viewMode: ViewMode) {
if (preferences) {
updatePreferences({ ...preferences, libraryViewMode: viewMode });
}
}

function setSeriesViewMode(viewMode: ViewMode) {
if (preferences) {
updatePreferences({ ...preferences, seriesViewMode: viewMode });
}
}

// const { userPreferences, setLibraryViewMode, setSeriesViewMode } = useStore(
// ({ userPreferences, setLibraryViewMode, setSeriesViewMode }) => ({
// userPreferences,
// setLibraryViewMode,
// setSeriesViewMode,
// }),
// shallow,
// );

const { showViewOptions, viewAsGrid, onViewModeChange } = useMemo(() => {
let _showViewOptions =
Expand All @@ -29,10 +45,10 @@ export function useViewMode() {
let _onViewModeChange;

if (location.pathname.match(/\/libraries\/.+$/)) {
_viewAsGrid = userPreferences?.libraryViewMode === 'GRID';
_viewAsGrid = preferences?.libraryViewMode === 'GRID';
_onViewModeChange = setLibraryViewMode;
} else if (location.pathname.match(/\/series\/.+$/)) {
_viewAsGrid = userPreferences?.seriesViewMode === 'GRID';
_viewAsGrid = preferences?.seriesViewMode === 'GRID';
_onViewModeChange = setSeriesViewMode;
}

Expand All @@ -48,7 +64,7 @@ export function useViewMode() {
viewAsGrid: _viewAsGrid,
onViewModeChange: _onViewModeChange,
};
}, [location.pathname, userPreferences]);
}, [location.pathname, preferences]);

return { showViewOptions, viewAsGrid, onViewModeChange };
}
9 changes: 3 additions & 6 deletions apps/client/src/pages/Auth/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { FieldValues, useForm } from 'react-hook-form';
import { Navigate } from 'react-router-dom';
import { z } from 'zod';
Expand Down Expand Up @@ -46,10 +46,7 @@ export default function Login() {
}
}, [claimCheck]);

const { user, setUserAndPreferences } = useStore(
({ user, setUserAndPreferences }) => ({ user, setUserAndPreferences }),
shallow,
);
const { user, setUser } = useStore(({ user, setUser }) => ({ user, setUser }), shallow);

const { isLoading: isLoggingIn, mutateAsync: loginUser } = useMutation(['loginUser'], {
mutationFn: login,
Expand All @@ -60,7 +57,7 @@ export default function Login() {

client.invalidateQueries(['getLibraries']);

setUserAndPreferences(res.data);
setUser(res.data);
},
onError: (err) => {
// TODO: handle this error
Expand Down
Loading

0 comments on commit f309c15

Please sign in to comment.