3
0
mirror of https://github.com/Qortal/q-tube.git synced 2025-02-11 17:55:51 +00:00

Merged Phil's new MultiplePublishAll component into main branch

This commit is contained in:
Qortal Dev 2024-01-15 14:11:22 -07:00
parent 8d3549739c
commit 3d1d4b2053
6 changed files with 361 additions and 232 deletions

View File

@ -47,7 +47,7 @@ import {
} from "../../state/features/videoSlice";
import ImageUploader from "../common/ImageUploader";
import { categories, subCategories } from "../../constants/Categories.ts";
import { MultiplePublish } from "../common/MultiplePublish/MultiplePublish";
import { MultiplePublish } from "../common/MultiplePublish/MultiplePublishAll";
import { TextEditor } from "../common/TextEditor/TextEditor";
import { extractTextFromHTML } from "../common/TextEditor/utils";
import { toBase64 } from "../PublishVideo/PublishVideo.tsx";
@ -83,7 +83,7 @@ export const EditVideo = () => {
const editVideoProperties = useSelector(
(state: RootState) => state.video.editVideoProperties
);
const [publishes, setPublishes] = useState<any[]>([]);
const [publishes, setPublishes] = useState<any>(null);
const [isOpenMultiplePublish, setIsOpenMultiplePublish] = useState(false);
const [videoPropertiesToSetToRedux, setVideoPropertiesToSetToRedux] =
useState(null);
@ -322,7 +322,11 @@ export const EditVideo = () => {
listOfPublishes.push(requestBodyVideo);
}
setPublishes(listOfPublishes);
const multiplePublish = {
action: "PUBLISH_MULTIPLE_QDN_RESOURCES",
resources: [...listOfPublishes],
};
setPublishes(multiplePublish);
setIsOpenMultiplePublish(true);
setVideoPropertiesToSetToRedux({
...editVideoProperties,
@ -596,6 +600,18 @@ export const EditVideo = () => {
{isOpenMultiplePublish && (
<MultiplePublish
isOpen={isOpenMultiplePublish}
onError={messageNotification => {
setIsOpenMultiplePublish(false);
setPublishes(null);
if (messageNotification) {
dispatch(
setNotification({
msg: messageNotification,
alertType: "error",
})
);
}
}}
onSubmit={() => {
setIsOpenMultiplePublish(false);
const clonedCopy = structuredClone(videoPropertiesToSetToRedux);

View File

@ -46,7 +46,7 @@ import {
} from "../../state/features/videoSlice";
import ImageUploader from "../common/ImageUploader";
import { categories, subCategories } from "../../constants/Categories.ts";
import { MultiplePublish } from "../common/MultiplePublish/MultiplePublish";
import { MultiplePublish } from "../common/MultiplePublish/MultiplePublishAll";
import {
CrowdfundSubTitle,
CrowdfundSubTitleRow,
@ -130,7 +130,7 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
useState<any>(null);
const [playlistSetting, setPlaylistSetting] = useState<null | string>(null);
const [publishes, setPublishes] = useState<any[]>([]);
const [publishes, setPublishes] = useState<any>(null);
const [isCheckTitleByFile, setIsCheckTitleByFile] = useState(true);
const [isCheckSameCoverImage, setIsCheckSameCoverImage] = useState(true);
const [isCheckDescriptionIsTitle, setIsCheckDescriptionIsTitle] =
@ -469,7 +469,11 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
}
}
setPublishes(listOfPublishes);
const multiplePublish = {
action: "PUBLISH_MULTIPLE_QDN_RESOURCES",
resources: [...listOfPublishes],
};
setPublishes(multiplePublish);
setIsOpenMultiplePublish(true);
} catch (error: any) {
let notificationObj: any = null;
@ -1250,6 +1254,18 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
{isOpenMultiplePublish && (
<MultiplePublish
isOpen={isOpenMultiplePublish}
onError={messageNotification => {
setIsOpenMultiplePublish(false);
setPublishes(null);
if (messageNotification) {
dispatch(
setNotification({
msg: messageNotification,
alertType: "error",
})
);
}
}}
onSubmit={() => {
setIsOpenMultiplePublish(false);
setIsOpen(false);

View File

@ -11,8 +11,8 @@ 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) => {
import EmojiEventsIcon from "@mui/icons-material/EmojiEvents";
const truncateMessage = message => {
return message.length > 40 ? message.slice(0, 40) + "..." : message;
};
@ -28,18 +28,16 @@ export default function ListSuperLikes({ superlikes }) {
// let hasHash = false
let message = "";
let url = "";
let forName = ""
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
forName = info?.name;
url = `/video/${info?.name}/${info?.identifier}`;
}
@ -57,7 +55,7 @@ export default function ListSuperLikes({ superlikes }) {
alignItems="flex-start"
sx={{
cursor: url ? "pointer" : "default",
minHeight: '130px'
minHeight: "130px",
}}
onClick={async () => {
if (url) {
@ -65,79 +63,86 @@ export default function ListSuperLikes({ superlikes }) {
}
}}
>
<Box sx={{
width: '100%'
}}>
<ListItem
sx={{
padding: '0px'
}}
alignItems="flex-start"
>
<ListItemAvatar>
<Avatar
alt="Remy Sharp"
src={`/arbitrary/THUMBNAIL/${superlike?.name}/qortal_avatar`}
/>
</ListItemAvatar>
<ListItemText
primary={
<Box
sx={{
width: "100%",
}}
>
<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",
wordBreak: "break-word",
fontSize: "16px",
}}
component="span"
variant="body2"
color="text.primary"
>
{superlike?.name}
</Typography>
{` - ${truncateMessage(message)}`}
</Box>
}
/>
</ListItem>
{forName && (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "5px",
fontSize: "16px",
fontSize: "17px",
gap: "10px",
justifyContent: "flex-end",
}}
>
<ThumbUpIcon
style={{
color: "gold",
}}
/>
<Typography
sx={{
fontSize: "18px",
}}
>
{amount ? amount : ""} QORT
</Typography>
<EmojiEventsIcon />
{forName}
</Box>
}
secondary={
<Box sx={{
fontSize: '15px'
}}>
<Typography
sx={{ display: "inline", wordBreak: "break-word", fontSize: '16px'}}
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>
)}
</Box>
</ListItem>
<Box
sx={{

View File

@ -1,149 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
Box,
Button,
CircularProgress,
Modal,
Typography,
useTheme,
} from "@mui/material";
import React, { useCallback, useEffect, useState, useRef } from "react";
import { ModalBody } from "../../PublishVideo/PublishVideo-styles.tsx";
import { CircleSVG } from "../../../assets/svgs/CircleSVG";
import { EmptyCircleSVG } from "../../../assets/svgs/EmptyCircleSVG";
export const MultiplePublish = ({ publishes, isOpen, onSubmit }) => {
const theme = useTheme();
const listOfSuccessfulPublishesRef = useRef([]);
const [listOfSuccessfulPublishes, setListOfSuccessfulPublishes] = useState<
any[]
>([]);
const [currentlyInPublish, setCurrentlyInPublish] = useState(null);
const hasStarted = useRef(false);
const publish = useCallback(async (pub: any) => {
await qortalRequest(pub);
}, []);
const [isPublishing, setIsPublishing] = useState(true);
const handlePublish = useCallback(
async (pub: any) => {
try {
setCurrentlyInPublish(pub?.identifier);
await publish(pub);
setListOfSuccessfulPublishes((prev: any) => [...prev, pub?.identifier]);
listOfSuccessfulPublishesRef.current = [
...listOfSuccessfulPublishesRef.current,
pub?.identifier,
];
} catch (error) {
console.log({ error });
await new Promise<void>(res => {
setTimeout(() => {
res();
}, 5000);
});
// await handlePublish(pub);
}
},
[publish]
);
const startPublish = useCallback(
async (pubs: any) => {
setIsPublishing(true);
const filterPubs = pubs.filter(
pub => !listOfSuccessfulPublishesRef.current.includes(pub.identifier)
);
for (const pub of filterPubs) {
await handlePublish(pub);
}
if (listOfSuccessfulPublishesRef.current.length === pubs.length) {
onSubmit();
}
setIsPublishing(false);
},
[handlePublish, onSubmit, listOfSuccessfulPublishes, publishes]
);
useEffect(() => {
if (publishes && !hasStarted.current) {
hasStarted.current = true;
startPublish(publishes);
}
}, [startPublish, publishes, listOfSuccessfulPublishes]);
return (
<Modal
open={isOpen}
aria-labelledby="modal-title"
aria-describedby="modal-description"
>
<ModalBody
sx={{
minHeight: "50vh",
}}
>
{publishes.map((publish: any) => {
return (
<Box
sx={{
display: "flex",
gap: "20px",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography>{publish?.title}</Typography>
{publish?.identifier === currentlyInPublish ? (
<CircularProgress
size={20}
thickness={2}
sx={{
color: theme.palette.secondary.main,
}}
/>
) : listOfSuccessfulPublishes.includes(publish.identifier) ? (
<CircleSVG
color={theme.palette.text.primary}
height="24px"
width="24px"
/>
) : (
<EmptyCircleSVG
color={theme.palette.text.primary}
height="24px"
width="24px"
/>
)}
</Box>
);
})}
{!isPublishing &&
listOfSuccessfulPublishes.length !== publishes.length && (
<>
<Typography
sx={{
marginTop: "20px",
fontSize: "16px",
}}
>
Some files were not published. Please try again. It's important
that all the files get published. Maybe wait a couple minutes if
the error keeps occurring
</Typography>
<Button
onClick={() => {
startPublish(publishes);
}}
>
Try again
</Button>
</>
)}
</ModalBody>
</Modal>
);
};

View File

@ -0,0 +1,224 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
Box,
Button,
CircularProgress,
Modal,
Typography,
useTheme,
} from "@mui/material";
import React, { useCallback, useEffect, useState, useRef } from "react";
import { CircleSVG } from "../../../assets/svgs/CircleSVG";
import { EmptyCircleSVG } from "../../../assets/svgs/EmptyCircleSVG";
import { styled } from "@mui/system";
interface Publish {
resources: any[];
action: string;
}
interface MultiplePublishProps {
publishes: Publish;
isOpen: boolean;
onSubmit: () => void;
onError: (message?: string) => void;
}
export const MultiplePublish = ({
publishes,
isOpen,
onSubmit,
onError,
}: MultiplePublishProps) => {
const theme = useTheme();
const listOfSuccessfulPublishesRef = useRef([]);
const [listOfSuccessfulPublishes, setListOfSuccessfulPublishes] = useState<
any[]
>([]);
const [listOfUnsuccessfulPublishes, setListOfUnSuccessfulPublishes] =
useState<any[]>([]);
const [currentlyInPublish, setCurrentlyInPublish] = useState(null);
const hasStarted = useRef(false);
const publish = useCallback(async (pub: any) => {
const lengthOfResources = pub?.resources?.length;
const lengthOfTimeout = lengthOfResources * 30000;
return await qortalRequestWithTimeout(pub, lengthOfTimeout);
}, []);
const [isPublishing, setIsPublishing] = useState(true);
const handlePublish = useCallback(
async (pub: any) => {
try {
setCurrentlyInPublish(pub?.identifier);
setIsPublishing(true);
const res = await publish(pub);
onSubmit();
setListOfUnSuccessfulPublishes([]);
} catch (error: any) {
const unsuccessfulPublishes = error?.error?.unsuccessfulPublishes || [];
if (error?.error === "User declined request") {
onError();
return;
}
if (error?.error === "The request timed out") {
onError("The request timed out");
return;
}
if (unsuccessfulPublishes?.length > 0) {
setListOfUnSuccessfulPublishes(unsuccessfulPublishes);
}
} finally {
setIsPublishing(false);
}
},
[publish]
);
const retry = () => {
let newlistOfMultiplePublishes: any[] = [];
listOfUnsuccessfulPublishes?.forEach(item => {
const findPub = publishes?.resources.find(
(res: any) => res?.identifier === item.identifier
);
if (findPub) {
newlistOfMultiplePublishes.push(findPub);
}
});
const multiplePublish = {
...publishes,
resources: newlistOfMultiplePublishes,
};
handlePublish(multiplePublish);
};
const startPublish = useCallback(
async (pubs: any) => {
await handlePublish(pubs);
},
[handlePublish, onSubmit, listOfSuccessfulPublishes, publishes]
);
useEffect(() => {
if (publishes && !hasStarted.current) {
hasStarted.current = true;
startPublish(publishes);
}
}, [startPublish, publishes, listOfSuccessfulPublishes]);
return (
<Modal
open={isOpen}
aria-labelledby="modal-title"
aria-describedby="modal-description"
>
<ModalBody
sx={{
minHeight: "50vh",
}}
>
{publishes?.resources?.map((publish: any) => {
const unpublished = listOfUnsuccessfulPublishes.map(
item => item?.identifier
);
return (
<Box
sx={{
display: "flex",
gap: "20px",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Typography>{publish?.identifier}</Typography>
{!isPublishing && hasStarted.current ? (
<>
{!unpublished.includes(publish.identifier) ? (
<CircleSVG
color={theme.palette.text.primary}
height="24px"
width="24px"
/>
) : (
<EmptyCircleSVG
color={theme.palette.text.primary}
height="24px"
width="24px"
/>
)}
</>
) : (
<CircularProgress size={16} color="secondary" />
)}
</Box>
);
})}
{!isPublishing && listOfUnsuccessfulPublishes.length > 0 && (
<>
<Typography
sx={{
marginTop: "20px",
fontSize: "16px",
}}
>
Some files were not published. Please try again. It's important
that all the files get published. Maybe wait a couple minutes if
the error keeps occurring
</Typography>
<Button
variant="contained"
onClick={() => {
retry();
}}
>
Try again
</Button>
</>
)}
</ModalBody>
</Modal>
);
};
export const ModalBody = styled(Box)(({ theme }) => ({
position: "absolute",
backgroundColor: theme.palette.background.default,
borderRadius: "4px",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: "75%",
maxWidth: "900px",
padding: "15px 35px",
display: "flex",
flexDirection: "column",
gap: "17px",
overflowY: "auto",
maxHeight: "95vh",
boxShadow:
theme.palette.mode === "dark"
? "0px 4px 5px 0px hsla(0,0%,0%,0.14), 0px 1px 10px 0px hsla(0,0%,0%,0.12), 0px 2px 4px -1px hsla(0,0%,0%,0.2)"
: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px",
"&::-webkit-scrollbar-track": {
backgroundColor: theme.palette.background.paper,
},
"&::-webkit-scrollbar-track:hover": {
backgroundColor: theme.palette.background.paper,
},
"&::-webkit-scrollbar": {
width: "16px",
height: "10px",
backgroundColor: theme.palette.mode === "light" ? "#f6f8fa" : "#292d3e",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: theme.palette.mode === "light" ? "#d3d9e1" : "#575757",
borderRadius: "8px",
backgroundClip: "content-box",
border: "4px solid transparent",
},
"&::-webkit-scrollbar-thumb:hover": {
backgroundColor: theme.palette.mode === "light" ? "#b7bcc4" : "#474646",
},
}));

View File

@ -17,7 +17,7 @@ import {
Tooltip,
} from "@mui/material";
import qortImg from "../../../assets/img/qort.png";
import { MultiplePublish } from "../MultiplePublish/MultiplePublish";
import { MultiplePublish } from "../MultiplePublish/MultiplePublishAll";
import { useDispatch, useSelector } from "react-redux";
import { setNotification } from "../../../state/features/notificationsSlice";
import ShortUniqueId from "short-unique-id";
@ -64,13 +64,13 @@ export const SuperLike = ({
const [comment, setComment] = useState<string>("");
const username = useSelector((state: RootState) => state.auth?.user?.name);
const [isOpenMultiplePublish, setIsOpenMultiplePublish] = useState(false);
const [publishes, setPublishes] = useState<any[]>([]);
const [publishes, setPublishes] = useState<any>(null);
const dispatch = useDispatch();
const resetValues = () => {
setSuperlikeDonationAmount(0);
setComment("");
setPublishes([]);
setPublishes(null);
};
const onClose = () => {
resetValues();
@ -177,7 +177,12 @@ export const SuperLike = ({
listOfPublishes.push(requestBodyJson);
setPublishes(listOfPublishes);
const multiplePublish = {
action: "PUBLISH_MULTIPLE_QDN_RESOURCES",
resources: [...listOfPublishes],
};
setPublishes(multiplePublish);
setIsOpenMultiplePublish(true);
} catch (error: any) {
let notificationObj: any = null;
@ -405,6 +410,18 @@ export const SuperLike = ({
{isOpenMultiplePublish && (
<MultiplePublish
isOpen={isOpenMultiplePublish}
onError={messageNotification => {
setIsOpenMultiplePublish(false);
setPublishes(null);
if (messageNotification) {
dispatch(
setNotification({
msg: messageNotification,
alertType: "error",
})
);
}
}}
onSubmit={() => {
onSuccess({
name: username,