Browse Source

Final updates to new Q-Tube 2.0 release

settingsSlice.ts renamed to persistentSlice, it is only used to store persistent data.

reset button no longer changes video type from "playlist" to "video".

Subscriptions are now stored as list of objects that have the name of the user and the name of the channel that is followed.

When the application starts in App.tsx the subscription list is filtered by the user's name, so they only see channels by the name they have subscribed to.

Edits to QuickMythril's bounty commits (showing home page stats and publish video form displaying supported codecs) to improve visibility and readability.
pull/18/head
Qortal Dev 7 months ago
parent
commit
1a4dc8375b
  1. 2
      package.json
  2. 48
      src/App.tsx
  3. 29
      src/components/PublishVideo/PublishVideo-styles.tsx
  4. 27
      src/components/PublishVideo/PublishVideo.tsx
  5. 44
      src/components/common/SubscribeButton.tsx
  6. 32
      src/hooks/useFetchVideos.tsx
  7. 18
      src/main.tsx
  8. 73
      src/pages/Home/Home.tsx
  9. 10
      src/pages/Home/VideoList-styles.tsx
  10. 75
      src/pages/IndividualProfile/IndividualProfile.tsx
  11. 2
      src/pages/PlaylistContent/PlaylistContent.tsx
  12. 5
      src/pages/VideoContent/VideoContent.tsx
  13. 34
      src/state/features/persistSlice.ts
  14. 11
      src/state/features/videoSlice.ts
  15. 4
      src/state/store.ts

2
package.json

