mirror of
https://github.com/Qortal/q-tube.git
synced 2025-02-11 17:55:51 +00:00
global superlikes
This commit is contained in:
parent
a0e1c65900
commit
8db8bd9dd2
@ -0,0 +1,19 @@
|
||||
import { Box, Typography } from '@mui/material'
|
||||
import React from 'react'
|
||||
import ListSuperLikes from './ListSuperLikes'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState } from '../../../state/store'
|
||||
|
||||
export const LiskSuperLikeContainer = () => {
|
||||
const superlikelist = useSelector((state: RootState) => state.global.superlikelistAll);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography sx={{
|
||||
fontSize: '18px',
|
||||
color: 'gold'
|
||||
}}>Recent Super likes</Typography>
|
||||
<ListSuperLikes superlikes={superlikelist} />
|
||||
</Box>
|
||||
)
|
||||
}
|
152
src/components/common/ListSuperLikes/ListSuperLikes.tsx
Normal file
152
src/components/common/ListSuperLikes/ListSuperLikes.tsx
Normal file
@ -0,0 +1,152 @@
|
||||
import * as React from "react";
|
||||
import List from "@mui/material/List";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import ListItemAvatar from "@mui/material/ListItemAvatar";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import ThumbUpIcon from "@mui/icons-material/ThumbUp";
|
||||
import { Box } from "@mui/material";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "../../../state/store";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
|
||||
const truncateMessage = (message) => {
|
||||
return message.length > 40 ? message.slice(0, 40) + "..." : message;
|
||||
};
|
||||
|
||||
export default function ListSuperLikes({ superlikes }) {
|
||||
const hashMapSuperlikes = useSelector(
|
||||
(state: RootState) => state.video.hashMapSuperlikes
|
||||
);
|
||||
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<List sx={{ width: "100%", maxWidth: 360, bgcolor: "background.paper" }}>
|
||||
{superlikes?.map((superlike, index) => {
|
||||
// let hasHash = false
|
||||
let message = "";
|
||||
let url = "";
|
||||
let forName = ""
|
||||
// let hash = {}
|
||||
if (hashMapSuperlikes[superlike?.identifier]) {
|
||||
|
||||
message = hashMapSuperlikes[superlike?.identifier]?.comment || "";
|
||||
if (
|
||||
hashMapSuperlikes[superlike?.identifier]?.notificationInformation
|
||||
) {
|
||||
|
||||
const info =
|
||||
hashMapSuperlikes[superlike?.identifier]?.notificationInformation;
|
||||
forName = info?.name
|
||||
url = `/video/${info?.name}/${info?.identifier}`;
|
||||
}
|
||||
|
||||
// hasHash = true
|
||||
// hash = hashMapSuperlikes[superlike?.identifier]
|
||||
}
|
||||
let amount = null;
|
||||
if (!isNaN(parseFloat(superlike?.amount))) {
|
||||
amount = parseFloat(superlike?.amount).toFixed(2);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<ListItem
|
||||
key={superlike?.identifier}
|
||||
alignItems="flex-start"
|
||||
sx={{
|
||||
cursor: url ? "pointer" : "default",
|
||||
minHeight: '130px'
|
||||
}}
|
||||
onClick={async () => {
|
||||
if (url) {
|
||||
navigate(url);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<ListItem
|
||||
sx={{
|
||||
padding: '0px'
|
||||
}}
|
||||
alignItems="flex-start"
|
||||
|
||||
>
|
||||
|
||||
<ListItemAvatar>
|
||||
<Avatar
|
||||
alt="Remy Sharp"
|
||||
src={`/arbitrary/THUMBNAIL/${superlike?.name}/qortal_avatar`}
|
||||
/>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "5px",
|
||||
fontSize: "16px",
|
||||
}}
|
||||
>
|
||||
<ThumbUpIcon
|
||||
style={{
|
||||
color: "gold",
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
}}
|
||||
>
|
||||
{amount ? amount : ""} QORT
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
secondary={
|
||||
<Box sx={{
|
||||
fontSize: '15px'
|
||||
}}>
|
||||
<Typography
|
||||
sx={{ display: "inline" }}
|
||||
component="span"
|
||||
variant="body2"
|
||||
color="text.primary"
|
||||
>
|
||||
{superlike?.name}
|
||||
</Typography>
|
||||
|
||||
{` - ${truncateMessage(message)}`}
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
{forName && (
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '17px',
|
||||
gap: '10px',
|
||||
justifyContent: 'flex-end'
|
||||
}}>
|
||||
<EmojiEventsIcon />
|
||||
{forName}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
</Box>
|
||||
</ListItem>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{superlikes.length === index + 1 ? null : <Divider />}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
);
|
||||
}
|
@ -14,7 +14,7 @@ import moment from 'moment'
|
||||
const generalLocal = localForage.createInstance({
|
||||
name: "q-tube-general",
|
||||
});
|
||||
function extractIdValue(metadescription) {
|
||||
export function extractIdValue(metadescription) {
|
||||
// Function to extract the substring within double asterisks
|
||||
function extractSubstring(str) {
|
||||
const match = str.match(/\*\*(.*?)\*\*/);
|
||||
|
@ -12,6 +12,39 @@ export const VideoContainer = styled(Grid)(({ theme }) => ({
|
||||
width: '100%'
|
||||
}));
|
||||
|
||||
// export const VideoCardContainer = styled(Grid)({
|
||||
// display: "flex",
|
||||
// flexWrap: "wrap",
|
||||
// padding: "5px 35px 15px 35px",
|
||||
// });
|
||||
|
||||
// export const VideoCardCol = styled(Grid)(({ theme }) => ({
|
||||
// display: "flex",
|
||||
// gap: 1,
|
||||
// alignItems: "center",
|
||||
// width: "auto",
|
||||
// position: "relative",
|
||||
// maxWidth: "100%",
|
||||
// flexGrow: 1,
|
||||
// [theme.breakpoints.down("sm")]: {
|
||||
// width: "100%",
|
||||
// },
|
||||
// }));
|
||||
|
||||
export const VideoCardContainer = styled('div')(({ theme }) => ({
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))',
|
||||
gap: theme.spacing(2),
|
||||
padding: '10px',
|
||||
width: '100%'
|
||||
}));
|
||||
|
||||
export const VideoCardCol = styled('div')({
|
||||
minWidth: '250px', // Minimum width of each item
|
||||
maxWidth: '1fr', // Maximum width, allowing the item to fill the column
|
||||
// ... other styles
|
||||
});
|
||||
|
||||
export const StoresRow = styled(Grid)(({ theme }) => ({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
@ -30,7 +63,7 @@ export const VideoCard = styled(Grid)(({ theme }) => ({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "320px",
|
||||
width: '300px',
|
||||
// width: '300px',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: "8px",
|
||||
padding: "10px 15px",
|
||||
@ -177,6 +210,16 @@ export const MyStoresCheckbox = styled(Checkbox)(({ theme }) => ({
|
||||
}
|
||||
}));
|
||||
|
||||
export const ProductManagerRow = styled(Box)(({ theme }) => ({
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr auto",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
width: "100%",
|
||||
}));
|
||||
|
||||
|
||||
|
||||
export const FiltersCol = styled(Grid)(({ theme }) => ({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
|
@ -33,6 +33,9 @@ import {
|
||||
FiltersTitle,
|
||||
IconsBox,
|
||||
NameContainer,
|
||||
VideoCardCol,
|
||||
ProductManagerRow,
|
||||
VideoCardContainer,
|
||||
VideoCard,
|
||||
VideoCardName,
|
||||
VideoCardTitle,
|
||||
@ -60,6 +63,7 @@ import { Playlists } from "../../components/Playlists/Playlists";
|
||||
import { PlaylistSVG } from "../../assets/svgs/PlaylistSVG";
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import { LiskSuperLikeContainer } from "../../components/common/ListSuperLikes/LiskSuperLikeContainer";
|
||||
|
||||
interface VideoListProps {
|
||||
mode?: string;
|
||||
@ -286,7 +290,7 @@ export const VideoList = ({ mode }: VideoListProps) => {
|
||||
|
||||
return (
|
||||
<Grid container sx={{ width: "100%" }}>
|
||||
<FiltersCol item xs={12} md={2} sm={3}>
|
||||
<FiltersCol item xs={12} md={2} lg={2} xl={2} sm={3} >
|
||||
<FiltersContainer>
|
||||
<Input
|
||||
id="standard-adornment-name"
|
||||
@ -506,7 +510,8 @@ export const VideoList = ({ mode }: VideoListProps) => {
|
||||
</Button>
|
||||
</FiltersContainer>
|
||||
</FiltersCol>
|
||||
<Grid item xs={12} md={10} sm={9}>
|
||||
<Grid item xs={12} md={10} lg={7} xl={8} sm={9}>
|
||||
<ProductManagerRow>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
@ -524,41 +529,10 @@ export const VideoList = ({ mode }: VideoListProps) => {
|
||||
maxWidth: "1400px",
|
||||
}}
|
||||
>
|
||||
{/* <Subtitle sx={{
|
||||
textAlign: 'start',
|
||||
fontSize: '18px'
|
||||
}}>
|
||||
{!isFiltering ? 'Recently Published Videos': 'Search'}
|
||||
</Subtitle> */}
|
||||
|
||||
</SubtitleContainer>
|
||||
{/* { countNewVideos > 0 && !isFiltering && (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography>
|
||||
{countNewVideos === 1
|
||||
? `There is ${countNewVideos} new video`
|
||||
: `There are ${countNewVideos} new videos`}
|
||||
</Typography>
|
||||
<Button
|
||||
sx={{
|
||||
backgroundColor: theme.palette.primary.light,
|
||||
color: theme.palette.text.primary,
|
||||
fontFamily: 'Arial'
|
||||
}}
|
||||
onClick={()=> {
|
||||
getNewVideos()
|
||||
}}
|
||||
>
|
||||
Load new Posts
|
||||
</Button>
|
||||
</Box>
|
||||
)} */}
|
||||
<VideoContainer>
|
||||
|
||||
<VideoCardContainer >
|
||||
{videos.map((video: any, index: number) => {
|
||||
const existingVideo = hashMapVideos[video?.id];
|
||||
let hasHash = false;
|
||||
@ -581,17 +555,8 @@ export const VideoList = ({ mode }: VideoListProps) => {
|
||||
|
||||
if (isPlaylist) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flex: 0,
|
||||
alignItems: "center",
|
||||
width: "auto",
|
||||
position: "relative",
|
||||
" @media (max-width: 450px)": {
|
||||
width: "100%",
|
||||
},
|
||||
}}
|
||||
<VideoCardCol
|
||||
|
||||
onMouseEnter={() => setShowIcons(videoObj.id)}
|
||||
onMouseLeave={() => setShowIcons(null)}
|
||||
key={videoObj.id}
|
||||
@ -686,22 +651,13 @@ export const VideoList = ({ mode }: VideoListProps) => {
|
||||
</Box>
|
||||
</BottomParent>
|
||||
</VideoCard>
|
||||
</Box>
|
||||
</VideoCardCol>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flex: 0,
|
||||
alignItems: "center",
|
||||
width: "auto",
|
||||
position: "relative",
|
||||
" @media (max-width: 450px)": {
|
||||
width: "100%",
|
||||
},
|
||||
}}
|
||||
<VideoCardCol
|
||||
|
||||
key={videoObj.id}
|
||||
onMouseEnter={() => setShowIcons(videoObj.id)}
|
||||
onMouseLeave={() => setShowIcons(null)}
|
||||
@ -776,17 +732,21 @@ export const VideoList = ({ mode }: VideoListProps) => {
|
||||
)}
|
||||
</BottomParent>
|
||||
</VideoCard>
|
||||
</Box>
|
||||
</VideoCardCol>
|
||||
);
|
||||
})}
|
||||
</VideoContainer>
|
||||
</VideoCardContainer>
|
||||
|
||||
<LazyLoad
|
||||
onLoadMore={getVideosHandler}
|
||||
isLoading={isLoading}
|
||||
></LazyLoad>
|
||||
</Box>
|
||||
</ProductManagerRow>
|
||||
</Grid>
|
||||
<FiltersCol item xs={0} lg={3} xl={2}>
|
||||
<LiskSuperLikeContainer />
|
||||
</FiltersCol>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
} from '@mui/material'
|
||||
import { useFetchVideos } from '../../hooks/useFetchVideos'
|
||||
import LazyLoad from '../../components/common/LazyLoad'
|
||||
import { BottomParent, NameContainer, VideoCard, VideoCardName, VideoCardTitle, VideoContainer, VideoUploadDate } from './VideoList-styles'
|
||||
import { BottomParent, NameContainer, ProductManagerRow, VideoCard, VideoCardCol, VideoCardContainer, VideoCardName, VideoCardTitle, VideoContainer, VideoUploadDate } from './VideoList-styles'
|
||||
import ResponsiveImage from '../../components/ResponsiveImage'
|
||||
import { formatDate, formatTimestampSeconds } from '../../utils/time'
|
||||
import { Video } from '../../state/features/videoSlice'
|
||||
@ -130,6 +130,7 @@ export const VideoListComponentLevel = ({ mode }: VideoListProps) => {
|
||||
|
||||
|
||||
return (
|
||||
<ProductManagerRow>
|
||||
<Box sx={{
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
@ -137,7 +138,7 @@ export const VideoListComponentLevel = ({ mode }: VideoListProps) => {
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
|
||||
<VideoContainer>
|
||||
<VideoCardContainer>
|
||||
{videos.map((video: any, index: number) => {
|
||||
const existingVideo = hashMapVideos[video.id]
|
||||
let hasHash = false
|
||||
@ -158,17 +159,8 @@ export const VideoListComponentLevel = ({ mode }: VideoListProps) => {
|
||||
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flex: 0,
|
||||
alignItems: 'center',
|
||||
width: 'auto',
|
||||
position: 'relative',
|
||||
' @media (max-width: 450px)': {
|
||||
width: '100%'
|
||||
}
|
||||
}}
|
||||
<VideoCardCol
|
||||
|
||||
key={videoObj.id}
|
||||
>
|
||||
|
||||
@ -193,12 +185,13 @@ export const VideoListComponentLevel = ({ mode }: VideoListProps) => {
|
||||
</VideoCard>
|
||||
|
||||
|
||||
</Box>
|
||||
</VideoCardCol>
|
||||
)
|
||||
})}
|
||||
</VideoContainer>
|
||||
</VideoCardContainer>
|
||||
<LazyLoad onLoadMore={getVideosHandler} isLoading={isLoading}></LazyLoad>
|
||||
</Box>
|
||||
</ProductManagerRow>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -7,13 +7,15 @@ interface GlobalState {
|
||||
userAvatarHash: Record<string, string>
|
||||
publishNames: string[] | null
|
||||
videoPlaying: any | null
|
||||
superlikelistAll: any[]
|
||||
}
|
||||
const initialState: GlobalState = {
|
||||
isLoadingGlobal: false,
|
||||
downloads: {},
|
||||
userAvatarHash: {},
|
||||
publishNames: null,
|
||||
videoPlaying: null
|
||||
videoPlaying: null,
|
||||
superlikelistAll: []
|
||||
}
|
||||
|
||||
export const globalSlice = createSlice({
|
||||
@ -47,6 +49,9 @@ export const globalSlice = createSlice({
|
||||
setVideoPlaying: (state, action) => {
|
||||
state.videoPlaying = action.payload
|
||||
},
|
||||
setSuperlikesAll: (state, action) => {
|
||||
state.superlikelistAll = action.payload
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
@ -56,7 +61,8 @@ export const {
|
||||
updateDownloads,
|
||||
setUserAvatarHash,
|
||||
addPublishNames,
|
||||
setVideoPlaying
|
||||
setVideoPlaying,
|
||||
setSuperlikesAll
|
||||
} = globalSlice.actions
|
||||
|
||||
export default globalSlice.reducer
|
||||
|
@ -11,13 +11,16 @@ import { addUser } from "../state/features/authSlice";
|
||||
import NavBar from "../components/layout/Navbar/Navbar";
|
||||
import PageLoader from "../components/common/PageLoader";
|
||||
import { RootState } from "../state/store";
|
||||
import { setUserAvatarHash } from "../state/features/globalSlice";
|
||||
import { setSuperlikesAll, setUserAvatarHash } from "../state/features/globalSlice";
|
||||
import { VideoPlayerGlobal } from "../components/common/VideoPlayerGlobal";
|
||||
import { Rnd } from "react-rnd";
|
||||
import { RequestQueue } from "../utils/queue";
|
||||
import { EditVideo } from "../components/EditVideo/EditVideo";
|
||||
import { EditPlaylist } from "../components/EditPlaylist/EditPlaylist";
|
||||
import ConsentModal from "../components/common/ConsentModal";
|
||||
import { SUPER_LIKE_BASE, minPriceSuperlike } from "../constants";
|
||||
import { extractSigValue, getPaymentInfo, isTimestampWithinRange } from "../pages/VideoContent/VideoContent";
|
||||
import { useFetchSuperLikes } from "../hooks/useFetchSuperLikes";
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
@ -35,6 +38,9 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
const isDragging = useRef(false);
|
||||
const [userAvatar, setUserAvatar] = useState<string>("");
|
||||
const user = useSelector((state: RootState) => state.auth.user);
|
||||
const {addSuperlikeRawDataGetToList} = useFetchSuperLikes()
|
||||
const interval = useRef<any>(null)
|
||||
|
||||
const videoPlaying = useSelector(
|
||||
(state: RootState) => state.global.videoPlaying
|
||||
);
|
||||
@ -128,6 +134,80 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
return isDragging.current;
|
||||
}, []);
|
||||
|
||||
|
||||
const getSuperlikes = useCallback(
|
||||
async () => {
|
||||
try {
|
||||
|
||||
|
||||
const url = `/arbitrary/resources/search?mode=ALL&service=BLOG_COMMENT&query=${SUPER_LIKE_BASE}&limit=20&includemetadata=true&reverse=true&excludeblocked=true`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const responseData = await response.json();
|
||||
let comments: any[] = [];
|
||||
for (const comment of responseData) {
|
||||
if (comment.identifier && comment.name && comment?.metadata?.description) {
|
||||
|
||||
|
||||
try {
|
||||
|
||||
const result = extractSigValue(comment?.metadata?.description)
|
||||
if(!result) continue
|
||||
const res = await getPaymentInfo(result);
|
||||
if(+res?.amount >= minPriceSuperlike && isTimestampWithinRange(res?.timestamp, comment.created)){
|
||||
addSuperlikeRawDataGetToList({name:comment.name, identifier:comment.identifier, content: comment})
|
||||
|
||||
comments = [...comments, {
|
||||
...comment,
|
||||
message: "",
|
||||
amount: res.amount
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
dispatch(setSuperlikesAll(comments));
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const checkSuperlikes = useCallback(
|
||||
() => {
|
||||
let isCalling = false
|
||||
interval.current = setInterval(async () => {
|
||||
if (isCalling) return
|
||||
isCalling = true
|
||||
const res = await getSuperlikes()
|
||||
isCalling = false
|
||||
}, 300000)
|
||||
getSuperlikes()
|
||||
},
|
||||
[getSuperlikes])
|
||||
|
||||
useEffect(() => {
|
||||
checkSuperlikes();
|
||||
}, [checkSuperlikes]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{isLoadingGlobal && <PageLoader />}
|
||||
|
Loading…
x
Reference in New Issue
Block a user