Browse Source

Updates to User Interface

Layout of VideoContent.tsx and PlaylistContent.tsx updated, so it will feel more familiar to users.

Video Description boxes will not show the expand/contract button if the contracted description shows all text. The height of the contracted description is doubled.

Deleted Video Image no longer appears in VideoContent.tsx until after the video is loaded.

A new hotkey 'o' on the Video Player lets users switch between maintaining aspect ratio or filling all available space

Description and file downloader don't appear if video is deleted

In PlaylistContent.tsx and VideoContent.tsx, clicking anywhere other than the description or commentEditors will focus the video so that hotkeys will work on it
pull/35/head
Qortal Dev 1 month ago
parent
commit
a16639be84
  1. 3
      src/components/Publish/PublishVideo/PublishVideo-styles.tsx
  2. 18
      src/components/common/Comments/CommentSection.tsx
  3. 8
      src/components/common/Comments/Comments-styles.tsx
  4. 20
      src/components/common/Notifications/Notifications.tsx
  5. 6
      src/components/common/SuperLikesList/Comments-styles.tsx
  6. 24
      src/components/common/SuperLikesList/SuperLikesSection.tsx
  7. 23
      src/components/common/VideoPlayer/VideoPlayer.tsx
  8. 1
      src/pages/ContentPages/PlaylistContent/PlaylistContent-styles.tsx
  9. 69
      src/pages/ContentPages/PlaylistContent/PlaylistContent.tsx
  10. 56
      src/pages/ContentPages/VideoContent/VideoContent-functions.ts
  11. 11
      src/pages/ContentPages/VideoContent/VideoContent-styles.tsx
  12. 237
      src/pages/ContentPages/VideoContent/VideoContent.tsx
  13. 1
      src/state/features/persistSlice.ts
  14. 15
      src/wrappers/GlobalWrapper.tsx

3
src/components/Publish/PublishVideo/PublishVideo-styles.tsx

