diff --git a/package.json b/package.json index ba7d281..b753d69 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "qtube", "private": true, - "version": "0.0.0", + "version": "2.0.0", "type": "module", "scripts": { "dev": "vite", diff --git a/src/App.tsx b/src/App.tsx index 1c7c968..e6f629b 100644 --- a/src/App.tsx +++ b/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 ( diff --git a/src/components/PublishVideo/PublishVideo-styles.tsx b/src/components/PublishVideo/PublishVideo-styles.tsx index b1b8813..6495a8a 100644 --- a/src/components/PublishVideo/PublishVideo-styles.tsx +++ b/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", diff --git a/src/components/PublishVideo/PublishVideo.tsx b/src/components/PublishVideo/PublishVideo.tsx index 3b9307e..ab59967 100644 --- a/src/components/PublishVideo/PublishVideo.tsx +++ b/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) => { - - Supported File Containers: MP4, Ogg, WebM, WAV - - - Audio Codecs: FLAC, MP3, Opus, PCM (8/16/32-bit, μ-law), Vorbis - - - Video Codecs: AV1, VP8, VP9 - + + Supported File Containers:{" "} + MP4, Ogg, WebM, + WAV + + + Audio Codecs: Opus + , MP3, FLAC, PCM (8/16/32-bit, μ-law), Vorbis + + + Video Codecs: AV1, + VP8, VP9, H.264 + + + Using unsupported Codecs may result in video or audio not + working properly + { +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(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); }; diff --git a/src/hooks/useFetchVideos.tsx b/src/hooks/useFetchVideos.tsx index f6904f9..8a8b3d4 100644 --- a/src/hooks/useFetchVideos.tsx +++ b/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}`; }); } diff --git a/src/main.tsx b/src/main.tsx index b13bb52..17b98a1 100644 --- a/src/main.tsx +++ b/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(