@ -1,7 +1,7 @@
{
"name": "qtube",
"private": true,
"version": "0.0.0",
"version": "2.0.0",
"type": "module",
"scripts": {
"dev": "vite",

48
src/App.tsx

@ -1,8 +1,8 @@
import { useState } from "react";
import { Routes, Route } from "react-router-dom";
import { useEffect, useState } from "react";
import { Route, Routes } from "react-router-dom";
import { ThemeProvider } from "@mui/material/styles";
import { CssBaseline } from "@mui/material";
import { lightTheme, darkTheme } from "./styles/theme";
import { darkTheme, lightTheme } from "./styles/theme";
import { store } from "./state/store";
import { Provider } from "react-redux";
import GlobalWrapper from "./wrappers/GlobalWrapper";
@ -14,6 +14,8 @@ import { IndividualProfile } from "./pages/IndividualProfile/IndividualProfile";
import { PlaylistContent } from "./pages/PlaylistContent/PlaylistContent";
import { PersistGate } from "redux-persist/integration/react";
import { persistStore } from "redux-persist";
import { setFilteredSubscriptions } from "./state/features/videoSlice.ts";
import { SubscriptionObject } from "./state/features/persistSlice.ts";
function App() {
// const themeColor = window._qdnTheme
@ -21,6 +23,46 @@ function App() {
const [theme, setTheme] = useState("dark");
let persistor = persistStore(store);
const filterVideosByName = (
subscriptionList: SubscriptionObject[],
userName: string
) => {
return subscriptionList.filter(item => {
return item.userName === userName;
});
};
const getUserName = async () => {
const account = await qortalRequest({
action: "GET_USER_ACCOUNT",
});
const nameData = await qortalRequest({
action: "GET_ACCOUNT_NAMES",
address: account.address,
});
if (nameData?.length > 0) return nameData[0].name;
else return "";
};
const subscriptionListFilter = async () => {
const subscriptionList = store.getState().persist.subscriptionList;
const filterByUserName =
store.getState().persist.subscriptionListFilter === "currentNameOnly";
const userName = await getUserName();
if (filterByUserName && userName) {
return filterVideosByName(subscriptionList, userName);
} else return subscriptionList;
};
useEffect(() => {
const subscriptionList = store.getState().persist.subscriptionList;
subscriptionListFilter().then(filteredList => {
store.dispatch(setFilteredSubscriptions(filteredList));
});
}, []);
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>

29
src/components/PublishVideo/PublishVideo-styles.tsx

@ -9,7 +9,7 @@ import {
Rating,
TextField,
Typography,
Select
Select,
} from "@mui/material";
import AddPhotoAlternateIcon from "@mui/icons-material/AddPhotoAlternate";
import { TimesSVG } from "../../assets/svgs/TimesSVG";
@ -51,6 +51,9 @@ export const CreateContainer = styled(Box)(({ theme }) => ({
borderRadius: "50%",
}));
export const CodecTypography = styled(Typography)(({ theme }) => ({
fontSize: "18px",
}));
export const ModalBody = styled(Box)(({ theme }) => ({
position: "absolute",
backgroundColor: theme.palette.background.default,
@ -159,8 +162,6 @@ export const CustomInputField = styled(TextField)(({ theme }) => ({
},
}));
export const CrowdfundTitle = styled(Typography)(({ theme }) => ({
fontFamily: "Copse",
letterSpacing: "1px",
@ -539,8 +540,8 @@ export const NoReviewsFont = styled(Typography)(({ theme }) => ({
export const StyledButton = styled(Button)(({ theme }) => ({
fontWeight: 600,
color: theme.palette.text.primary
}))
color: theme.palette.text.primary,
}));
export const CustomSelect = styled(Select)(({ theme }) => ({
fontFamily: "Mulish",
@ -549,34 +550,34 @@ export const CustomSelect = styled(Select)(({ theme }) => ({
fontWeight: 400,
color: theme.palette.text.primary,
backgroundColor: theme.palette.background.default,
'& .MuiSelect-select': {
padding: '12px',
"& .MuiSelect-select": {
padding: "12px",
fontFamily: "Mulish",
fontSize: "19px",
letterSpacing: "0px",
fontWeight: 400,
borderRadius: theme.shape.borderRadius, // Match border radius
},
'&:before': {
"&:before": {
// Underline style
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
},
'&:after': {
"&:after": {
// Underline style when focused
borderBottomColor: theme.palette.secondary.main,
},
'& .MuiOutlinedInput-root': {
'& fieldset': {
"& .MuiOutlinedInput-root": {
"& fieldset": {
borderColor: "#E0E3E7",
},
'&:hover fieldset': {
"&:hover fieldset": {
borderColor: "#B2BAC2",
},
'&.Mui-focused fieldset': {
"&.Mui-focused fieldset": {
borderColor: "#6F7E8C",
},
},
'& .MuiInputBase-root': {
"& .MuiInputBase-root": {
fontFamily: "Mulish",
fontSize: "19px",
letterSpacing: "0px",

27
src/components/PublishVideo/PublishVideo.tsx

@ -3,6 +3,7 @@ import Compressor from "compressorjs";
import {
AddCoverImageButton,
AddLogoIcon,
CodecTypography,
CoverImagePreview,
CrowdfundActionButton,
CrowdfundActionButtonRow,
@ -713,15 +714,23 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
</Typography>
</Box>
<Box>
<Typography sx={{fontSize: "14px"}}>
Supported File Containers: MP4, Ogg, WebM, WAV
</Typography>
<Typography sx={{fontSize: "14px"}}>
Audio Codecs: FLAC, MP3, Opus, PCM (8/16/32-bit, μ-law), Vorbis
</Typography>
<Typography sx={{fontSize: "14px"}}>
Video Codecs: AV1, VP8, VP9
</Typography>
<CodecTypography>
Supported File Containers:{" "}
<span style={{ fontWeight: "bold" }}>MP4</span>, Ogg, WebM,
WAV
</CodecTypography>
<CodecTypography>
Audio Codecs: <span style={{ fontWeight: "bold" }}>Opus</span>
, MP3, FLAC, PCM (8/16/32-bit, μ-law), Vorbis
</CodecTypography>
<CodecTypography>
Video Codecs: <span style={{ fontWeight: "bold" }}>AV1</span>,
VP8, VP9, H.264
</CodecTypography>
<CodecTypography sx={{ fontWeight: "800", color: "red" }}>
Using unsupported Codecs may result in video or audio not
working properly
</CodecTypography>
</Box>
<Box

44
src/components/common/SubscribeButton.tsx

@ -2,29 +2,57 @@ import { Button, ButtonProps } from "@mui/material";
import { MouseEvent, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../../state/store.ts";
import { subscribe, unSubscribe } from "../../state/features/persistSlice.ts";
import {
resetSubscriptions,
subscribe,
unSubscribe,
} from "../../state/features/persistSlice.ts";
import { setFilteredSubscriptions } from "../../state/features/videoSlice.ts";
interface SubscribeButtonProps extends ButtonProps {
name: string;
subscriberName: string;
}
export const SubscribeButton = ({ name, ...props }: SubscribeButtonProps) => {
export const SubscribeButton = ({
subscriberName,
...props
}: SubscribeButtonProps) => {
const dispatch = useDispatch();
const persistSelector = useSelector((state: RootState) => {
return state.persist;
const filteredSubscriptionList = useSelector((state: RootState) => {
return state.video.filteredSubscriptionList;
});
const userName = useSelector((state: RootState) => state.auth.user?.name);
const [isSubscribed, setIsSubscribed] = useState<boolean>(false);
useEffect(() => {
setIsSubscribed(persistSelector.subscriptionList.includes(name));
const isSubscribedToName =
filteredSubscriptionList.find(item => {
return item.subscriberName === subscriberName;
}) !== undefined;
setIsSubscribed(isSubscribedToName);
}, []);
const subscriptionData = {
userName: userName,
subscriberName: subscriberName,
};
const subscribeToRedux = () => {
dispatch(subscribe(name));
dispatch(subscribe(subscriptionData));
dispatch(
setFilteredSubscriptions([...filteredSubscriptionList, subscriptionData])
);
setIsSubscribed(true);
};
const unSubscribeFromRedux = () => {
dispatch(unSubscribe(name));
dispatch(unSubscribe(subscriptionData));
dispatch(
setFilteredSubscriptions(
filteredSubscriptionList.filter(
item => item.subscriberName !== subscriptionData.subscriberName
)
)
);
setIsSubscribed(false);
};

32
src/hooks/useFetchVideos.tsx

@ -25,6 +25,7 @@ import {
QTUBE_VIDEO_BASE,
} from "../constants/Identifiers.ts";
import { allTabValue, subscriptionTabValue } from "../constants/Misc.ts";
import { persistReducer } from "redux-persist";
export const useFetchVideos = () => {
const dispatch = useDispatch();
@ -48,9 +49,7 @@ export const useFetchVideos = () => {
(state: RootState) => state.video.filteredVideos
);
const subscriptions = useSelector(
(state: RootState) => state.persist.subscriptionList
);
const videoReducer = useSelector((state: RootState) => state.video);
const checkAndUpdateVideo = React.useCallback(
(video: Video) => {
@ -189,22 +188,38 @@ export const useFetchVideos = () => {
}
}, [videos, hashMapVideos]);
type FilterType = {
name?: string;
category?: string;
subcategory?: string;
keywords?: string;
type?: string;
};
const emptyFilters = {
name: "",
category: "",
subcategory: "",
keywords: "",
type: "",
};
const getVideos = React.useCallback(
async (
filters = {},
filters = emptyFilters,
reset?: boolean,
resetFilters?: boolean,
limit?: number,
listType = allTabValue
) => {
emptyFilters.type = filters.type;
try {
const {
name = "",
category = "",
subcategory = "",
keywords = "",
type = "",
}: any = resetFilters ? {} : filters;
type = filters.type,
}: FilterType = resetFilters ? emptyFilters : filters;
let offset = videos.length;
if (reset) {
offset = 0;
@ -217,8 +232,9 @@ export const useFetchVideos = () => {
defaultUrl = defaultUrl + `&name=${name}`;
}
if (listType === subscriptionTabValue) {
subscriptions.map(sub => {
defaultUrl += `&name=${sub}`;
const filteredSubscribeList = videoReducer.filteredSubscriptionList;
filteredSubscribeList.map(sub => {
defaultUrl += `&name=${sub.subscriberName}`;
});
}

18
src/main.tsx

@ -1,17 +1,17 @@
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
import { BrowserRouter } from 'react-router-dom'
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
import { BrowserRouter } from "react-router-dom";
interface CustomWindow extends Window {
_qdnBase: string
_qdnBase: string;
}
const customWindow = window as unknown as CustomWindow
const customWindow = window as unknown as CustomWindow;
const baseUrl = customWindow?._qdnBase || ''
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
const baseUrl = customWindow?._qdnBase || "";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<BrowserRouter basename={baseUrl}>
<App />
<div id="modal-root" />
</BrowserRouter>
)
);

73
src/pages/Home/Home.tsx

@ -25,6 +25,7 @@ import {
FiltersSubContainer,
ProductManagerRow,
FiltersRadioButton,
StatsCol,
} from "./VideoList-styles";
import { SubtitleContainer } from "./Home-styles";
@ -34,7 +35,10 @@ import {
changefilterName,
changefilterSearch,
} from "../../state/features/videoSlice";
import { changeFilterType } from "../../state/features/persistSlice.ts";
import {
changeFilterType,
resetSubscriptions,
} from "../../state/features/persistSlice.ts";
import { categories, subCategories } from "../../constants/Categories.ts";
import { ListSuperLikeContainer } from "../../components/common/ListSuperLikes/ListSuperLikeContainer.tsx";
import { TabContext, TabList, TabPanel } from "@mui/lab";
@ -53,7 +57,7 @@ export const Home = ({ mode }: HomeProps) => {
const filterValue = useSelector(
(state: RootState) => state.video.filterValue
);
const persistSelector = useSelector((state: RootState) => state.persist);
const persistReducer = useSelector((state: RootState) => state.persist);
const filterType = useSelector(
(state: RootState) => state.persist.filterType
);
@ -74,12 +78,12 @@ export const Home = ({ mode }: HomeProps) => {
(state: RootState) => state.global.videosPerNamePublished
);
const { videos: globalVideos } = useSelector(
const { videos: globalVideos, filteredSubscriptionList } = useSelector(
(state: RootState) => state.video
);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [tabValue, setTabValue] = useState<string>(persistSelector.selectedTab);
const [tabValue, setTabValue] = useState<string>(persistReducer.selectedTab);
const tabFontSize = "20px";
@ -120,8 +124,13 @@ export const Home = ({ mode }: HomeProps) => {
const afterFetch = useRef(false);
const isFetching = useRef(false);
const { getVideos, getNewVideos, checkNewVideos, getVideosFiltered, getVideosCount } =
useFetchVideos();
const {
getVideos,
getNewVideos,
checkNewVideos,
getVideosFiltered,
getVideosCount,
} = useFetchVideos();
const getVideosHandler = React.useCallback(
async (reset?: boolean, resetFilters?: boolean) => {
@ -170,7 +179,19 @@ export const Home = ({ mode }: HomeProps) => {
firstFetch.current = true;
setIsLoading(true);
await getVideos({ type: filterType }, null, null, 20, tabValue);
await getVideos(
{
name: "",
category: "",
subcategory: "",
keywords: "",
type: filterType,
},
null,
null,
20,
tabValue
);
afterFetch.current = true;
isFetching.current = false;
@ -227,7 +248,6 @@ export const Home = ({ mode }: HomeProps) => {
}, [getVideosHandlerMount, globalVideos]);
const filtersToDefault = async () => {
setFilterType("videos");
setFilterSearch("");
setFilterName("");
setSelectedCategoryVideos(null);
@ -273,22 +293,31 @@ export const Home = ({ mode }: HomeProps) => {
return (
<>
<Box sx={{ width: "100%" }}>
<Grid container spacing={2} justifyContent="space-around">
<Grid item xs={12} sm={4}>
Total Videos Published: {totalVideosPublished}
</Grid>
<Grid item xs={12} sm={4}>
Total Names Publishing: {totalNamesPublished}
</Grid>
<Grid item xs={12} sm={4}>
Average Videos per Name: {videosPerNamePublished}
</Grid>
</Grid>
</Box>
<Grid container sx={{ width: "100%" }}>
<FiltersCol item xs={12} md={2} lg={2} xl={2} sm={3}>
<FiltersContainer>
<StatsCol
sx={{ display: persistReducer.showStats ? "block" : "none" }}
>
<div>
# of Videos:{" "}
<span style={{ fontWeight: "bold" }}>
{totalVideosPublished}
</span>
</div>
<div>
Names Publishing:{" "}
<span style={{ fontWeight: "bold" }}>
{totalNamesPublished}
</span>
</div>
<div>
Videos per Name:{" "}
<span style={{ fontWeight: "bold" }}>
{videosPerNamePublished}
</span>
</div>
</StatsCol>
<Input
id="standard-adornment-name"
onChange={e => {
@ -538,7 +567,7 @@ export const Home = ({ mode }: HomeProps) => {
></LazyLoad>
</TabPanel>
<TabPanel value={subscriptionTabValue} sx={{ width: "100%" }}>
{persistSelector.subscriptionList.length > 0 ? (
{filteredSubscriptionList.length > 0 ? (
<>
<VideoList videos={videos} />
<LazyLoad

10
src/pages/Home/VideoList-styles.tsx

@ -237,6 +237,16 @@ export const FiltersCol = styled(Grid)(({ theme }) => ({
borderRight: `1px solid ${theme.palette.background.paper}`,
}));
export const StatsCol = styled(Grid)(({ theme }) => ({
display: "flex",
flexDirection: "column",
width: "100%",
padding: "20px 15px",
backgroundColor: theme.palette.background.default,
borderTop: `1px solid ${theme.palette.background.paper}`,
borderRight: `1px solid ${theme.palette.background.paper}`,
}));
export const FiltersContainer = styled(Box)(({ theme }) => ({
display: "flex",
flexDirection: "column",

75
src/pages/IndividualProfile/IndividualProfile.tsx

@ -1,65 +1,74 @@
import React, { useMemo } from 'react'
import { VideoListComponentLevel } from '../Home/VideoListComponentLevel'
import { HeaderContainer, ProfileContainer } from './Profile-styles'
import { AuthorTextComment, StyledCardColComment, StyledCardHeaderComment } from '../VideoContent/VideoContent-styles'
import { Avatar, Box, useTheme } from '@mui/material'
import { useParams } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { setUserAvatarHash } from '../../state/features/globalSlice'
import { RootState } from '../../state/store'
import React, { useMemo } from "react";
import { VideoListComponentLevel } from "../Home/VideoListComponentLevel";
import { HeaderContainer, ProfileContainer } from "./Profile-styles";
import {
AuthorTextComment,
StyledCardColComment,
StyledCardHeaderComment,
} from "../VideoContent/VideoContent-styles";
import { Avatar, Box, useTheme } from "@mui/material";
import { useParams } from "react-router-dom";
import { useSelector } from "react-redux";
import { setUserAvatarHash } from "../../state/features/globalSlice";
import { RootState } from "../../state/store";
import { SubscribeButton } from "../../components/common/SubscribeButton.tsx";
export const IndividualProfile = () => {
const { name: paramName } = useParams()
const { name: paramName } = useParams();
const userAvatarHash = useSelector(
(state: RootState) => state.global.userAvatarHash
)
const theme = useTheme()
);
const theme = useTheme();
const avatarUrl = useMemo(()=> {
let url = ''
if(paramName && userAvatarHash[paramName]){
url = userAvatarHash[paramName]
const avatarUrl = useMemo(() => {
let url = "";
if (paramName && userAvatarHash[paramName]) {
url = userAvatarHash[paramName];
}
return url
}, [userAvatarHash, paramName])
return url;
}, [userAvatarHash, paramName]);
return (
<ProfileContainer>
<HeaderContainer>
<Box sx={{
cursor: 'pointer'
}} >
<Box
sx={{
cursor: "pointer",
}}
>
<StyledCardHeaderComment
sx={{
'& .MuiCardHeader-content': {
overflow: 'hidden'
}
"& .MuiCardHeader-content": {
overflow: "hidden",
},
}}
>
<Box>
<Avatar src={`/arbitrary/THUMBNAIL/${paramName}/qortal_avatar`} alt={`${paramName}'s avatar`} />
<Avatar
src={`/arbitrary/THUMBNAIL/${paramName}/qortal_avatar`}
alt={`${paramName}'s avatar`}
/>
</Box>
<StyledCardColComment>
<AuthorTextComment
color={
theme.palette.mode === 'light'
theme.palette.mode === "light"
? theme.palette.text.secondary
: '#d6e8ff'
: "#d6e8ff"
}
>
{paramName}
</AuthorTextComment>
</StyledCardColComment>
<SubscribeButton name={paramName} sx={{marginLeft:'10px'}}/>
<SubscribeButton
subscriberName={paramName}
sx={{ marginLeft: "10px" }}
/>
</StyledCardHeaderComment>
</Box>
</HeaderContainer>
<VideoListComponentLevel />
</ProfileContainer>
)
}
);
};

2
src/pages/PlaylistContent/PlaylistContent.tsx

@ -497,7 +497,7 @@ export const PlaylistContent = () => {
>
{name}
<SubscribeButton
name={name}
subscriberName={name}
sx={{ marginLeft: "20px" }}
/>
</AuthorTextComment>

5
src/pages/VideoContent/VideoContent.tsx

@ -437,7 +437,10 @@ export const VideoContent = () => {
}}
>
{name}
<SubscribeButton name={name} sx={{ marginLeft: "20px" }} />
<SubscribeButton
subscriberName={name}
sx={{ marginLeft: "20px" }}
/>
</AuthorTextComment>
</StyledCardColComment>
</StyledCardHeaderComment>

34
src/state/features/persistSlice.ts

@ -2,12 +2,21 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { subscriptionTabValue } from "../../constants/Misc.ts";
type StretchVideoType = "contain" | "fill" | "cover" | "none" | "scale-down";
type SubscriptionListFilterType = "ALL" | "currentNameOnly";
export type SubscriptionObject = {
userName: string;
subscriberName: string;
};
interface settingsState {
selectedTab: string;
stretchVideoSetting: StretchVideoType;
filterType: string;
subscriptionList: string[];
subscriptionList: SubscriptionObject[];
playbackRate: number;
subscriptionListFilter: SubscriptionListFilterType;
showStats: boolean;
}
const initialState: settingsState = {
@ -16,6 +25,8 @@ const initialState: settingsState = {
filterType: "videos",
subscriptionList: [],
playbackRate: 1,
subscriptionListFilter: "currentNameOnly",
showStats: true,
};
export const persistSlice = createSlice({
@ -28,16 +39,28 @@ export const persistSlice = createSlice({
setStretchVideoSetting: (state, action) => {
state.stretchVideoSetting = action.payload;
},
subscribe: (state, action: PayloadAction<string>) => {
setShowStats: (state, action) => {
state.showStats = action.payload;
},
subscribe: (state, action: PayloadAction<SubscriptionObject>) => {
const currentSubscriptions = state.subscriptionList;
if (!currentSubscriptions.includes(action.payload)) {
const notSubscribedToName =
currentSubscriptions.find(item => {
return item.subscriberName === action.payload.subscriberName;
}) === undefined;
if (notSubscribedToName) {
state.subscriptionList = [...currentSubscriptions, action.payload];
}
console.log("subscribeList after subscribe: ", state.subscriptionList);
},
unSubscribe: (state, action) => {
unSubscribe: (state, action: PayloadAction<SubscriptionObject>) => {
state.subscriptionList = state.subscriptionList.filter(
item => item !== action.payload
item => item.subscriberName !== action.payload.subscriberName
);
console.log("subscribeList after unsubscribe: ", state.subscriptionList);
},
resetSubscriptions: state => {
state.subscriptionList = [];
},
setReduxPlaybackRate: (state, action) => {
state.playbackRate = action.payload;
@ -54,6 +77,7 @@ export const {
unSubscribe,
setReduxPlaybackRate,
changeFilterType,
resetSubscriptions,
} = persistSlice.actions;
export default persistSlice.reducer;

11
src/state/features/videoSlice.ts

@ -1,4 +1,5 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { SubscriptionObject } from "./persistSlice.ts";
interface GlobalState {
videos: Video[];
@ -14,6 +15,7 @@ interface GlobalState {
selectedSubCategoryVideos: any;
editVideoProperties: any;
editPlaylistProperties: any;
filteredSubscriptionList: SubscriptionObject[];
}
const initialState: GlobalState = {
@ -30,6 +32,7 @@ const initialState: GlobalState = {
selectedSubCategoryVideos: null,
editVideoProperties: null,
editPlaylistProperties: null,
filteredSubscriptionList: [],
};
export interface Video {
@ -168,6 +171,13 @@ export const videoSlice = createSlice({
state.videos = state.videos.filter(item => item.user !== username);
},
setFilteredSubscriptions: (
state,
action: PayloadAction<SubscriptionObject[]>
) => {
state.filteredSubscriptionList = action.payload;
},
},
});
@ -196,6 +206,7 @@ export const {
setEditVideo,
setEditPlaylist,
addtoHashMapSuperlikes,
setFilteredSubscriptions,
} = videoSlice.actions;
export default videoSlice.reducer;

4
src/state/store.ts

@ -3,7 +3,7 @@ import notificationsReducer from "./features/notificationsSlice";
import authReducer from "./features/authSlice";
import globalReducer from "./features/globalSlice";
import videoReducer from "./features/videoSlice";
import settingsReducer from "./features/persistSlice.ts";
import persistDataReducer from "./features/persistSlice.ts";
import {
persistReducer,
FLUSH,
@ -26,7 +26,7 @@ const reducer = combineReducers({
auth: authReducer,
global: globalReducer,
video: videoReducer,
persist: persistReducer(persistSettingsConfig, settingsReducer),
persist: persistReducer(persistSettingsConfig, persistDataReducer),
});
export const store = configureStore({

Loading…
Cancel
Save