@ -175,8 +175,7 @@ export const CrowdfundTitle = styled(Typography)(({ theme }) => ({
export const CrowdfundSubTitleRow = styled(Box)({
display: "flex",
alignItems: "center",
justifyContent: "center",
width: "100%",
justifyContent: "start",
flexDirection: "row",
});

18
src/components/common/Comments/CommentSection.tsx

@ -28,8 +28,8 @@ interface CommentSectionProps {
const Panel = styled("div")`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
justify-content: start;
align-items: start;
width: 100%;
padding-bottom: 10px;
height: 100%;
@ -57,7 +57,7 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
const { user } = useSelector((state: RootState) => state.auth);
const [newMessages, setNewMessages] = useState(0);
const [loadingComments, setLoadingComments] = useState<boolean>(false);
// console.log("postId is: ", postId, " postName is: ", postName);
const onSubmit = (obj?: any, isEdit?: boolean) => {
if (isEdit) {
setListComments((prev: any[]) => {
@ -113,6 +113,7 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
)}_reply_${removeBaseCommentId.slice(
-6
)}&limit=0&includemetadata=false&offset=${offset}&reverse=false&excludeblocked=true`;
const response = await fetch(url, {
method: "GET",
headers: {
@ -120,6 +121,7 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
},
});
const responseData = await response.json();
const comments: any[] = [];
for (const comment of responseData) {
if (comment.identifier && comment.name) {
@ -163,6 +165,9 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
},
});
const responseData = await response.json();
// console.log("url is: ", url);
// console.log("response is: ", responseData);
let comments: any[] = [];
for (const comment of responseData) {
if (comment.identifier && comment.name) {
@ -222,18 +227,13 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
return (
<>
<Panel>
<CrowdfundSubTitleRow>
<CrowdfundSubTitle>Comments</CrowdfundSubTitle>
</CrowdfundSubTitleRow>
<CommentsContainer>
{loadingComments ? (
<NoCommentsRow>
<CircularProgress />
</NoCommentsRow>
) : listComments.length === 0 ? (
<NoCommentsRow>
There are no comments yet. Be the first to comment!
</NoCommentsRow>
<></>
) : (
<CommentContainer>
{structuredCommentList.map((comment: any) => {

8
src/components/common/Comments/Comments-styles.tsx

@ -93,7 +93,7 @@ export const StyledCardComment = styled(Typography)(({ theme }) => ({
fontWeight: 400,
color: theme.palette.text.primary,
fontSize: "19px",
wordBreak: "break-word"
wordBreak: "break-word",
}));
export const TitleText = styled(Typography)({
@ -159,7 +159,7 @@ export const BlockIconContainer = styled(Box)({
});
export const CommentsContainer = styled(Box)({
width: "90%",
width: "70%",
maxWidth: "1000px",
display: "flex",
flexDirection: "column",
@ -180,7 +180,7 @@ export const CommentContainer = styled(Box)({
export const NoCommentsRow = styled(Box)({
display: "flex",
alignItems: "center",
justifyContent: "center",
justifyContent: "start",
flex: "1",
padding: "10px 0px",
fontFamily: "Mulish",
@ -218,7 +218,7 @@ export const CommentActionButtonRow = styled(Box)({
export const CommentEditorContainer = styled(Box)({
width: "100%",
display: "flex",
justifyContent: "center",
justifyContent: "start",
});
export const CommentDateText = styled(Typography)(({ theme }) => ({

20
src/components/common/Notifications/Notifications.tsx

@ -16,15 +16,15 @@ import React, {
useState,
} from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../../../state/store";
import NotificationsIcon from "@mui/icons-material/Notifications";
import { formatDate } from "../../../utils/time";
import ThumbUpIcon from "@mui/icons-material/ThumbUp";
import {
extractSigValue,
getPaymentInfo,
isTimestampWithinRange,
} from "../../../pages/ContentPages/VideoContent/VideoContent";
} from "../../../pages/ContentPages/VideoContent/VideoContent-functions.ts";
import { RootState } from "../../../state/store";
import NotificationsIcon from "@mui/icons-material/Notifications";
import { formatDate } from "../../../utils/time";
import ThumbUpIcon from "@mui/icons-material/ThumbUp";
import { useNavigate } from "react-router-dom";
import localForage from "localforage";
import moment from "moment";
@ -148,7 +148,7 @@ export const Notifications = () => {
) {
let urlReference = null;
try {
let idForUrl = extractIdValue(comment?.metadata?.description);
const idForUrl = extractIdValue(comment?.metadata?.description);
const url = `/arbitrary/resources/search?mode=ALL&service=DOCUMENT&identifier=${idForUrl}&limit=1&includemetadata=false&reverse=false&excludeblocked=true&offset=0&name=${username}`;
const response2 = await fetch(url, {
method: "GET",
@ -160,7 +160,9 @@ export const Notifications = () => {
if (responseSearch.length > 0) {
urlReference = responseSearch[0];
}
} catch (error) {}
} catch (error) {
console.log(error);
}
// const url = `/arbitrary/BLOG_COMMENT/${comment.name}/${comment.identifier}`;
// const response = await fetch(url, {
// method: "GET",
@ -180,7 +182,9 @@ export const Notifications = () => {
},
];
}
} catch (error) {}
} catch (error) {
console.log(error);
}
}
}
setNotifications(prev => {

6
src/components/common/SuperLikesList/Comments-styles.tsx

@ -93,7 +93,7 @@ export const StyledCardComment = styled(Typography)(({ theme }) => ({
fontWeight: 400,
color: theme.palette.text.primary,
fontSize: "19px",
wordBreak: "break-word"
wordBreak: "break-word",
}));
export const TitleText = styled(Typography)({
@ -159,7 +159,7 @@ export const BlockIconContainer = styled(Box)({
});
export const CommentsContainer = styled(Box)({
width: "90%",
width: "70%",
maxWidth: "1000px",
display: "flex",
flexDirection: "column",
@ -180,7 +180,7 @@ export const CommentContainer = styled(Box)({
export const NoCommentsRow = styled(Box)({
display: "flex",
alignItems: "center",
justifyContent: "center",
justifyContent: "start",
flex: "1",
padding: "10px 0px",
fontFamily: "Mulish",

24
src/components/common/SuperLikesList/SuperLikesSection.tsx

@ -24,15 +24,15 @@ interface CommentSectionProps {
postId: string;
postName: string;
superlikes: any[];
getMore: () => void;
getMore?: () => void;
loadingSuperLikes: boolean;
}
const Panel = styled("div")`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
justify-content: start;
align-items: start;
width: 100%;
padding-bottom: 10px;
height: 100%;
@ -199,30 +199,18 @@ export const SuperLikesSection = ({
return (
<>
<Panel>
<CrowdfundSubTitleRow>
<CrowdfundSubTitle
sx={{
fontSize: "18px",
color: "gold",
}}
>
Super Likes
</CrowdfundSubTitle>
</CrowdfundSubTitleRow>
<CommentsContainer>
{loadingComments || loadingSuperLikes ? (
<NoCommentsRow>
<CircularProgress />
</NoCommentsRow>
) : listComments.length === 0 ? (
<NoCommentsRow>
There are no super likes yet. Be the first!
</NoCommentsRow>
<></>
) : (
<CommentContainer>
{structuredCommentList.map((comment: any) => {
let hasHash = false;
let message = { ...comment };
const message = { ...comment };
let hash = {};
if (hashMapSuperlikes[comment?.identifier]) {
message.message =
@ -249,7 +237,7 @@ export const SuperLikesSection = ({
<LoadMoreCommentsButtonRow>
<LoadMoreCommentsButton
onClick={() => {
getMore();
if (getMore) getMore();
}}
variant="contained"
size="small"

23
src/components/common/VideoPlayer/VideoPlayer.tsx

@ -34,7 +34,11 @@ import {
VideoElement,
} from "./VideoPlayer-styles.ts";
import CSS from "csstype";
import { setReduxPlaybackRate } from "../../../state/features/persistSlice.ts";
import {
setReduxPlaybackRate,
setStretchVideoSetting,
StretchVideoType,
} from "../../../state/features/persistSlice.ts";
export interface VideoStyles {
videoContainer?: CSS.Properties;
@ -101,6 +105,10 @@ export const VideoPlayer = React.forwardRef<refType, VideoPlayerProps>(
const [anchorEl, setAnchorEl] = useState(null);
const [showControlsFullScreen, setShowControlsFullScreen] =
useState<boolean>(true);
const [videoObjectFit, setVideoObjectFit] = useState<StretchVideoType>(
persistSelector.stretchVideoSetting
);
const videoPlaying = useSelector(
(state: RootState) => state.global.videoPlaying
);
@ -597,10 +605,21 @@ export const VideoPlayer = React.forwardRef<refType, VideoPlayerProps>(
}
};
const toggleStretchVideoSetting = () => {
const newStretchVideoSetting =
persistSelector.stretchVideoSetting === "contain" ? "fill" : "contain";
setVideoObjectFit(newStretchVideoSetting);
dispatch(setStretchVideoSetting(newStretchVideoSetting));
};
const keyboardShortcutsDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
e.preventDefault();
switch (e.key) {
case "o":
toggleStretchVideoSetting();
break;
case Key.Add:
increaseSpeed(false);
break;
@ -825,7 +844,7 @@ export const VideoPlayer = React.forwardRef<refType, VideoPlayerProps>(
startPlay
? {
...videoStyles?.video,
objectFit: persistSelector.stretchVideoSetting,
objectFit: videoObjectFit,
}
: { height: "100%", ...videoStyles }
}

1
src/pages/ContentPages/PlaylistContent/PlaylistContent-styles.tsx

@ -2,7 +2,6 @@ import { styled } from "@mui/system";
import { Box, Grid, Typography, Checkbox } from "@mui/material";
export const VideoPlayerContainer = styled(Box)(({ theme }) => ({
maxWidth: "95%",
display: "flex",
flexDirection: "column",
alignItems: "flex-start",

69
src/pages/ContentPages/PlaylistContent/PlaylistContent.tsx

@ -20,6 +20,11 @@ import AttachFileIcon from "@mui/icons-material/AttachFile";
import DownloadIcon from "@mui/icons-material/Download";
import mockImg from "../../../test/mockimg.jpg";
import {
extractSigValue,
getPaymentInfo,
isTimestampWithinRange,
} from "../VideoContent/VideoContent-functions.ts";
import {
AuthorTextComment,
FileAttachmentContainer,
@ -48,11 +53,6 @@ import { DisplayHtml } from "../../../components/common/TextEditor/DisplayHtml.t
import FileElement from "../../../components/common/FileElement.tsx";
import { SuperLike } from "../../../components/common/ContentButtons/SuperLike.tsx";
import { useFetchSuperLikes } from "../../../hooks/useFetchSuperLikes.tsx";
import {
extractSigValue,
getPaymentInfo,
isTimestampWithinRange,
} from "../VideoContent/VideoContent.tsx";
import { SuperLikesSection } from "../../../components/common/SuperLikesList/SuperLikesSection.tsx";
import {
QTUBE_VIDEO_BASE,
@ -196,6 +196,7 @@ export const PlaylistContent = () => {
setVideoData(combinedData);
dispatch(addToHashMap(combinedData));
checkforPlaylist(name, id);
}
}
@ -275,11 +276,8 @@ export const PlaylistContent = () => {
const fullId = vid ? `${vid.identifier}-${vid.name}` : undefined;
const existingVideo = hashMapVideos[fullId];
if (existingVideo) {
setVideoData(existingVideo);
} else {
getVideoData(vid?.name, vid?.identifier);
}
if (existingVideo) setVideoData(existingVideo);
else getVideoData(vid?.name, vid?.identifier);
}
}
}
@ -298,13 +296,12 @@ export const PlaylistContent = () => {
}
}, [id, channelName]);
const descriptionThreshold = 200;
useEffect(() => {
if (contentRef.current) {
const height = contentRef.current.offsetHeight;
if (height > 100) {
// Assuming 100px is your threshold
setDescriptionHeight(100);
}
if (height > descriptionThreshold)
setDescriptionHeight(descriptionThreshold);
}
}, [videoData]);
@ -409,13 +406,27 @@ export const PlaylistContent = () => {
}, [getComments, videoData?.id, nameAddress]);
const focusVideo = (e: React.MouseEvent<HTMLDivElement>) => {
console.log("in focusVideo");
const target = e.target as Element;
const textTagNames = ["TEXTAREA", "P", "H[1-6]", "STRONG", "svg", "A"];
const noText =
textTagNames.findIndex(s => {
return target?.tagName.match(s);
}) < 0;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const clickOnEmptySpace = !target?.onclick && noText;
console.log("tagName is: ", target?.tagName);
if (target == e.currentTarget || clickOnEmptySpace) {
console.log("in correctTarget");
const focusRef = containerRef.current?.getContainerRef()?.current;
const isCorrectTarget = e.currentTarget == e.target;
if (focusRef && isCorrectTarget) {
focusRef.focus({ preventScroll: true });
}
};
return (
<Box
sx={{
@ -423,6 +434,7 @@ export const PlaylistContent = () => {
alignItems: "center",
flexDirection: "column",
padding: "0px 10px",
marginLeft: "5%",
}}
onClick={focusVideo}
>
@ -492,7 +504,6 @@ export const PlaylistContent = () => {
gridTemplateColumns: "1fr 1fr",
}}
>
{" "}
<Box>
<StyledCardHeaderComment
sx={{
@ -627,6 +638,7 @@ export const PlaylistContent = () => {
)}
<Spacer height="30px" />
{videoData?.fullDescription && (
<Box
sx={{
background: "#333333",
@ -671,7 +683,7 @@ export const PlaylistContent = () => {
? "auto"
: isExpandedDescription
? "auto"
: "100px",
: `${descriptionHeight}px`,
overflow: "hidden",
}}
>
@ -689,7 +701,7 @@ export const PlaylistContent = () => {
</VideoDescription>
)}
</Box>
{descriptionHeight && (
{descriptionHeight >= descriptionThreshold && (
<Typography
onClick={() => {
setIsExpandedDescription(prev => !prev);
@ -706,29 +718,24 @@ export const PlaylistContent = () => {
</Typography>
)}
</Box>
)}
</>
)}
</VideoPlayerContainer>
{videoData?.id && videoData?.user && (
<SuperLikesSection
getMore={() => {}}
loadingSuperLikes={loadingSuperLikes}
superlikes={superlikeList}
postId={videoData?.id || ""}
postName={videoData?.user || ""}
/>
<Box
sx={{
display: "flex",
gap: "20px",
width: "100%",
maxWidth: "1200px",
}}
>
)}
{videoData?.id && channelName && (
<CommentSection
postId={videoData?.id || ""}
postName={channelName || ""}
/>
</Box>
)}
</VideoPlayerContainer>
</Box>
);
};

56
src/pages/ContentPages/VideoContent/VideoContent-functions.ts

@ -0,0 +1,56 @@
export function isTimestampWithinRange(resTimestamp, resCreated) {
// Calculate the absolute difference in milliseconds
const difference = Math.abs(resTimestamp - resCreated);
// 2 minutes in milliseconds
const twoMinutesInMilliseconds = 3 * 60 * 1000;
// Check if the difference is within 2 minutes
return difference <= twoMinutesInMilliseconds;
}
export function extractSigValue(metadescription) {
// Function to extract the substring within double asterisks
function extractSubstring(str) {
const match = str.match(/\*\*(.*?)\*\*/);
return match ? match[1] : null;
}
// Function to extract the 'sig' value
function extractSig(str) {
const regex = /sig:(.*?)(;|$)/;
const match = str.match(regex);
return match ? match[1] : null;
}
// Extracting the relevant substring
const relevantSubstring = extractSubstring(metadescription);
if (relevantSubstring) {
// Extracting the 'sig' value
return extractSig(relevantSubstring);
} else {
return null;
}
}
export const getPaymentInfo = async (signature: string) => {
try {
const url = `/transactions/signature/${signature}`;
const response = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
// Coin payment info must be added to responseData so we can display it to the user
const responseData = await response.json();
if (responseData && !responseData.error) {
return responseData;
} else {
throw new Error("unable to get payment");
}
} catch (error) {
throw new Error("unable to get payment");
}
};

11
src/pages/ContentPages/VideoContent/VideoContent-styles.tsx

@ -1,12 +1,15 @@
import { styled } from "@mui/system";
import { Box, Grid, Typography, Checkbox } from "@mui/material";
export const VideoPlayerContainer = styled(Box)(({ theme }) => ({
maxWidth: "95%",
width: "1000px",
export const VideoContentContainer = styled(Box)(({ theme }) => ({
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
alignItems: "start",
}));
export const VideoPlayerContainer = styled(Box)(({ theme }) => ({
width: "55vw",
marginLeft: "5%",
}));
export const VideoTitle = styled(Typography)(({ theme }) => ({

237
src/pages/ContentPages/VideoContent/VideoContent.tsx

@ -1,26 +1,45 @@
import DownloadIcon from "@mui/icons-material/Download";
import { Avatar, Box, Typography, useTheme } from "@mui/material";
import React, {
useState,
useCallback,
useEffect,
useMemo,
useRef,
useEffect,
useCallback,
useState,
} from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router-dom";
import ResponsiveImage from "../../../components/ResponsiveImage.tsx";
import { setIsLoadingGlobal } from "../../../state/features/globalSlice.ts";
import { Avatar, Box, Typography, useTheme } from "@mui/material";
import DeletedVideo from "../../../assets/img/DeletedVideo.jpg";
import { CommentSection } from "../../../components/common/Comments/CommentSection.tsx";
import { FollowButton } from "../../../components/common/ContentButtons/FollowButton.tsx";
import { LikeAndDislike } from "../../../components/common/ContentButtons/LikeAndDislike.tsx";
import { SubscribeButton } from "../../../components/common/ContentButtons/SubscribeButton.tsx";
import { SuperLike } from "../../../components/common/ContentButtons/SuperLike.tsx";
import FileElement from "../../../components/common/FileElement.tsx";
import { SuperLikesSection } from "../../../components/common/SuperLikesList/SuperLikesSection.tsx";
import { DisplayHtml } from "../../../components/common/TextEditor/DisplayHtml.tsx";
import {
refType,
VideoPlayer,
} from "../../../components/common/VideoPlayer/VideoPlayer.tsx";
import { RootState } from "../../../state/store.ts";
import {
QTUBE_VIDEO_BASE,
SUPER_LIKE_BASE,
} from "../../../constants/Identifiers.ts";
import {
minPriceSuperlike,
titleFormatterOnSave,
} from "../../../constants/Misc.ts";
import { useFetchSuperLikes } from "../../../hooks/useFetchSuperLikes.tsx";
import { setIsLoadingGlobal } from "../../../state/features/globalSlice.ts";
import { addToHashMap } from "../../../state/features/videoSlice.ts";
import AttachFileIcon from "@mui/icons-material/AttachFile";
import DownloadIcon from "@mui/icons-material/Download";
import DeletedVideo from "../../../assets/img/DeletedVideo.jpg";
import mockImg from "../../../test/mockimg.jpg";
import { RootState } from "../../../state/store.ts";
import { formatDate } from "../../../utils/time.ts";
import {
extractSigValue,
getPaymentInfo,
isTimestampWithinRange,
} from "./VideoContent-functions.ts";
import {
AuthorTextComment,
FileAttachmentContainer,
@ -29,98 +48,10 @@ import {
StyledCardColComment,
StyledCardHeaderComment,
VideoDescription,
VideoPlayerContainer,
VideoContentContainer,
VideoTitle,
VideoPlayerContainer,
} from "./VideoContent-styles.tsx";
import { setUserAvatarHash } from "../../../state/features/globalSlice.ts";
import {
formatDate,
formatDateSeconds,
formatTimestampSeconds,
} from "../../../utils/time.ts";
import { NavbarName } from "../../../components/layout/Navbar/Navbar-styles.tsx";
import { CommentSection } from "../../../components/common/Comments/CommentSection.tsx";
import {
CrowdfundSubTitle,
CrowdfundSubTitleRow,
} from "../../../components/Publish/PublishVideo/PublishVideo-styles.tsx";
import { Playlists } from "../../../components/Playlists/Playlists.tsx";
import { DisplayHtml } from "../../../components/common/TextEditor/DisplayHtml.tsx";
import FileElement from "../../../components/common/FileElement.tsx";
import { SuperLike } from "../../../components/common/ContentButtons/SuperLike.tsx";
import { CommentContainer } from "../../../components/common/Comments/Comments-styles.tsx";
import { Comment } from "../../../components/common/Comments/Comment.tsx";
import { SuperLikesSection } from "../../../components/common/SuperLikesList/SuperLikesSection.tsx";
import { useFetchSuperLikes } from "../../../hooks/useFetchSuperLikes.tsx";
import {
FOR_SUPER_LIKE,
QTUBE_VIDEO_BASE,
SUPER_LIKE_BASE,
} from "../../../constants/Identifiers.ts";
import {
minPriceSuperlike,
titleFormatterOnSave,
} from "../../../constants/Misc.ts";
import { SubscribeButton } from "../../../components/common/ContentButtons/SubscribeButton.tsx";
import { FollowButton } from "../../../components/common/ContentButtons/FollowButton.tsx";
import { LikeAndDislike } from "../../../components/common/ContentButtons/LikeAndDislike.tsx";
export function isTimestampWithinRange(resTimestamp, resCreated) {
// Calculate the absolute difference in milliseconds
const difference = Math.abs(resTimestamp - resCreated);
// 2 minutes in milliseconds
const twoMinutesInMilliseconds = 3 * 60 * 1000;
// Check if the difference is within 2 minutes
return difference <= twoMinutesInMilliseconds;
}
export function extractSigValue(metadescription) {
// Function to extract the substring within double asterisks
function extractSubstring(str) {
const match = str.match(/\*\*(.*?)\*\*/);
return match ? match[1] : null;
}
// Function to extract the 'sig' value
function extractSig(str) {
const regex = /sig:(.*?)(;|$)/;
const match = str.match(regex);
return match ? match[1] : null;
}
// Extracting the relevant substring
const relevantSubstring = extractSubstring(metadescription);
if (relevantSubstring) {
// Extracting the 'sig' value
return extractSig(relevantSubstring);
} else {
return null;
}
}
export const getPaymentInfo = async (signature: string) => {
try {
const url = `/transactions/signature/${signature}`;
const response = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
// Coin payment info must be added to responseData so we can display it to the user
const responseData = await response.json();
if (responseData && !responseData.error) {
return responseData;
} else {
throw new Error("unable to get payment");
}
} catch (error) {
throw new Error("unable to get payment");
}
};
export const VideoContent = () => {
const { name: channelName, id } = useParams();
@ -130,6 +61,7 @@ export const VideoContent = () => {
useState<boolean>(false);
const [superlikeList, setSuperlikelist] = useState<any[]>([]);
const [loadingSuperLikes, setLoadingSuperLikes] = useState<boolean>(false);
const { addSuperlikeRawDataGetToList } = useFetchSuperLikes();
const containerRef = useRef<refType>(null);
@ -149,6 +81,8 @@ export const VideoContent = () => {
const [descriptionHeight, setDescriptionHeight] = useState<null | number>(
null
);
const [videoData, setVideoData] = useState<any>(null);
const [isVideoLoaded, setIsVideoLoaded] = useState<boolean>(false);
const userAvatarHash = useSelector(
(state: RootState) => state.global.userAvatarHash
@ -183,8 +117,6 @@ export const VideoContent = () => {
const navigate = useNavigate();
const theme = useTheme();
const [videoData, setVideoData] = useState<any>(null);
const saveAsFilename = useMemo(() => {
// nb. we prefer to construct the local filename to use for
// saving, from the video "title" when possible
@ -224,6 +156,7 @@ export const VideoContent = () => {
videoReference?.name &&
videoReference?.service
) {
setIsVideoLoaded(true);
return videoReference;
} else {
return null;
@ -302,13 +235,12 @@ export const VideoContent = () => {
}
}, [id, channelName]);
const descriptionThreshold = 200;
useEffect(() => {
if (contentRef.current) {
const height = contentRef.current.offsetHeight;
if (height > 100) {
// Assuming 100px is your threshold
setDescriptionHeight(100);
}
if (height > descriptionThreshold)
setDescriptionHeight(descriptionThreshold);
}
}, [videoData]);
@ -382,35 +314,42 @@ export const VideoContent = () => {
);
const focusVideo = (e: React.MouseEvent<HTMLDivElement>) => {
console.log("in focusVideo");
const target = e.target as Element;
const textTagNames = ["TEXTAREA", "P", "H[1-6]", "STRONG", "svg", "A"];
const noText =
textTagNames.findIndex(s => {
return target?.tagName.match(s);
}) < 0;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const clickOnEmptySpace = !target?.onclick && noText;
console.log("tagName is: ", target?.tagName);
// clicking on link in superlikes bar shows deleted video when loading
if (target == e.currentTarget || clickOnEmptySpace) {
console.log("in correctTarget");
const focusRef = containerRef.current?.getContainerRef()?.current;
const isCorrectTarget = e.currentTarget == e.target;
if (focusRef && isCorrectTarget) {
focusRef.focus({ preventScroll: true });
}
};
return (
<>
<Box
sx={{
display: "flex",
alignItems: "center",
marginLeft: "5%",
flexDirection: "column",
padding: "0px 10px",
}}
onClick={focusVideo}
>
<VideoPlayerContainer
sx={{
width: "55vw",
aspectRatio: "16/9",
}}
>
{videoReference ? (
<Box
sx={{
aspectRatio: "16/9",
}}
>
<VideoPlayerContainer>
<VideoPlayer
name={videoReference?.name}
service={videoReference?.service}
@ -424,13 +363,21 @@ export const VideoContent = () => {
video: { aspectRatio: "16 / 9" },
}}
/>
</Box>
</VideoPlayerContainer>
) : isVideoLoaded ? (
<img
src={DeletedVideo}
width={"70%"}
height={"37%"}
style={{ marginLeft: "5%" }}
/>
) : (
<img src={DeletedVideo} width={"100%"} height={"100%"} />
<Box sx={{ width: "55vw", aspectRatio: "16/9" }}></Box>
)}
<VideoContentContainer>
<Box
sx={{
width: "100%",
width: "80%",
display: "grid",
gridTemplateColumns: "1fr 1fr",
marginTop: "15px",
@ -512,6 +459,7 @@ export const VideoContent = () => {
/>
</>
)}
{videoData?.filename && (
<FileAttachmentContainer>
<FileAttachmentFont>Save to Disk</FileAttachmentFont>
<FileElement
@ -520,7 +468,9 @@ export const VideoContent = () => {
filename: saveAsFilename,
mimeType: videoData?.videoType || '"video/mp4',
}}
title={videoData?.filename || videoData?.title?.slice(0, 20)}
title={
videoData?.filename || videoData?.title?.slice(0, 20)
}
customStyles={{
display: "flex",
alignItems: "center",
@ -530,6 +480,7 @@ export const VideoContent = () => {
<DownloadIcon />
</FileElement>
</FileAttachmentContainer>
)}
</Box>
</Box>
<Box
@ -566,21 +517,28 @@ export const VideoContent = () => {
)}
<Spacer height="30px" />
{videoData?.fullDescription && (
<Box
sx={{
background: "#333333",
borderRadius: "5px",
padding: "5px",
width: "100%",
width: "70%",
cursor: !descriptionHeight
? "default"
: isExpandedDescription
? "default"
: "pointer",
position: "relative",
marginBottom: "30px",
}}
className={
!descriptionHeight ? "" : isExpandedDescription ? "" : "hover-click"
!descriptionHeight
? ""
: isExpandedDescription
? ""
: "hover-click"
}
>
{descriptionHeight && !isExpandedDescription && (
@ -606,7 +564,7 @@ export const VideoContent = () => {
? "auto"
: isExpandedDescription
? "auto"
: "100px",
: "200px",
overflow: "hidden",
}}
>
@ -624,7 +582,7 @@ export const VideoContent = () => {
</VideoDescription>
)}
</Box>
{descriptionHeight && (
{descriptionHeight >= descriptionThreshold && (
<Typography
onClick={() => {
setIsExpandedDescription(prev => !prev);
@ -641,7 +599,10 @@ export const VideoContent = () => {
</Typography>
)}
</Box>
</VideoPlayerContainer>
)}
{id && channelName && (
<>
<SuperLikesSection
/* eslint-disable-next-line @typescript-eslint/no-empty-function */
getMore={() => {}}
@ -650,17 +611,11 @@ export const VideoContent = () => {
postId={id || ""}
postName={channelName || ""}
/>
<Box
sx={{
display: "flex",
gap: "20px",
width: "100%",
maxWidth: "1200px",
}}
>
<CommentSection postId={id || ""} postName={channelName || ""} />
</>
)}
</VideoContentContainer>
</Box>
</Box>
</>
);
};

1
src/state/features/persistSlice.ts

@ -77,6 +77,7 @@ export const persistSlice = createSlice({
export const {
setHomePageSelectedTab,
setStretchVideoSetting,
subscribe,
unSubscribe,
setReduxPlaybackRate,

15
src/wrappers/GlobalWrapper.tsx

@ -6,6 +6,11 @@ import React, {
useMemo,
} from "react";
import { useDispatch, useSelector } from "react-redux";
import {
extractSigValue,
getPaymentInfo,
isTimestampWithinRange,
} from "../pages/ContentPages/VideoContent/VideoContent-functions.ts";
import { addUser } from "../state/features/authSlice";
import NavBar from "../components/layout/Navbar/Navbar";
@ -21,11 +26,6 @@ import { RequestQueue } from "../utils/queue";
import { EditVideo } from "../components/Publish/EditVideo/EditVideo";
import { EditPlaylist } from "../components/Publish/EditPlaylist/EditPlaylist";
import ConsentModal from "../components/common/ConsentModal";
import {
extractSigValue,
getPaymentInfo,
isTimestampWithinRange,
} from "../pages/ContentPages/VideoContent/VideoContent";
import { useFetchSuperLikes } from "../hooks/useFetchSuperLikes";
import { SUPER_LIKE_BASE } from "../constants/Identifiers.ts";
import { minPriceSuperlike } from "../constants/Misc.ts";
@ -185,7 +185,9 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
];
validCount++;
}
} catch (error) {}
} catch (error) {
console.log(error);
}
}
}
}
@ -194,7 +196,6 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
dispatch(setSuperlikesAll(comments));
} catch (error) {
console.error(error);
} finally {
}
}, []);

Loading…
Cancel
Save