Browse Source

Merge pull request #30 from QortalSeth/main

Fixed video skeleton not loading bug.
pull/31/head^2
Qortal Dev 2 months ago committed by GitHub
parent
commit
dfe096bcbe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. BIN
      src/assets/img/DeletedVideo.jpg
  2. 68
      src/components/ResponsiveImage.tsx
  3. 5
      src/components/common/SuperLikesList/CommentEditor.tsx
  4. 7
      src/constants/Misc.ts
  5. 7
      src/pages/ContentPages/VideoContent/VideoContent.tsx
  6. 22
      src/pages/Home/VideoList.tsx
  7. 1
      src/state/store.ts
  8. 35
      src/utils/fetchVideos.ts

BIN
src/assets/img/DeletedVideo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

68
src/components/ResponsiveImage.tsx

@ -1,14 +1,14 @@
import React, { useState, useEffect, CSSProperties } from 'react' import React, { useState, useEffect, CSSProperties } from "react";
import Skeleton from '@mui/material/Skeleton' import Skeleton from "@mui/material/Skeleton";
import { Box } from '@mui/material' import { Box } from "@mui/material";
import DeletedVideo from "../assets/img/DeletedVideo.jpg";
interface ResponsiveImageProps { interface ResponsiveImageProps {
src: string src: string;
width: number width: number;
height: number height: number;
alt?: string alt?: string;
className?: string className?: string;
style?: CSSProperties style?: CSSProperties;
} }
const ResponsiveImage: React.FC<ResponsiveImageProps> = ({ const ResponsiveImage: React.FC<ResponsiveImageProps> = ({
@ -17,49 +17,55 @@ const ResponsiveImage: React.FC<ResponsiveImageProps> = ({
height, height,
alt, alt,
className, className,
style style,
}) => { }) => {
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true);
const endLoading = (endTimeSeconds: number) => {
const endTimeMilliSeconds = endTimeSeconds * 1000;
setTimeout(() => {
if (loading) setLoading(false);
}, endTimeMilliSeconds);
};
useEffect(() => endLoading(5), []);
return ( return (
<Box <Box
sx={{ sx={{
padding: '2px', padding: "2px",
height: '100%', height: "100%",
...style ...style,
}} }}
> >
{loading && ( {loading && (
<Skeleton <Skeleton
variant="rectangular" variant="rectangular"
style={{ style={{
width: '100%', width: "100%",
height: 0, height: 0,
paddingBottom: `${(height / width) * 100}%`, paddingBottom: `${(height / width) * 100}%`,
objectFit: 'contain', objectFit: "contain",
visibility: loading ? 'visible' : 'hidden', visibility: loading ? "visible" : "hidden",
borderRadius: '8px' borderRadius: "8px",
}} }}
/> />
)} )}
<img <img
onLoad={() => setLoading(false)} onLoad={() => setLoading(false)}
src={src} src={!src && !loading ? DeletedVideo : src}
style={{ style={{
width: '100%', width: "100%",
height: '100%', height: "100%",
borderRadius: '8px', borderRadius: "8px",
visibility: loading ? 'hidden' : 'visible', visibility: loading ? "hidden" : "visible",
position: loading ? 'absolute' : 'unset', position: loading ? "absolute" : "unset",
objectFit: 'contain' objectFit: "contain",
}} }}
/> />
</Box> </Box>
) );
} };
export default ResponsiveImage export default ResponsiveImage;

5
src/components/common/SuperLikesList/CommentEditor.tsx

@ -181,18 +181,17 @@ export const CommentEditor = ({
notificationInformation: comment.notificationInformation, notificationInformation: comment.notificationInformation,
about: comment.about, about: comment.about,
}; };
const superLikeToFile = await objectToFile(superObj); const superLikeToFile = objectToFile(superObj);
dataFile = superLikeToFile; dataFile = superLikeToFile;
} }
if (isSuperLike && !dataFile) if (isSuperLike && !dataFile)
throw new Error("unable to edit Super like"); throw new Error("unable to edit Super like");
const stringFile = stringToFile(value);
const resourceResponse = await qortalRequest({ const resourceResponse = await qortalRequest({
action: "PUBLISH_QDN_RESOURCE", action: "PUBLISH_QDN_RESOURCE",
name: name, name: name,
service: "BLOG_COMMENT", service: "BLOG_COMMENT",
file: isSuperLike ? dataFile : stringFile, file: isSuperLike ? dataFile : stringToFile(value),
identifier: identifier, identifier: identifier,
description, description,
tag1, tag1,

7
src/constants/Misc.ts

@ -1,6 +1,7 @@
export const minPriceSuperlike = 1; export const minPriceSuperlike = 1;
export const titleFormatter = /[^a-zA-Z0-9\s-_!?()&'",.;:|—~@#$%^*+=<>]/g;
export const titleFormatterOnSave = /[^a-zA-Z0-9\s-_!()&',.;—~@#$%^+=]/g; export const titleFormatter = /[\r\n]+/g;
export const titleFormatterOnSave = /[\r\n/<>:"'\\*|?]+/g;
export const videoMaxSize = 400; // Size in Megabytes (decimal) export const videoMaxSize = 400; // Size in Megabytes (decimal)
export const maxSize = videoMaxSize *1024*1024 export const maxSize = videoMaxSize * 1024 * 1024;

7
src/pages/ContentPages/VideoContent/VideoContent.tsx

@ -7,6 +7,7 @@ import React, {
} from "react"; } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import ResponsiveImage from "../../../components/ResponsiveImage.tsx";
import { setIsLoadingGlobal } from "../../../state/features/globalSlice.ts"; import { setIsLoadingGlobal } from "../../../state/features/globalSlice.ts";
import { Avatar, Box, Typography, useTheme } from "@mui/material"; import { Avatar, Box, Typography, useTheme } from "@mui/material";
import { import {
@ -17,6 +18,7 @@ import { RootState } from "../../../state/store.ts";
import { addToHashMap } from "../../../state/features/videoSlice.ts"; import { addToHashMap } from "../../../state/features/videoSlice.ts";
import AttachFileIcon from "@mui/icons-material/AttachFile"; import AttachFileIcon from "@mui/icons-material/AttachFile";
import DownloadIcon from "@mui/icons-material/Download"; import DownloadIcon from "@mui/icons-material/Download";
import DeletedVideo from "../../../assets/img/DeletedVideo.jpg";
import mockImg from "../../../test/mockimg.jpg"; import mockImg from "../../../test/mockimg.jpg";
import { import {
@ -403,7 +405,7 @@ export const VideoContent = () => {
width: "70vw", width: "70vw",
}} }}
> >
{videoReference && ( {videoReference ? (
<VideoPlayer <VideoPlayer
name={videoReference?.name} name={videoReference?.name}
service={videoReference?.service} service={videoReference?.service}
@ -414,6 +416,8 @@ export const VideoContent = () => {
customStyle={{ aspectRatio: "16/9" }} customStyle={{ aspectRatio: "16/9" }}
ref={containerRef} ref={containerRef}
/> />
) : (
<img src={DeletedVideo} width={"100%"} height={"100%"} />
)} )}
<Box <Box
sx={{ sx={{
@ -630,6 +634,7 @@ export const VideoContent = () => {
</Box> </Box>
</VideoPlayerContainer> </VideoPlayerContainer>
<SuperLikesSection <SuperLikesSection
/* eslint-disable-next-line @typescript-eslint/no-empty-function */
getMore={() => {}} getMore={() => {}}
loadingSuperLikes={loadingSuperLikes} loadingSuperLikes={loadingSuperLikes}
superlikes={superlikeList} superlikes={superlikeList}

22
src/pages/Home/VideoList.tsx

@ -6,7 +6,12 @@ import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { PlaylistSVG } from "../../assets/svgs/PlaylistSVG.tsx"; import { PlaylistSVG } from "../../assets/svgs/PlaylistSVG.tsx";
import ResponsiveImage from "../../components/ResponsiveImage.tsx"; import ResponsiveImage from "../../components/ResponsiveImage.tsx";
import { blockUser, setEditPlaylist, setEditVideo, Video } from "../../state/features/videoSlice.ts"; import {
blockUser,
setEditPlaylist,
setEditVideo,
Video,
} from "../../state/features/videoSlice.ts";
import { RootState } from "../../state/store.ts"; import { RootState } from "../../state/store.ts";
import { formatDate } from "../../utils/time.ts"; import { formatDate } from "../../utils/time.ts";
import { VideoCardImageContainer } from "./VideoCardImageContainer.tsx"; import { VideoCardImageContainer } from "./VideoCardImageContainer.tsx";
@ -55,16 +60,14 @@ export const VideoList = ({ videos }: VideoListProps) => {
if (response === true) { if (response === true) {
dispatch(blockUser(user)); dispatch(blockUser(user));
} }
} catch (error) {console.log(error)} } catch (error) {
console.log(error);
}
}; };
const filteredVideos = useMemo(() => {
return videos.filter((video: Video) => hashMapVideos[`${video.id}-${video.user}`]?.isValid);
}, [videos, hashMapVideos]);
return ( return (
<VideoCardContainer> <VideoCardContainer>
{filteredVideos.map((video: any) => { {videos.map((video: any) => {
const fullId = video ? `${video.id}-${video.user}` : undefined; const fullId = video ? `${video.id}-${video.user}` : undefined;
const existingVideo = hashMapVideos[fullId]; const existingVideo = hashMapVideos[fullId];
let hasHash = false; let hasHash = false;
@ -244,11 +247,6 @@ export const VideoList = ({ videos }: VideoListProps) => {
videoImage={videoObj.videoImage} videoImage={videoObj.videoImage}
frameImages={videoObj?.extracts || []} frameImages={videoObj?.extracts || []}
/> />
{/* <ResponsiveImage
src={videoObj.videoImage}
width={266}
height={150}
/> */}
<VideoCardTitle>{videoObj.title}</VideoCardTitle> <VideoCardTitle>{videoObj.title}</VideoCardTitle>
<BottomParent> <BottomParent>
<NameContainer <NameContainer

1
src/state/store.ts

@ -1,3 +1,4 @@
/* eslint-disable */
import { combineReducers, configureStore } from "@reduxjs/toolkit"; import { combineReducers, configureStore } from "@reduxjs/toolkit";
import notificationsReducer from "./features/notificationsSlice"; import notificationsReducer from "./features/notificationsSlice";
import authReducer from "./features/authSlice"; import authReducer from "./features/authSlice";

35
src/utils/fetchVideos.ts

@ -1,36 +1,35 @@
import { checkStructure } from './checkStructure' import { checkStructure } from "./checkStructure";
export const fetchAndEvaluateVideos = async (data: any) => { export const fetchAndEvaluateVideos = async (data: any) => {
const getVideo = async () => { const getVideo = async () => {
const { user, videoId, content } = data const { user, videoId, content } = data;
let obj: any = { let obj: any = {
...content, ...content,
isValid: false };
}
if (!user || !videoId) return obj if (!user || !videoId) return obj;
try { try {
const responseData = await qortalRequest({ const responseData = await qortalRequest({
action: 'FETCH_QDN_RESOURCE', action: "FETCH_QDN_RESOURCE",
name: user, name: user,
service: content?.service || 'DOCUMENT', service: content?.service || "DOCUMENT",
identifier: videoId identifier: videoId,
}) });
if (responseData) { if (responseData) {
obj = { obj = {
...content, ...content,
...responseData, ...responseData,
isValid: true isValid: true,
} isDeleted: false,
};
} }
return obj return obj;
} catch (error: any) { } catch (error: any) {
throw new Error(error?.message || 'error') throw new Error(error?.message || "error");
} }
} };
const res = await getVideo() const res = await getVideo();
return res return res;
} };

Loading…
Cancel
Save