mirror of
https://github.com/Qortal/q-tube.git
synced 2025-12-12 15:52:59 +00:00
removed more reducers
This commit is contained in:
@@ -24,15 +24,8 @@ import {
|
||||
useTheme,
|
||||
} from '@mui/material';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { objectToBase64 } from '../../../utils/PublishFormatter.ts';
|
||||
import { RootState } from '../../../state/store.ts';
|
||||
import {
|
||||
updateVideo,
|
||||
updateInHashMap,
|
||||
setEditPlaylist,
|
||||
} from '../../../state/features/videoSlice.ts';
|
||||
import ImageUploader from '../../common/ImageUploader.tsx';
|
||||
import { categories, subCategories } from '../../../constants/Categories.ts';
|
||||
import { Playlists } from '../../Playlists/Playlists.tsx';
|
||||
@@ -43,25 +36,25 @@ import {
|
||||
QTUBE_PLAYLIST_BASE,
|
||||
QTUBE_VIDEO_BASE,
|
||||
} from '../../../constants/Identifiers.ts';
|
||||
import { useAuth } from 'qapp-core';
|
||||
import { useAuth, useGlobal } from 'qapp-core';
|
||||
import {
|
||||
AltertObject,
|
||||
setNotificationAtom,
|
||||
} from '../../../state/global/notifications.ts';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
import { editPlaylistAtom } from '../../../state/publish/playlist.ts';
|
||||
|
||||
const uid = new ShortUniqueId();
|
||||
const shortuid = new ShortUniqueId({ length: 5 });
|
||||
|
||||
export const EditPlaylist = () => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const { name: username, address: userAddress } = useAuth();
|
||||
const setNotification = useSetAtom(setNotificationAtom);
|
||||
const { lists } = useGlobal();
|
||||
const [editVideoProperties] = useAtom(editPlaylistAtom);
|
||||
const setEditPlaylist = useSetAtom(editPlaylistAtom);
|
||||
|
||||
const editVideoProperties = useSelector(
|
||||
(state: RootState) => state.video.editPlaylistProperties
|
||||
);
|
||||
const [playlistData, setPlaylistData] = useState<any>(null);
|
||||
const [title, setTitle] = useState<string>('');
|
||||
const [description, setDescription] = useState<string>('');
|
||||
@@ -84,52 +77,6 @@ export const EditPlaylist = () => {
|
||||
}
|
||||
}, [isNew]);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (editVideoProperties) {
|
||||
// const descriptionString = editVideoProperties?.description || "";
|
||||
// // Splitting the string at the asterisks
|
||||
// const parts = descriptionString.split("**");
|
||||
|
||||
// // The part within the asterisks
|
||||
// const extractedString = parts[1];
|
||||
|
||||
// // The part after the last asterisks
|
||||
// const description = parts[2] || ""; // Using '|| '' to handle cases where there is no text after the last **
|
||||
// setTitle(editVideoProperties?.title || "");
|
||||
// setDescription(editVideoProperties?.fullDescription || "");
|
||||
// setCoverImage(editVideoProperties?.videoImage || "");
|
||||
|
||||
// // Split the extracted string into key-value pairs
|
||||
// const keyValuePairs = extractedString.split(";");
|
||||
|
||||
// // Initialize variables to hold the category and subcategory values
|
||||
// let category, subcategory;
|
||||
|
||||
// // Loop through each key-value pair
|
||||
// keyValuePairs.forEach((pair) => {
|
||||
// const [key, value] = pair.split(":");
|
||||
|
||||
// // Check the key and assign the value to the appropriate variable
|
||||
// if (key === "category") {
|
||||
// category = value;
|
||||
// } else if (key === "subcategory") {
|
||||
// subcategory = value;
|
||||
// }
|
||||
// });
|
||||
|
||||
// if(category){
|
||||
// const selectedOption = categories.find((option) => option.id === +category);
|
||||
// setSelectedCategoryVideos(selectedOption || null);
|
||||
// }
|
||||
|
||||
// if(subcategory){
|
||||
// const selectedOption = categories.find((option) => option.id === +subcategory);
|
||||
// setSelectedCategoryVideos(selectedOption || null);
|
||||
// }
|
||||
|
||||
// }
|
||||
// }, [editVideoProperties]);
|
||||
|
||||
const checkforPlaylist = React.useCallback(async (videoList) => {
|
||||
try {
|
||||
const combinedData: any = {};
|
||||
@@ -203,7 +150,7 @@ export const EditPlaylist = () => {
|
||||
setSelectedCategoryVideos(null);
|
||||
setSelectedSubCategoryVideos(null);
|
||||
setCoverImage('');
|
||||
dispatch(setEditPlaylist(null));
|
||||
setEditPlaylist(null);
|
||||
};
|
||||
|
||||
async function publishQDNResource() {
|
||||
@@ -331,21 +278,25 @@ export const EditPlaylist = () => {
|
||||
user: username,
|
||||
...playlistObject,
|
||||
};
|
||||
dispatch(updateVideo(objectToStore));
|
||||
dispatch(updateInHashMap(objectToStore));
|
||||
} else {
|
||||
dispatch(
|
||||
updateVideo({
|
||||
...editVideoProperties,
|
||||
...playlistObject,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
updateInHashMap({
|
||||
...editVideoProperties,
|
||||
...playlistObject,
|
||||
})
|
||||
);
|
||||
lists.updateNewResources([
|
||||
{
|
||||
data: playlistObject,
|
||||
qortalMetadata: {
|
||||
identifier: identifier,
|
||||
service: 'PLAYLIST',
|
||||
name: username,
|
||||
size: 100,
|
||||
updated: Date.now(),
|
||||
metadata: {
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
tags: [QTUBE_VIDEO_BASE],
|
||||
},
|
||||
created: editVideoProperties?.created,
|
||||
},
|
||||
},
|
||||
]);
|
||||
}
|
||||
const notificationObj: AltertObject = {
|
||||
msg: 'Playlist published',
|
||||
|
||||
@@ -11,12 +11,10 @@ import {
|
||||
Typography,
|
||||
useTheme,
|
||||
} from '@mui/material';
|
||||
import { Signal, useSignal, useSignalEffect } from '@preact/signals-react';
|
||||
import { Signal, useSignal } from '@preact/signals-react';
|
||||
import Compressor from 'compressorjs';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import { categories, subCategories } from '../../../constants/Categories.ts';
|
||||
import { QTUBE_VIDEO_BASE } from '../../../constants/Identifiers.ts';
|
||||
import {
|
||||
@@ -25,12 +23,6 @@ import {
|
||||
videoMaxSize,
|
||||
} from '../../../constants/Misc.ts';
|
||||
|
||||
import {
|
||||
setEditVideo,
|
||||
updateInHashMap,
|
||||
updateVideo,
|
||||
} from '../../../state/features/videoSlice.ts';
|
||||
import { RootState } from '../../../state/store.ts';
|
||||
import BoundedNumericTextField from '../../../utils/BoundedNumericTextField.tsx';
|
||||
import { objectToBase64 } from '../../../utils/PublishFormatter.ts';
|
||||
import { FrameExtractor } from '../../common/FrameExtractor/FrameExtractor.tsx';
|
||||
@@ -52,33 +44,29 @@ import {
|
||||
NewCrowdfundTitle,
|
||||
TimesIcon,
|
||||
} from './EditVideo-styles.tsx';
|
||||
import { useAuth, usePublish } from 'qapp-core';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useAuth, useGlobal, usePublish } from 'qapp-core';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
import {
|
||||
AltertObject,
|
||||
setNotificationAtom,
|
||||
} from '../../../state/global/notifications.ts';
|
||||
import { editVideoAtom } from '../../../state/publish/video.ts';
|
||||
|
||||
export const EditVideo = () => {
|
||||
const theme = useTheme();
|
||||
const setNotification = useSetAtom(setNotificationAtom);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const setEditVideo = useSetAtom(editVideoAtom);
|
||||
const { name: username, address: userAddress } = useAuth();
|
||||
|
||||
const editVideoProperties = useSelector(
|
||||
(state: RootState) => state.video.editVideoProperties
|
||||
);
|
||||
const { lists, auth } = useGlobal();
|
||||
const [editVideoProperties] = useAtom(editVideoAtom);
|
||||
const [publishes, setPublishes] = useState<any>(null);
|
||||
const [isOpenMultiplePublish, setIsOpenMultiplePublish] = useState(false);
|
||||
const [videoPropertiesToSetToRedux, setVideoPropertiesToSetToRedux] =
|
||||
useState(null);
|
||||
|
||||
const publishFromLibrary = usePublish();
|
||||
|
||||
const [title, setTitle] = useState<string>('');
|
||||
const [description, setDescription] = useState<string>('');
|
||||
const [coverImage, setCoverImage] = useState<string>('');
|
||||
const [file, setFile] = useState(null);
|
||||
const [file, setFile] = useState<null | File>(null);
|
||||
const [selectedCategoryVideos, setSelectedCategoryVideos] =
|
||||
useState<any>(null);
|
||||
const [selectedSubCategoryVideos, setSelectedSubCategoryVideos] =
|
||||
@@ -104,7 +92,7 @@ export const EditVideo = () => {
|
||||
|
||||
setFile(firstFile);
|
||||
|
||||
let errorString = null;
|
||||
let errorString: null | string = null;
|
||||
|
||||
rejectedFiles.forEach(({ file, errors }) => {
|
||||
errors.forEach((error) => {
|
||||
@@ -155,9 +143,10 @@ export const EditVideo = () => {
|
||||
}
|
||||
}, [editVideoProperties]);
|
||||
|
||||
console.log('editVideoProperties', editVideoProperties);
|
||||
|
||||
const onClose = () => {
|
||||
dispatch(setEditVideo(null));
|
||||
setVideoPropertiesToSetToRedux(null);
|
||||
setEditVideo(null);
|
||||
setFile(null);
|
||||
setTitle('');
|
||||
setImageExtracts([]);
|
||||
@@ -167,6 +156,7 @@ export const EditVideo = () => {
|
||||
|
||||
async function publishQDNResource() {
|
||||
try {
|
||||
if (!username) throw new Error('A name is required to publish');
|
||||
if (!title) throw new Error('Please enter a title');
|
||||
if (!description) throw new Error('Please enter a description');
|
||||
if (!coverImage) throw new Error('Please select cover image');
|
||||
@@ -195,14 +185,14 @@ export const EditVideo = () => {
|
||||
setNotification(notificationObj);
|
||||
return;
|
||||
}
|
||||
const listOfPublishes = [];
|
||||
const listOfPublishes: any[] = [];
|
||||
const category = selectedCategoryVideos.id;
|
||||
const subcategory = selectedSubCategoryVideos?.id || '';
|
||||
|
||||
const fullDescription = extractTextFromHTML(description);
|
||||
let fileExtension = 'mp4';
|
||||
const fileExtensionSplit = file?.name?.split('.');
|
||||
if (fileExtensionSplit?.length > 1) {
|
||||
if (fileExtensionSplit && fileExtensionSplit?.length > 1) {
|
||||
fileExtension = fileExtensionSplit?.pop() || 'mp4';
|
||||
}
|
||||
|
||||
@@ -268,18 +258,26 @@ export const EditVideo = () => {
|
||||
listOfPublishes.push(requestBodyVideo);
|
||||
}
|
||||
|
||||
setVideoPropertiesToSetToRedux({
|
||||
...editVideoProperties,
|
||||
...videoObject,
|
||||
});
|
||||
|
||||
await publishFromLibrary.publishMultipleResources(listOfPublishes);
|
||||
const clonedCopy = structuredClone({
|
||||
...editVideoProperties,
|
||||
...videoObject,
|
||||
});
|
||||
dispatch(updateVideo(clonedCopy));
|
||||
dispatch(updateInHashMap(clonedCopy));
|
||||
|
||||
lists.updateNewResources([
|
||||
{
|
||||
data: videoObject,
|
||||
qortalMetadata: {
|
||||
identifier: editVideoProperties.id,
|
||||
service: 'DOCUMENT',
|
||||
name: username,
|
||||
size: 100,
|
||||
updated: Date.now(),
|
||||
metadata: {
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
tags: [QTUBE_VIDEO_BASE],
|
||||
},
|
||||
created: editVideoProperties?.created,
|
||||
},
|
||||
},
|
||||
]);
|
||||
const notificationObj: AltertObject = {
|
||||
msg: 'Video updated',
|
||||
alertType: 'success',
|
||||
@@ -319,7 +317,7 @@ export const EditVideo = () => {
|
||||
|
||||
const onFramesExtracted = async (imgs) => {
|
||||
try {
|
||||
const imagesExtracts = [];
|
||||
const imagesExtracts: string[] = [];
|
||||
|
||||
for (const img of imgs) {
|
||||
try {
|
||||
@@ -343,8 +341,11 @@ export const EditVideo = () => {
|
||||
});
|
||||
});
|
||||
if (!compressedFile) continue;
|
||||
const base64Img = await toBase64(compressedFile);
|
||||
imagesExtracts.push(base64Img);
|
||||
const result = await toBase64(compressedFile);
|
||||
|
||||
if (result && typeof result === 'string') {
|
||||
imagesExtracts.push(result);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@@ -536,7 +537,7 @@ export const EditVideo = () => {
|
||||
onClick={() => {
|
||||
publishQDNResource();
|
||||
}}
|
||||
disabled={file && imageExtracts.length === 0}
|
||||
disabled={!!file && imageExtracts?.length === 0}
|
||||
>
|
||||
{file && imageExtracts.length === 0 && (
|
||||
<CircularProgress color="secondary" size={14} />
|
||||
|
||||
@@ -20,7 +20,6 @@ import { useSignals } from '@preact/signals-react/runtime';
|
||||
import Compressor from 'compressorjs';
|
||||
import React, { useState } from 'react';
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import { categories, subCategories } from '../../../constants/Categories.ts';
|
||||
import {
|
||||
@@ -108,7 +107,6 @@ export const PublishVideo = ({
|
||||
afterClose,
|
||||
}: PublishVideoProps) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const [isOpenMultiplePublish, setIsOpenMultiplePublish] = useState(false);
|
||||
const setNotification = useSetAtom(setNotificationAtom);
|
||||
|
||||
@@ -183,7 +181,7 @@ export const PublishVideo = ({
|
||||
|
||||
setFiles((prev) => [...prev, ...formatArray]);
|
||||
|
||||
let errorString = null;
|
||||
let errorString: string | null = null;
|
||||
rejectedFiles.forEach(({ file, errors }) => {
|
||||
errors.forEach((error) => {
|
||||
if (error.code === 'file-too-large') {
|
||||
@@ -255,7 +253,7 @@ export const PublishVideo = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const listOfPublishes = [];
|
||||
const listOfPublishes: any[] = [];
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const publish = files[i];
|
||||
@@ -587,7 +585,7 @@ export const PublishVideo = ({
|
||||
|
||||
const onFramesExtracted = async (imgs, index) => {
|
||||
try {
|
||||
const imagesExtracts = [];
|
||||
const imagesExtracts: string[] = [];
|
||||
|
||||
for (const img of imgs) {
|
||||
try {
|
||||
@@ -612,7 +610,9 @@ export const PublishVideo = ({
|
||||
});
|
||||
if (!compressedFile) continue;
|
||||
const base64Img = await toBase64(compressedFile);
|
||||
imagesExtracts.push(base64Img);
|
||||
if (base64Img && typeof base64Img === 'string') {
|
||||
imagesExtracts.push(base64Img);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@@ -1065,7 +1065,7 @@ export const PublishVideo = ({
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{searchResults?.map((vid, index) => {
|
||||
{searchResults?.map((vid: any, index) => {
|
||||
return (
|
||||
<Box
|
||||
key={vid?.identifier}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { styled } from "@mui/system";
|
||||
import { Grid } from "@mui/material";
|
||||
import { useFetchVideos } from "../hooks/useFetchVideos.tsx";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "../state/store.ts";
|
||||
import { signal } from "@preact/signals-react";
|
||||
import React, { useEffect } from 'react';
|
||||
import { styled } from '@mui/system';
|
||||
import { Grid } from '@mui/material';
|
||||
import { useFetchVideos } from '../hooks/useFetchVideos.tsx';
|
||||
import { signal } from '@preact/signals-react';
|
||||
|
||||
/* eslint-disable react-refresh/only-export-components */
|
||||
export const totalVideosPublished = signal(0);
|
||||
@@ -13,20 +11,19 @@ export const videosPerNamePublished = signal(0);
|
||||
|
||||
export const StatsData = () => {
|
||||
const StatsCol = styled(Grid)(({ theme }) => ({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
padding: "20px 0px",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
padding: '20px 0px',
|
||||
backgroundColor: theme.palette.background.default,
|
||||
}));
|
||||
|
||||
const { getVideosCount } = useFetchVideos();
|
||||
|
||||
const showValueIfExists = (value: number) => {
|
||||
return value > 0 ? "inline" : "none";
|
||||
return value > 0 ? 'inline' : 'none';
|
||||
};
|
||||
|
||||
const showStats = useSelector((state: RootState) => state.persist.showStats);
|
||||
const showVideoCount = showValueIfExists(totalVideosPublished.value);
|
||||
const showPublisherCount = showValueIfExists(totalNamesPublished.value);
|
||||
const showAverage = showValueIfExists(videosPerNamePublished.value);
|
||||
@@ -35,24 +32,24 @@ export const StatsData = () => {
|
||||
}, [getVideosCount]);
|
||||
|
||||
return (
|
||||
<StatsCol sx={{ display: showStats ? "block" : "none" }}>
|
||||
<StatsCol sx={{ display: 'block' }}>
|
||||
<div>
|
||||
Videos:{" "}
|
||||
<span style={{ fontWeight: "bold", display: showVideoCount }}>
|
||||
Videos:{' '}
|
||||
<span style={{ fontWeight: 'bold', display: showVideoCount }}>
|
||||
{totalVideosPublished.value}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
Publishers:{" "}
|
||||
<span style={{ fontWeight: "bold", display: showPublisherCount }}>
|
||||
Publishers:{' '}
|
||||
<span style={{ fontWeight: 'bold', display: showPublisherCount }}>
|
||||
{totalNamesPublished.value}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
Average:{" "}
|
||||
Average:{' '}
|
||||
<span
|
||||
style={{
|
||||
fontWeight: "bold",
|
||||
fontWeight: 'bold',
|
||||
display: showAverage,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -3,7 +3,6 @@ import { CommentEditor } from './CommentEditor';
|
||||
import { Comment } from './Comment';
|
||||
import { Box, Button, CircularProgress, useTheme } from '@mui/material';
|
||||
import { styled } from '@mui/system';
|
||||
import { RootState } from '../../../state/store';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
CommentContainer,
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
fontSizeMedium,
|
||||
minPriceSuperLike,
|
||||
} from '../../../constants/Misc.ts';
|
||||
import { RootState } from '../../../state/store.ts';
|
||||
import BoundedNumericTextField from '../../../utils/BoundedNumericTextField.tsx';
|
||||
import { numberToInt, truncateNumber } from '../../../utils/numberFunctions.ts';
|
||||
import { objectToBase64 } from '../../../utils/PublishFormatter.ts';
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
import EmojiEventsIcon from "@mui/icons-material/EmojiEvents";
|
||||
import ThumbUpIcon from "@mui/icons-material/ThumbUp";
|
||||
import { Box } from "@mui/material";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import List from "@mui/material/List";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
import ListItemAvatar from "@mui/material/ListItemAvatar";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import * as React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { fontSizeSmall } from "../../../constants/Misc.ts";
|
||||
import { RootState } from "../../../state/store";
|
||||
import { formatDate } from "../../../utils/time.ts";
|
||||
import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
|
||||
import ThumbUpIcon from '@mui/icons-material/ThumbUp';
|
||||
import { Box } from '@mui/material';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import List from '@mui/material/List';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import ListItemAvatar from '@mui/material/ListItemAvatar';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import * as React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { fontSizeSmall } from '../../../constants/Misc.ts';
|
||||
import { RootState } from '../../../state/store';
|
||||
import { formatDate } from '../../../utils/time.ts';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { hashMapSuperlikesAtom } from '../../../state/global/superlikes.ts';
|
||||
|
||||
const truncateMessage = message => {
|
||||
return message.length > 40 ? message.slice(0, 40) + "..." : message;
|
||||
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 hashMapSuperlikes = useAtomValue(hashMapSuperlikesAtom);
|
||||
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<List sx={{ width: "100%", maxWidth: 360, bgcolor: "background.paper" }}>
|
||||
<List sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}>
|
||||
{superlikes?.map((superlike, index) => {
|
||||
// let hasHash = false
|
||||
let message = "";
|
||||
let url = "";
|
||||
let forName = "";
|
||||
let message = '';
|
||||
let url = '';
|
||||
let forName = '';
|
||||
// let hash = {}
|
||||
if (hashMapSuperlikes[superlike?.identifier]) {
|
||||
message = hashMapSuperlikes[superlike?.identifier]?.comment || "";
|
||||
message = hashMapSuperlikes[superlike?.identifier]?.comment || '';
|
||||
if (
|
||||
hashMapSuperlikes[superlike?.identifier]?.notificationInformation
|
||||
) {
|
||||
@@ -56,8 +56,8 @@ export default function ListSuperLikes({ superlikes }) {
|
||||
<ListItem
|
||||
alignItems="flex-start"
|
||||
sx={{
|
||||
cursor: url ? "pointer" : "default",
|
||||
minHeight: "130px",
|
||||
cursor: url ? 'pointer' : 'default',
|
||||
minHeight: '130px',
|
||||
}}
|
||||
onClick={async () => {
|
||||
if (url) {
|
||||
@@ -67,13 +67,13 @@ export default function ListSuperLikes({ superlikes }) {
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<List sx={{ padding: "0px" }}>
|
||||
<List sx={{ padding: '0px' }}>
|
||||
<ListItem
|
||||
sx={{
|
||||
padding: "0px",
|
||||
padding: '0px',
|
||||
}}
|
||||
alignItems="flex-start"
|
||||
>
|
||||
@@ -87,23 +87,23 @@ export default function ListSuperLikes({ superlikes }) {
|
||||
primary={
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "5px",
|
||||
fontSize: "18px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
fontSize: '18px',
|
||||
}}
|
||||
>
|
||||
<ThumbUpIcon
|
||||
style={{
|
||||
color: "gold",
|
||||
color: 'gold',
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
fontSize: '18px',
|
||||
}}
|
||||
>
|
||||
{amount ? amount : ""} QORT
|
||||
{amount ? amount : ''} QORT
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
@@ -111,9 +111,9 @@ export default function ListSuperLikes({ superlikes }) {
|
||||
<>
|
||||
<Typography
|
||||
sx={{
|
||||
display: "inline",
|
||||
wordBreak: "break-word",
|
||||
fontSize: "15px",
|
||||
display: 'inline',
|
||||
wordBreak: 'break-word',
|
||||
fontSize: '15px',
|
||||
}}
|
||||
component="span"
|
||||
variant="body2"
|
||||
@@ -131,11 +131,11 @@ export default function ListSuperLikes({ superlikes }) {
|
||||
{forName && (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontSize: "17px",
|
||||
gap: "10px",
|
||||
justifyContent: "flex-end",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '17px',
|
||||
gap: '10px',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<EmojiEventsIcon />
|
||||
@@ -149,7 +149,7 @@ export default function ListSuperLikes({ superlikes }) {
|
||||
</ListItem>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{superlikes.length === index + 1 ? null : <Divider />}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { toast, ToastContainer, Zoom, Slide } from 'react-toastify';
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
import { RootState } from '../../../state/store';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
import {
|
||||
alertAtom,
|
||||
@@ -9,8 +7,6 @@ import {
|
||||
} from '../../../state/global/notifications';
|
||||
|
||||
const Notification = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [alertTypes] = useAtom(alertAtom);
|
||||
const removeNotification = useSetAtom(removeNotificationAtom);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import localforage from 'localforage';
|
||||
import { useEffect, useState } from 'react';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import { COMMENT_BASE } from '../../../constants/Identifiers.ts';
|
||||
import { addtoHashMapSuperlikes } from '../../../state/features/videoSlice';
|
||||
import { objectToBase64 } from '../../../utils/PublishFormatter.ts';
|
||||
import {
|
||||
CommentInput,
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
AltertObject,
|
||||
setNotificationAtom,
|
||||
} from '../../../state/global/notifications.ts';
|
||||
import { addToHashMapSuperlikesAtom } from '../../../state/global/superlikes.ts';
|
||||
|
||||
const uid = new ShortUniqueId({ length: 7 });
|
||||
|
||||
@@ -120,6 +120,7 @@ export const CommentEditor = ({
|
||||
}: CommentEditorProps) => {
|
||||
const [value, setValue] = useState<string>('');
|
||||
const setNotification = useSetAtom(setNotificationAtom);
|
||||
const addSuperlike = useSetAtom(addToHashMapSuperlikesAtom);
|
||||
|
||||
const { name, address } = useAuth();
|
||||
useEffect(() => {
|
||||
@@ -197,13 +198,11 @@ export const CommentEditor = ({
|
||||
setNotification(notificationObj);
|
||||
|
||||
if (isSuperLike) {
|
||||
dispatch(
|
||||
addtoHashMapSuperlikes({
|
||||
...superObj,
|
||||
...comment,
|
||||
message: value,
|
||||
})
|
||||
);
|
||||
addSuperlike({
|
||||
...superObj,
|
||||
...comment,
|
||||
message: value,
|
||||
});
|
||||
}
|
||||
if (idForNotification) {
|
||||
addItem({
|
||||
|
||||
@@ -16,6 +16,8 @@ import {
|
||||
|
||||
import { COMMENT_BASE } from '../../../constants/Identifiers.ts';
|
||||
import { hashWordWithoutPublicSalt } from 'qapp-core';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { hashMapSuperlikesAtom } from '../../../state/global/superlikes.ts';
|
||||
|
||||
interface CommentSectionProps {
|
||||
postId: string;
|
||||
@@ -61,9 +63,9 @@ export const SuperLikesSection = ({
|
||||
const [listComments, setListComments] = useState<any[]>([]);
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const [loadingComments, setLoadingComments] = useState<boolean>(null);
|
||||
const hashMapSuperlikes = useSelector(
|
||||
(state: RootState) => state.video.hashMapSuperlikes
|
||||
);
|
||||
|
||||
const hashMapSuperlikes = useAtomValue(hashMapSuperlikesAtom);
|
||||
|
||||
const onSubmit = (obj?: any, isEdit?: boolean) => {
|
||||
if (isEdit) {
|
||||
setListComments((prev: any[]) => {
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
import { useDispatch } from "react-redux";
|
||||
import { headerIconSize, menuIconSize } from "../../../../constants/Misc.ts";
|
||||
import { setEditPlaylist } from "../../../../state/features/videoSlice.ts";
|
||||
import { StyledButton } from "../../../Publish/PublishVideo/PublishVideo-styles.tsx";
|
||||
import { PublishVideo } from "../../../Publish/PublishVideo/PublishVideo.tsx";
|
||||
import { headerIconSize, menuIconSize } from '../../../../constants/Misc.ts';
|
||||
import { StyledButton } from '../../../Publish/PublishVideo/PublishVideo-styles.tsx';
|
||||
import { PublishVideo } from '../../../Publish/PublishVideo/PublishVideo.tsx';
|
||||
import {
|
||||
AvatarContainer,
|
||||
DropdownContainer,
|
||||
DropdownText,
|
||||
NavbarName,
|
||||
} from "../Navbar-styles.tsx";
|
||||
import AddBoxIcon from "@mui/icons-material/AddBox";
|
||||
import { PopMenu, PopMenuRefType } from "../../../common/PopMenu.tsx";
|
||||
import { useRef } from "react";
|
||||
import { useMediaQuery } from "@mui/material";
|
||||
} from '../Navbar-styles.tsx';
|
||||
import AddBoxIcon from '@mui/icons-material/AddBox';
|
||||
import { PopMenu, PopMenuRefType } from '../../../common/PopMenu.tsx';
|
||||
import { useRef } from 'react';
|
||||
import { useMediaQuery } from '@mui/material';
|
||||
|
||||
export interface PublishButtonsProps {
|
||||
isDisplayed: boolean;
|
||||
}
|
||||
import PlaylistAddIcon from "@mui/icons-material/PlaylistAdd";
|
||||
import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
|
||||
import { editPlaylistAtom } from '../../../../state/publish/playlist.ts';
|
||||
import { useSetAtom } from 'jotai';
|
||||
|
||||
export const PublishMenu = ({ isDisplayed }: PublishButtonsProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const popMenuRef = useRef<PopMenuRefType>(null);
|
||||
|
||||
const setEditPlaylist = useSetAtom(editPlaylistAtom);
|
||||
const isScreenSmall = !useMediaQuery(`(min-width:600px)`);
|
||||
return (
|
||||
<>
|
||||
@@ -31,11 +30,11 @@ export const PublishMenu = ({ isDisplayed }: PublishButtonsProps) => {
|
||||
MenuHeader={
|
||||
<>
|
||||
{!isScreenSmall && (
|
||||
<NavbarName sx={{ marginRight: "5px" }}>Publish</NavbarName>
|
||||
<NavbarName sx={{ marginRight: '5px' }}>Publish</NavbarName>
|
||||
)}
|
||||
<AddBoxIcon
|
||||
sx={{
|
||||
color: "DarkGreen",
|
||||
color: 'DarkGreen',
|
||||
width: headerIconSize,
|
||||
height: headerIconSize,
|
||||
}}
|
||||
@@ -53,14 +52,14 @@ export const PublishMenu = ({ isDisplayed }: PublishButtonsProps) => {
|
||||
startIcon={
|
||||
<PlaylistAddIcon
|
||||
sx={{
|
||||
color: "#00BFFF",
|
||||
color: '#00BFFF',
|
||||
width: menuIconSize,
|
||||
height: menuIconSize,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
onClick={() => {
|
||||
dispatch(setEditPlaylist({ mode: "new" }));
|
||||
setEditPlaylist({ mode: 'new' });
|
||||
}}
|
||||
>
|
||||
Playlist
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Logo from "../../../../assets/img/logo.webp";
|
||||
import {
|
||||
addFilteredVideos,
|
||||
setFilterValue,
|
||||
setIsFiltering,
|
||||
} from "../../../../state/features/videoSlice.ts";
|
||||
import { LogoContainer, ThemeSelectRow } from "../Navbar-styles.tsx";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useMediaQuery } from "@mui/material";
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import Logo from '../../../../assets/img/logo.webp';
|
||||
|
||||
import { LogoContainer, ThemeSelectRow } from '../Navbar-styles.tsx';
|
||||
import { useMediaQuery } from '@mui/material';
|
||||
|
||||
export const QtubeLogo = () => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const isScreenSmall = !useMediaQuery(`(min-width:600px)`);
|
||||
|
||||
@@ -19,19 +13,16 @@ export const QtubeLogo = () => {
|
||||
<ThemeSelectRow>
|
||||
<LogoContainer
|
||||
onClick={() => {
|
||||
navigate("/");
|
||||
dispatch(setIsFiltering(false));
|
||||
dispatch(setFilterValue(""));
|
||||
dispatch(addFilteredVideos([]));
|
||||
navigate('/');
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={Logo}
|
||||
style={{
|
||||
width: isScreenSmall ? "50px" : "auto",
|
||||
height: "45px",
|
||||
padding: "2px",
|
||||
marginTop: "5px",
|
||||
width: isScreenSmall ? '50px' : 'auto',
|
||||
height: '45px',
|
||||
padding: '2px',
|
||||
marginTop: '5px',
|
||||
}}
|
||||
/>
|
||||
</LogoContainer>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Popover, useMediaQuery, useTheme, Avatar } from '@mui/material';
|
||||
import { AccountCircleSVG } from '../../../../assets/svgs/AccountCircleSVG.tsx';
|
||||
import { headerIconSize, menuIconSize } from '../../../../constants/Misc.ts';
|
||||
import { useMediaQuery, useTheme, Avatar } from '@mui/material';
|
||||
import { menuIconSize } from '../../../../constants/Misc.ts';
|
||||
import { BlockedNamesModal } from '../../../common/BlockedNamesModal/BlockedNamesModal.tsx';
|
||||
import {
|
||||
AvatarContainer,
|
||||
@@ -8,11 +7,8 @@ import {
|
||||
DropdownText,
|
||||
NavbarName,
|
||||
} from '../Navbar-styles.tsx';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import PersonOffIcon from '@mui/icons-material/PersonOff';
|
||||
import { RootState } from '../../../../state/store';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { PopMenu, PopMenuRefType } from '../../../common/PopMenu.tsx';
|
||||
import { UserDropDown } from '../../../UserDropDown.tsx';
|
||||
@@ -38,7 +34,6 @@ export const UserMenu = ({
|
||||
useState<boolean>(false);
|
||||
const popMenuRef = useRef<PopMenuRefType>(null);
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleMyChannelLink = useCallback(
|
||||
(switchToName: string) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const useTestIdentifiers = false;
|
||||
export const useTestIdentifiers = true;
|
||||
export const QTUBE_VIDEO_BASE = useTestIdentifiers
|
||||
? 'MYTEST2_vid_'
|
||||
: 'qtube_vid_';
|
||||
|
||||
@@ -1,114 +1,107 @@
|
||||
import React, { useCallback } from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import { queueSuperlikes } from '../wrappers/GlobalWrapper';
|
||||
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
|
||||
import {
|
||||
|
||||
addtoHashMapSuperlikes
|
||||
} from '../state/features/videoSlice'
|
||||
|
||||
import { RootState } from '../state/store'
|
||||
import { queueSuperlikes } from '../wrappers/GlobalWrapper'
|
||||
|
||||
|
||||
addToHashMapSuperlikesAtom,
|
||||
hashMapSuperlikesAtom,
|
||||
} from '../state/global/superlikes';
|
||||
|
||||
export const useFetchSuperLikes = () => {
|
||||
const dispatch = useDispatch()
|
||||
const hashMapSuperlikes = useSelector(
|
||||
(state: RootState) => state.video.hashMapSuperlikes
|
||||
)
|
||||
const checkAndUpdateSuperlike= React.useCallback(
|
||||
const addSuperlike = useSetAtom(addToHashMapSuperlikesAtom);
|
||||
const hashMapSuperlikes = useAtomValue(hashMapSuperlikesAtom);
|
||||
|
||||
const checkAndUpdateSuperlike = React.useCallback(
|
||||
(superlike: any) => {
|
||||
const existingVideo = hashMapSuperlikes[superlike.identifier]
|
||||
const existingVideo = hashMapSuperlikes[superlike.identifier];
|
||||
if (!existingVideo) {
|
||||
return true
|
||||
return true;
|
||||
} else if (
|
||||
superlike?.updated &&
|
||||
existingVideo?.updated &&
|
||||
(!existingVideo?.updated || superlike?.updated) > existingVideo?.updated
|
||||
) {
|
||||
return true
|
||||
return true;
|
||||
} else {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[hashMapSuperlikes]
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
const fetchSuperlike = async (data: any) => {
|
||||
const getsuper = async () => {
|
||||
const { user, videoId, content } = data
|
||||
const { user, videoId, content } = data;
|
||||
let obj: any = {
|
||||
...content,
|
||||
isValid: false
|
||||
}
|
||||
|
||||
if (!user || !videoId) return obj
|
||||
|
||||
isValid: false,
|
||||
};
|
||||
|
||||
if (!user || !videoId) return obj;
|
||||
|
||||
try {
|
||||
|
||||
const responseData = await qortalRequest({
|
||||
action: 'FETCH_QDN_RESOURCE',
|
||||
name: user,
|
||||
service: content?.service || 'BLOG_COMMENT',
|
||||
identifier: videoId
|
||||
})
|
||||
|
||||
obj = {
|
||||
...content,
|
||||
...responseData,
|
||||
isValid: true
|
||||
}
|
||||
|
||||
return obj
|
||||
identifier: videoId,
|
||||
});
|
||||
|
||||
obj = {
|
||||
...content,
|
||||
...responseData,
|
||||
isValid: true,
|
||||
};
|
||||
|
||||
return obj;
|
||||
} catch (error: any) {
|
||||
throw new Error(error?.message || 'error')
|
||||
throw new Error(error?.message || 'error');
|
||||
}
|
||||
}
|
||||
|
||||
const res = await getsuper()
|
||||
return res
|
||||
}
|
||||
};
|
||||
|
||||
const res = await getsuper();
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
const getSuperLikes = async (user: string, videoId: string, content: any, retries: number = 0) => {
|
||||
const getSuperLikes = async (
|
||||
user: string,
|
||||
videoId: string,
|
||||
content: any,
|
||||
retries: number = 0
|
||||
) => {
|
||||
try {
|
||||
const res = await fetchSuperlike({
|
||||
user,
|
||||
videoId,
|
||||
content
|
||||
})
|
||||
|
||||
dispatch(addtoHashMapSuperlikes(res))
|
||||
content,
|
||||
});
|
||||
addSuperlike(res);
|
||||
} catch (error) {
|
||||
retries= retries + 1
|
||||
if (retries < 2) { // 3 is the maximum number of retries here, you can adjust it to your needs
|
||||
queueSuperlikes.push(() => getSuperLikes(user, videoId, content, retries + 1));
|
||||
retries = retries + 1;
|
||||
if (retries < 2) {
|
||||
// 3 is the maximum number of retries here, you can adjust it to your needs
|
||||
queueSuperlikes.push(() =>
|
||||
getSuperLikes(user, videoId, content, retries + 1)
|
||||
);
|
||||
} else {
|
||||
console.error('Failed to get video after 3 attempts', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const addSuperlikeRawDataGetToList = useCallback(({name, identifier, content})=> {
|
||||
|
||||
const addSuperlikeRawDataGetToList = useCallback(
|
||||
({ name, identifier, content }) => {
|
||||
if (name && identifier) {
|
||||
const res = checkAndUpdateSuperlike(content)
|
||||
const res = checkAndUpdateSuperlike(content);
|
||||
if (res) {
|
||||
queueSuperlikes.push(() => getSuperLikes(name, identifier, content));
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}, [checkAndUpdateSuperlike])
|
||||
|
||||
|
||||
},
|
||||
[checkAndUpdateSuperlike]
|
||||
);
|
||||
|
||||
return {
|
||||
addSuperlikeRawDataGetToList
|
||||
}
|
||||
}
|
||||
addSuperlikeRawDataGetToList,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
import { RootState } from '../../../state/store.ts';
|
||||
import { useVideoContentState } from '../VideoContent/VideoContent-State.ts';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
@@ -43,92 +41,85 @@ export const usePlaylistContentState = () => {
|
||||
const navigate = useNavigate();
|
||||
const [playlistData, setPlaylistData] = useState<any>(null);
|
||||
|
||||
const hashMapVideos = useSelector(
|
||||
(state: RootState) => state.video.hashMapVideos
|
||||
);
|
||||
const checkforPlaylist = useCallback(async (name, id) => {
|
||||
try {
|
||||
setIsLoadingPlaylist(true);
|
||||
|
||||
const checkforPlaylist = useCallback(
|
||||
async (name, id) => {
|
||||
try {
|
||||
setIsLoadingPlaylist(true);
|
||||
if (!name || !id) return;
|
||||
|
||||
if (!name || !id) return;
|
||||
const url = `/arbitrary/resources/search?mode=ALL&service=PLAYLIST&identifier=${id}&limit=1&includemetadata=true&reverse=true&excludeblocked=true&name=${name}&exactmatchnames=true&offset=0`;
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseDataSearch = await response.json();
|
||||
|
||||
const url = `/arbitrary/resources/search?mode=ALL&service=PLAYLIST&identifier=${id}&limit=1&includemetadata=true&reverse=true&excludeblocked=true&name=${name}&exactmatchnames=true&offset=0`;
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
if (responseDataSearch?.length > 0) {
|
||||
let resourceData = responseDataSearch[0];
|
||||
resourceData = {
|
||||
title: resourceData?.metadata?.title,
|
||||
category: resourceData?.metadata?.category,
|
||||
categoryName: resourceData?.metadata?.categoryName,
|
||||
tags: resourceData?.metadata?.tags || [],
|
||||
description: resourceData?.metadata?.description,
|
||||
created: resourceData?.created,
|
||||
updated: resourceData?.updated,
|
||||
name: resourceData.name,
|
||||
videoImage: '',
|
||||
identifier: resourceData.identifier,
|
||||
service: resourceData.service,
|
||||
};
|
||||
|
||||
const responseData = await qortalRequest({
|
||||
action: 'FETCH_QDN_RESOURCE',
|
||||
name: resourceData.name,
|
||||
service: resourceData.service,
|
||||
identifier: resourceData.identifier,
|
||||
});
|
||||
const responseDataSearch = await response.json();
|
||||
|
||||
if (responseDataSearch?.length > 0) {
|
||||
let resourceData = responseDataSearch[0];
|
||||
resourceData = {
|
||||
title: resourceData?.metadata?.title,
|
||||
category: resourceData?.metadata?.category,
|
||||
categoryName: resourceData?.metadata?.categoryName,
|
||||
tags: resourceData?.metadata?.tags || [],
|
||||
description: resourceData?.metadata?.description,
|
||||
created: resourceData?.created,
|
||||
updated: resourceData?.updated,
|
||||
name: resourceData.name,
|
||||
videoImage: '',
|
||||
identifier: resourceData.identifier,
|
||||
service: resourceData.service,
|
||||
if (responseData && !responseData.error) {
|
||||
const combinedData = {
|
||||
...resourceData,
|
||||
...responseData,
|
||||
};
|
||||
const videos = [];
|
||||
if (combinedData?.videos) {
|
||||
for (const vid of combinedData.videos) {
|
||||
const url = `/arbitrary/resources/search?mode=ALL&service=DOCUMENT&identifier=${vid.identifier}&limit=1&includemetadata=true&reverse=true&name=${vid.name}&exactmatchnames=true&offset=0`;
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseDataSearchVid = await response.json();
|
||||
|
||||
const responseData = await qortalRequest({
|
||||
action: 'FETCH_QDN_RESOURCE',
|
||||
name: resourceData.name,
|
||||
service: resourceData.service,
|
||||
identifier: resourceData.identifier,
|
||||
});
|
||||
|
||||
if (responseData && !responseData.error) {
|
||||
const combinedData = {
|
||||
...resourceData,
|
||||
...responseData,
|
||||
};
|
||||
const videos = [];
|
||||
if (combinedData?.videos) {
|
||||
for (const vid of combinedData.videos) {
|
||||
const url = `/arbitrary/resources/search?mode=ALL&service=DOCUMENT&identifier=${vid.identifier}&limit=1&includemetadata=true&reverse=true&name=${vid.name}&exactmatchnames=true&offset=0`;
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseDataSearchVid = await response.json();
|
||||
|
||||
if (responseDataSearchVid?.length > 0) {
|
||||
const resourceData2 = responseDataSearchVid[0];
|
||||
videos.push(resourceData2);
|
||||
}
|
||||
if (responseDataSearchVid?.length > 0) {
|
||||
const resourceData2 = responseDataSearchVid[0];
|
||||
videos.push(resourceData2);
|
||||
}
|
||||
}
|
||||
combinedData.videos = videos;
|
||||
setPlaylistData(combinedData);
|
||||
if (combinedData?.videos?.length > 0) {
|
||||
const vid = combinedData?.videos[0];
|
||||
setVideoMetadataResource({
|
||||
name: vid?.name,
|
||||
identifier: vid?.identifier,
|
||||
service: 'DOCUMENT',
|
||||
});
|
||||
}
|
||||
}
|
||||
combinedData.videos = videos;
|
||||
setPlaylistData(combinedData);
|
||||
if (combinedData?.videos?.length > 0) {
|
||||
const vid = combinedData?.videos[0];
|
||||
setVideoMetadataResource({
|
||||
name: vid?.name,
|
||||
identifier: vid?.identifier,
|
||||
service: 'DOCUMENT',
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setIsLoadingPlaylist(false);
|
||||
}
|
||||
},
|
||||
[hashMapVideos]
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setIsLoadingPlaylist(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (channelName && id) {
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import DownloadIcon from "@mui/icons-material/Download";
|
||||
import { Box, SxProps, Theme } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { CopyLinkButton } from "../../../components/common/ContentButtons/CopyLinkButton.tsx";
|
||||
import { IndexButton } from "../../../components/common/ContentButtons/IndexButton.tsx";
|
||||
import { LikeAndDislike } from "../../../components/common/ContentButtons/LikeAndDislike.tsx";
|
||||
import { SuperLike } from "../../../components/common/ContentButtons/SuperLike.tsx";
|
||||
import FileElement from "../../../components/common/FileElement.tsx";
|
||||
import { titleFormatterOnSave } from "../../../constants/Misc.ts";
|
||||
import { ChannelActions } from "./ChannelActions.tsx";
|
||||
import DownloadIcon from '@mui/icons-material/Download';
|
||||
import { Box, SxProps, Theme } from '@mui/material';
|
||||
import { useMemo } from 'react';
|
||||
import { CopyLinkButton } from '../../../components/common/ContentButtons/CopyLinkButton.tsx';
|
||||
import { IndexButton } from '../../../components/common/ContentButtons/IndexButton.tsx';
|
||||
import { LikeAndDislike } from '../../../components/common/ContentButtons/LikeAndDislike.tsx';
|
||||
import { SuperLike } from '../../../components/common/ContentButtons/SuperLike.tsx';
|
||||
import FileElement from '../../../components/common/FileElement.tsx';
|
||||
import { titleFormatterOnSave } from '../../../constants/Misc.ts';
|
||||
import { ChannelActions } from './ChannelActions.tsx';
|
||||
import {
|
||||
FileAttachmentContainer,
|
||||
FileAttachmentFont,
|
||||
} from "./VideoContent-styles.tsx";
|
||||
} from './VideoContent-styles.tsx';
|
||||
|
||||
export interface VideoActionsBarProps {
|
||||
channelName: string;
|
||||
@@ -48,55 +47,53 @@ export const VideoActionsBar = ({
|
||||
return superLikeList?.length ?? 0;
|
||||
}, [superLikeList]);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const saveAsFilename = useMemo(() => {
|
||||
// nb. we prefer to construct the local filename to use for
|
||||
// saving, from the video "title" when possible
|
||||
if (videoData?.title) {
|
||||
// figure out filename extension
|
||||
let ext = ".mp4";
|
||||
let ext = '.mp4';
|
||||
if (videoData?.filename) {
|
||||
// nb. this regex copied from https://stackoverflow.com/a/680982
|
||||
const re = /(?:\.([^.]+))?$/;
|
||||
const match = re.exec(videoData.filename);
|
||||
if (match[1]) {
|
||||
ext = "." + match[1];
|
||||
ext = '.' + match[1];
|
||||
}
|
||||
}
|
||||
|
||||
return (videoData.title + ext).replace(titleFormatterOnSave, "");
|
||||
return (videoData.title + ext).replace(titleFormatterOnSave, '');
|
||||
}
|
||||
|
||||
// otherwise use QDN filename if applicable
|
||||
if (videoData?.filename) {
|
||||
return videoData.filename.replace(titleFormatterOnSave, "");
|
||||
return videoData.filename.replace(titleFormatterOnSave, '');
|
||||
}
|
||||
|
||||
// TODO: this was the previous value, leaving here as the
|
||||
// fallback for now even though it probably is not needed..?
|
||||
return videoData?.filename || videoData?.title?.slice(0, 20) + ".mp4";
|
||||
return videoData?.filename || videoData?.title?.slice(0, 20) + '.mp4';
|
||||
}, [videoData]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: "15px",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
gap: "20px",
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
gap: '20px',
|
||||
...sx,
|
||||
}}
|
||||
>
|
||||
<ChannelActions channelName={channelName} />
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
height: "100%",
|
||||
alignItems: "center",
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
height: '100%',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{videoData && (
|
||||
@@ -108,14 +105,14 @@ export const VideoActionsBar = ({
|
||||
name={videoData?.user}
|
||||
service={videoData?.service}
|
||||
identifier={videoData?.id}
|
||||
onSuccess={val => {
|
||||
setSuperLikeList(prev => [val, ...prev]);
|
||||
onSuccess={(val) => {
|
||||
setSuperLikeList((prev) => [val, ...prev]);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", gap: "5px" }}>
|
||||
<Box sx={{ display: 'flex', gap: '5px' }}>
|
||||
<IndexButton channelName={channelName} />
|
||||
<CopyLinkButton
|
||||
link={`qortal://APP/Q-Tube/video/${encodeURIComponent(videoData?.user)}/${encodeURIComponent(videoData?.id)}`}
|
||||
@@ -123,7 +120,7 @@ export const VideoActionsBar = ({
|
||||
/>
|
||||
</Box>
|
||||
{videoData && (
|
||||
<FileAttachmentContainer sx={{ width: "100%", maxWidth: "340px" }}>
|
||||
<FileAttachmentContainer sx={{ width: '100%', maxWidth: '340px' }}>
|
||||
<FileAttachmentFont>Save Video</FileAttachmentFont>
|
||||
<FileElement
|
||||
fileInfo={{
|
||||
@@ -133,9 +130,9 @@ export const VideoActionsBar = ({
|
||||
}}
|
||||
title={videoData?.filename || videoData?.title?.slice(0, 20)}
|
||||
customStyles={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<DownloadIcon />
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { blockUser, setEditVideo } from '../../../state/features/videoSlice.ts';
|
||||
import { blockUser } from '../../../state/features/videoSlice.ts';
|
||||
|
||||
import { VideoCardContainer } from './VideoList-styles.tsx';
|
||||
import { QortalSearchParams, ResourceListDisplay, useAuth } from 'qapp-core';
|
||||
import {
|
||||
QortalSearchParams,
|
||||
ResourceListDisplay,
|
||||
useAuth,
|
||||
useGlobal,
|
||||
} from 'qapp-core';
|
||||
import { VideoListItem } from './VideoListItem.tsx';
|
||||
import { VideoLoaderItem } from './VideoLoaderItem.tsx';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { editVideoAtom } from '../../../state/publish/video.ts';
|
||||
|
||||
interface VideoListProps {
|
||||
searchParameters: QortalSearchParams;
|
||||
@@ -14,8 +21,9 @@ interface VideoListProps {
|
||||
}
|
||||
export const VideoList = ({ searchParameters, listName }: VideoListProps) => {
|
||||
const { name: username } = useAuth();
|
||||
|
||||
const { lists } = useGlobal();
|
||||
const dispatch = useDispatch();
|
||||
const setEditVideo = useSetAtom(editVideoAtom);
|
||||
|
||||
const blockUserFunc = async (user: string) => {
|
||||
if (user === 'Q-Tube') return;
|
||||
@@ -28,7 +36,8 @@ export const VideoList = ({ searchParameters, listName }: VideoListProps) => {
|
||||
});
|
||||
|
||||
if (response === true) {
|
||||
dispatch(blockUser(user));
|
||||
lists.deleteList('AllVideos');
|
||||
// dispatch(blockUser(user));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
VideoCardTitle,
|
||||
VideoUploadDate,
|
||||
} from './VideoList-styles';
|
||||
import { setEditPlaylist } from '../../../state/features/videoSlice';
|
||||
import ResponsiveImage from '../../../components/ResponsiveImage';
|
||||
import { PlaylistSVG } from '../../../assets/svgs/PlaylistSVG';
|
||||
import { formatTime } from '../../../utils/numberFunctions';
|
||||
@@ -21,9 +20,10 @@ import { useNavigate } from 'react-router-dom';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import BlockIcon from '@mui/icons-material/Block';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useGlobal } from 'qapp-core';
|
||||
import { useState } from 'react';
|
||||
import { editPlaylistAtom } from '../../../state/publish/playlist';
|
||||
import { useSetAtom } from 'jotai';
|
||||
|
||||
export const VideoListItem = ({
|
||||
qortalMetadata,
|
||||
@@ -33,12 +33,12 @@ export const VideoListItem = ({
|
||||
setEditVideo,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const [showIcons, setShowIcons] = useState(null);
|
||||
const theme = useTheme();
|
||||
const { lists } = useGlobal();
|
||||
|
||||
const { deleteResource } = lists;
|
||||
const setEditPlaylist = useSetAtom(editPlaylistAtom);
|
||||
|
||||
const isPlaylist = qortalMetadata?.service === 'PLAYLIST';
|
||||
|
||||
@@ -73,7 +73,7 @@ export const VideoListItem = ({
|
||||
identifier: qortalMetadata.identifier,
|
||||
service: qortalMetadata.service,
|
||||
};
|
||||
dispatch(setEditPlaylist({ ...resourceData, ...video }));
|
||||
setEditPlaylist({ ...resourceData, ...video });
|
||||
}}
|
||||
/>
|
||||
</BlockIconContainer>
|
||||
@@ -187,7 +187,7 @@ export const VideoListItem = ({
|
||||
id: qortalMetadata.identifier,
|
||||
};
|
||||
|
||||
dispatch(setEditVideo({ ...resourceData, ...video }));
|
||||
setEditVideo({ ...resourceData, ...video });
|
||||
}}
|
||||
/>
|
||||
</BlockIconContainer>
|
||||
|
||||
@@ -1,38 +1,12 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { SubscriptionData } from "../../components/common/ContentButtons/SubscribeButton.tsx";
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { SubscriptionData } from '../../components/common/ContentButtons/SubscribeButton.tsx';
|
||||
|
||||
interface GlobalState {
|
||||
videos: Video[];
|
||||
filteredVideos: Video[];
|
||||
hashMapVideos: Record<string, Video>;
|
||||
hashMapSuperlikes: Record<string, any>;
|
||||
countNewVideos: number;
|
||||
isFiltering: boolean;
|
||||
filterValue: string;
|
||||
filterSearch: string;
|
||||
filterName: string;
|
||||
selectedCategoryVideos: any;
|
||||
selectedSubCategoryVideos: any;
|
||||
editVideoProperties: any;
|
||||
editPlaylistProperties: any;
|
||||
filteredSubscriptionList: SubscriptionData[];
|
||||
}
|
||||
|
||||
const initialState: GlobalState = {
|
||||
videos: [],
|
||||
filteredVideos: [],
|
||||
hashMapVideos: {},
|
||||
hashMapSuperlikes: {},
|
||||
countNewVideos: 0,
|
||||
isFiltering: false,
|
||||
filterValue: "",
|
||||
filterSearch: "",
|
||||
filterName: "",
|
||||
selectedCategoryVideos: null,
|
||||
selectedSubCategoryVideos: null,
|
||||
editVideoProperties: null,
|
||||
editPlaylistProperties: null,
|
||||
filteredSubscriptionList: [],
|
||||
};
|
||||
|
||||
export interface Video {
|
||||
@@ -52,164 +26,17 @@ export interface Video {
|
||||
}
|
||||
|
||||
export const videoSlice = createSlice({
|
||||
name: "video",
|
||||
name: 'video',
|
||||
initialState,
|
||||
reducers: {
|
||||
setEditVideo: (state, action) => {
|
||||
state.editVideoProperties = action.payload;
|
||||
},
|
||||
setEditPlaylist: (state, action) => {
|
||||
state.editPlaylistProperties = action.payload;
|
||||
},
|
||||
|
||||
changefilterSearch: (state, action) => {
|
||||
state.filterSearch = action.payload;
|
||||
},
|
||||
changefilterName: (state, action) => {
|
||||
state.filterName = action.payload;
|
||||
},
|
||||
changeSelectedCategoryVideos: (state, action) => {
|
||||
state.selectedCategoryVideos = action.payload;
|
||||
},
|
||||
changeSelectedSubCategoryVideos: (state, action) => {
|
||||
state.selectedSubCategoryVideos = action.payload;
|
||||
},
|
||||
setCountNewVideos: (state, action) => {
|
||||
state.countNewVideos = action.payload;
|
||||
},
|
||||
addVideos: (state, action) => {
|
||||
state.videos = action.payload;
|
||||
},
|
||||
addFilteredVideos: (state, action) => {
|
||||
state.filteredVideos = action.payload;
|
||||
},
|
||||
removeVideo: (state, action) => {
|
||||
const idToDelete = action.payload;
|
||||
state.videos = state.videos.filter(item => item.id !== idToDelete);
|
||||
state.filteredVideos = state.filteredVideos.filter(
|
||||
item => item.id !== idToDelete
|
||||
);
|
||||
},
|
||||
addVideoToBeginning: (state, action) => {
|
||||
state.videos.unshift(action.payload);
|
||||
},
|
||||
clearVideoList: state => {
|
||||
state.videos = [];
|
||||
},
|
||||
updateVideo: (state, action) => {
|
||||
const { id } = action.payload;
|
||||
const index = state.videos.findIndex(video => video.id === id);
|
||||
if (index !== -1) {
|
||||
state.videos[index] = { ...action.payload };
|
||||
}
|
||||
const index2 = state.filteredVideos.findIndex(video => video.id === id);
|
||||
if (index2 !== -1) {
|
||||
state.filteredVideos[index2] = { ...action.payload };
|
||||
}
|
||||
},
|
||||
addToHashMap: (state, action) => {
|
||||
const video = action.payload;
|
||||
state.hashMapVideos[video.id + "-" + video.user] = video;
|
||||
},
|
||||
addtoHashMapSuperlikes: (state, action) => {
|
||||
const superlike = action.payload;
|
||||
state.hashMapSuperlikes[superlike.identifier] = superlike;
|
||||
},
|
||||
updateInHashMap: (state, action) => {
|
||||
const { id, user } = action.payload;
|
||||
const video = action.payload;
|
||||
state.hashMapVideos[id + "-" + user] = { ...video };
|
||||
},
|
||||
removeFromHashMap: (state, action) => {
|
||||
const idToDelete = action.payload;
|
||||
delete state.hashMapVideos[idToDelete];
|
||||
},
|
||||
addArrayToHashMap: (state, action) => {
|
||||
const videos = action.payload;
|
||||
videos.forEach((video: Video) => {
|
||||
state.hashMapVideos[video.id + "-" + video.user] = video;
|
||||
});
|
||||
},
|
||||
upsertVideos: (state, action) => {
|
||||
action.payload.forEach((video: Video) => {
|
||||
const index = state.videos.findIndex(p => p.id === video.id);
|
||||
if (index !== -1) {
|
||||
state.videos[index] = video;
|
||||
} else {
|
||||
state.videos.push(video);
|
||||
}
|
||||
});
|
||||
},
|
||||
upsertFilteredVideos: (state, action) => {
|
||||
action.payload.forEach((video: Video) => {
|
||||
const index = state.filteredVideos.findIndex(p => p.id === video.id);
|
||||
if (index !== -1) {
|
||||
state.filteredVideos[index] = video;
|
||||
} else {
|
||||
state.filteredVideos.push(video);
|
||||
}
|
||||
});
|
||||
},
|
||||
upsertVideosBeginning: (state, action) => {
|
||||
action.payload.reverse().forEach((video: Video) => {
|
||||
const index = state.videos.findIndex(p => p.id === video.id);
|
||||
if (index !== -1) {
|
||||
state.videos[index] = video;
|
||||
} else {
|
||||
state.videos.unshift(video);
|
||||
}
|
||||
});
|
||||
},
|
||||
setIsFiltering: (state, action) => {
|
||||
state.isFiltering = action.payload;
|
||||
},
|
||||
setFilterValue: (state, action) => {
|
||||
state.filterValue = action.payload;
|
||||
},
|
||||
blockUser: (state, action) => {
|
||||
const username = action.payload;
|
||||
|
||||
state.videos = state.videos.filter(item => item.user !== username);
|
||||
state.videos = state.videos.filter((item) => item.user !== username);
|
||||
},
|
||||
|
||||
setFilteredSubscriptions: (
|
||||
state,
|
||||
action: PayloadAction<SubscriptionData[]>
|
||||
) => {
|
||||
state.filteredSubscriptionList = action.payload;
|
||||
},
|
||||
resetVideoState: () => initialState,
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
setCountNewVideos,
|
||||
addVideos,
|
||||
addFilteredVideos,
|
||||
removeVideo,
|
||||
addVideoToBeginning,
|
||||
updateVideo,
|
||||
addToHashMap,
|
||||
updateInHashMap,
|
||||
removeFromHashMap,
|
||||
addArrayToHashMap,
|
||||
upsertVideos,
|
||||
upsertFilteredVideos,
|
||||
upsertVideosBeginning,
|
||||
setIsFiltering,
|
||||
setFilterValue,
|
||||
clearVideoList,
|
||||
changefilterSearch,
|
||||
changefilterName,
|
||||
changeSelectedCategoryVideos,
|
||||
changeSelectedSubCategoryVideos,
|
||||
blockUser,
|
||||
setEditVideo,
|
||||
setEditPlaylist,
|
||||
addtoHashMapSuperlikes,
|
||||
setFilteredSubscriptions,
|
||||
resetVideoState
|
||||
} = videoSlice.actions;
|
||||
export const { blockUser } = videoSlice.actions;
|
||||
|
||||
export default videoSlice.reducer;
|
||||
|
||||
@@ -2,4 +2,24 @@ import { atom } from 'jotai';
|
||||
|
||||
type SuperLikes = any[];
|
||||
|
||||
interface Superlike {
|
||||
identifier: string;
|
||||
[key: string]: any; // You can define more fields as needed
|
||||
}
|
||||
|
||||
// Atom to hold the hashMapSuperlikes
|
||||
export const hashMapSuperlikesAtom = atom<Record<string, Superlike>>({});
|
||||
|
||||
// Write-only atom to add a superlike
|
||||
export const addToHashMapSuperlikesAtom = atom(
|
||||
null,
|
||||
(get, set, superlike: Superlike) => {
|
||||
const prev = get(hashMapSuperlikesAtom);
|
||||
set(hashMapSuperlikesAtom, {
|
||||
...prev,
|
||||
[superlike.identifier]: superlike,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export const superlikesAtom = atom<SuperLikes>([]);
|
||||
|
||||
3
src/state/publish/playlist.ts
Normal file
3
src/state/publish/playlist.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { atom } from 'jotai';
|
||||
|
||||
export const editPlaylistAtom = atom<any>(null);
|
||||
3
src/state/publish/video.ts
Normal file
3
src/state/publish/video.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { atom } from 'jotai';
|
||||
|
||||
export const editVideoAtom = atom<any>(null);
|
||||
@@ -5,7 +5,6 @@ import React, {
|
||||
useRef,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import {
|
||||
extractSigValue,
|
||||
getPaymentInfo,
|
||||
@@ -35,7 +34,6 @@ export const queue = new RequestQueue();
|
||||
export const queueSuperlikes = new RequestQueue();
|
||||
|
||||
const GlobalWrapper: React.FC<Props> = ({ children }) => {
|
||||
const dispatch = useDispatch();
|
||||
const setSuperlikesAll = useSetAtom(superlikesAtom);
|
||||
const { addSuperlikeRawDataGetToList } = useFetchSuperLikes();
|
||||
const interval = useRef<any>(null);
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": false,
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"strictNullChecks": false,
|
||||
"types": ["node", "qapp-core/global"]
|
||||
},
|
||||
"include": ["src"],
|
||||
|
||||
Reference in New Issue
Block a user