Feat global state (#861)

* add zustand, add auth store

* add user config store, isAdmin from store

* move ColourVariants, fix importColours

* get userConfig from store

* fix name conflict

* home filter bar from config store

* use user store for channel list

* use userConfig store for channel pages

* use userConfig for playlist pages

* fix channel video type navigation

* use userConfig update on downloads page

* fix view style in search

* handle initial user config, take 2

* modify userSettings in global state
This commit is contained in:
Simon
2025-01-06 19:44:05 +07:00
committed by GitHub
parent 0eca242fd6
commit c9607343e6
31 changed files with 443 additions and 721 deletions

View File

@@ -1,14 +1,11 @@
import { useEffect, useState } from 'react';
import {
Link,
useLoaderData,
useOutletContext,
useParams,
useSearchParams,
} from 'react-router-dom';
import { SortByType, SortOrderType, ViewLayoutType } from './Home';
import { OutletContextType } from './Base';
import { UserMeType } from '../api/actions/updateUserConfig';
import VideoList from '../components/VideoList';
import Routes from '../configuration/routes/RouteList';
import Pagination from '../components/Pagination';
@@ -27,33 +24,23 @@ import loadVideoListByFilter, {
} from '../api/loader/loadVideoListByPage';
import loadChannelAggs, { ChannelAggsType } from '../api/loader/loadChannelAggs';
import humanFileSize from '../functions/humanFileSize';
import { useUserConfigStore } from '../stores/UserConfigStore';
type ChannelParams = {
channelId: string;
};
type ChannelVideoLoaderType = {
userConfig: UserMeType;
};
type ChannelVideoProps = {
videoType: VideoTypes;
};
const ChannelVideo = ({ videoType }: ChannelVideoProps) => {
const { channelId } = useParams() as ChannelParams;
const { userConfig } = useLoaderData() as ChannelVideoLoaderType;
const { isAdmin, currentPage, setCurrentPage } = useOutletContext() as OutletContextType;
const { userConfig } = useUserConfigStore();
const { currentPage, setCurrentPage } = useOutletContext() as OutletContextType;
const [searchParams] = useSearchParams();
const videoId = searchParams.get('videoId');
const userMeConfig = userConfig.config;
const [hideWatched, setHideWatched] = useState(userMeConfig.hide_watched || false);
const [sortBy, setSortBy] = useState<SortByType>(userMeConfig.sort_by || 'published');
const [sortOrder, setSortOrder] = useState<SortOrderType>(userMeConfig.sort_order || 'asc');
const [view, setView] = useState<ViewLayoutType>(userMeConfig.view_style_home || 'grid');
const [gridItems, setGridItems] = useState(userMeConfig.grid_items || 3);
const [refresh, setRefresh] = useState(false);
const [channelResponse, setChannelResponse] = useState<ChannelResponseType>();
@@ -67,37 +54,40 @@ const ChannelVideo = ({ videoType }: ChannelVideoProps) => {
const hasVideos = videoResponse?.data?.length !== 0;
const showEmbeddedVideo = videoId !== null;
const view = userConfig.config.view_style_home
const isGridView = view === ViewStyles.grid;
const gridView = isGridView ? `boxed-${gridItems}` : '';
const gridViewGrid = isGridView ? `grid-${gridItems}` : '';
const gridView = isGridView ? `boxed-${userConfig.config.grid_items}` : '';
const gridViewGrid = isGridView ? `grid-${userConfig.config.grid_items}` : '';
useEffect(() => {
(async () => {
if (
refresh ||
pagination?.current_page === undefined ||
currentPage !== pagination?.current_page
) {
const channelResponse = await loadChannelById(channelId);
const videos = await loadVideoListByFilter({
channel: channelId,
page: currentPage,
watch: hideWatched ? 'unwatched' : undefined,
sort: sortBy,
order: sortOrder,
type: videoType,
});
const channelAggs = await loadChannelAggs(channelId);
const channelResponse = await loadChannelById(channelId);
const videos = await loadVideoListByFilter({
channel: channelId,
page: currentPage,
watch: userConfig.config.hide_watched ? 'unwatched' : undefined,
sort: userConfig.config.sort_by,
order: userConfig.config.sort_order,
type: videoType,
});
const channelAggs = await loadChannelAggs(channelId);
setChannelResponse(channelResponse);
setVideoReponse(videos);
setVideoAggsResponse(channelAggs);
setRefresh(false);
}
setChannelResponse(channelResponse);
setVideoReponse(videos);
setVideoAggsResponse(channelAggs);
setRefresh(false);
})();
// Do not add sort, order, hideWatched this will not work as expected!
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [refresh, currentPage, channelId, pagination?.current_page]);
}, [
refresh,
userConfig.config.sort_by,
userConfig.config.sort_order,
userConfig.config.hide_watched,
currentPage,
channelId,
pagination?.current_page,
videoType,
]);
if (!channel) {
return (
@@ -121,7 +111,6 @@ const ChannelVideo = ({ videoType }: ChannelVideoProps) => {
channelSubscribed={channel.channel_subscribed}
channelThumbUrl={channel.channel_thumb_url}
showSubscribeButton={true}
isUserAdmin={isAdmin}
setRefresh={setRefresh}
/>
<div className="info-box-item">
@@ -172,18 +161,6 @@ const ChannelVideo = ({ videoType }: ChannelVideoProps) => {
<div className={`boxed-content ${gridView}`}>
<Filterbar
hideToggleText={'Hide watched videos:'}
view={view}
isGridView={isGridView}
hideWatched={hideWatched}
gridItems={gridItems}
sortBy={sortBy}
sortOrder={sortOrder}
userMeConfig={userMeConfig}
setSortBy={setSortBy}
setSortOrder={setSortOrder}
setHideWatched={setHideWatched}
setView={setView}
setGridItems={setGridItems}
viewStyleName={ViewStyleNames.home}
setRefresh={setRefresh}
/>