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

Fixed Bug that allowed publishing issue with non-unique title if the title consisted only of characters that are filtered out when sanitized.

More references to Q-Share removed. Issue page has its routing change from /share to /issue

Consent modal changed app name from Q-Share to Q-Support

User can no longer block themselves

Edit and Block buttons in IssueList.tsx no longer have tooltips. Instead, a description is in text visible when the button is loaded to make it easier to see both the button as a whole as well as what it does.
This commit is contained in:
Qortal Dev 2024-04-16 16:01:03 -06:00
parent 7d700ccc74
commit 92f5c236b6
15 changed files with 252 additions and 272 deletions

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Q-Share</title> <title>Q-Support</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@ -26,7 +26,7 @@ function App() {
<CssBaseline /> <CssBaseline />
<Routes> <Routes>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home />} />
<Route path="/share/:name/:id" element={<IssueContent />} /> <Route path="/issue/:name/:id" element={<IssueContent />} />
<Route path="/channel/:name" element={<IndividualProfile />} /> <Route path="/channel/:name" element={<IndividualProfile />} />
</Routes> </Routes>
</GlobalWrapper> </GlobalWrapper>

View File

@ -144,7 +144,6 @@ export const EditIssue = () => {
async function publishQDNResource() { async function publishQDNResource() {
try { try {
const categoryList = categoryListRef.current?.getSelectedCategories(); const categoryList = categoryListRef.current?.getSelectedCategories();
if (!title) throw new Error("Please enter a title");
if (!description) throw new Error("Please enter a description"); if (!description) throw new Error("Please enter a description");
if (!categoryList[0]) throw new Error("Please select a category"); if (!categoryList[0]) throw new Error("Please select a category");
if (!editFileProperties) return; if (!editFileProperties) return;
@ -173,10 +172,6 @@ export const EditIssue = () => {
); );
return; return;
} }
let fileReferences = [];
let listOfPublishes = [];
const fullDescription = extractTextFromHTML(description);
const sanitizeTitle = title const sanitizeTitle = title
.replace(/[^a-zA-Z0-9\s-]/g, "") .replace(/[^a-zA-Z0-9\s-]/g, "")
@ -185,6 +180,12 @@ export const EditIssue = () => {
.trim() .trim()
.toLowerCase(); .toLowerCase();
if (!sanitizeTitle) throw new Error("Please enter a title");
let fileReferences = [];
let listOfPublishes = [];
const fullDescription = extractTextFromHTML(description);
for (const publish of files) { for (const publish of files) {
if (publish?.identifier) { if (publish?.identifier) {
fileReferences.push(publish); fileReferences.push(publish);

View File

@ -219,7 +219,6 @@ export const EditPlaylist = () => {
async function publishQDNResource() { async function publishQDNResource() {
try { try {
if (!title) throw new Error("Please enter a title");
if (!description) throw new Error("Please enter a description"); if (!description) throw new Error("Please enter a description");
if (!coverImage) throw new Error("Please select cover image"); if (!coverImage) throw new Error("Please select cover image");
if (!selectedCategoryVideos) throw new Error("Please select a category"); if (!selectedCategoryVideos) throw new Error("Please select a category");
@ -249,6 +248,16 @@ export const EditPlaylist = () => {
); );
return; return;
} }
const sanitizeTitle = title
.replace(/[^a-zA-Z0-9\s-]/g, "")
.replace(/\s+/g, "-")
.replace(/-+/g, "-")
.trim()
.toLowerCase();
if (!sanitizeTitle) throw new Error("Please enter a title");
const category = selectedCategoryVideos.id; const category = selectedCategoryVideos.id;
const subcategory = selectedSubCategoryVideos?.id || ""; const subcategory = selectedSubCategoryVideos?.id || "";
@ -308,12 +317,7 @@ export const EditPlaylist = () => {
// Description is obtained from raw data // Description is obtained from raw data
let identifier = editVideoProperties?.id; let identifier = editVideoProperties?.id;
const sanitizeTitle = title
.replace(/[^a-zA-Z0-9\s-]/g, "")
.replace(/\s+/g, "-")
.replace(/-+/g, "-")
.trim()
.toLowerCase();
if (isNew) { if (isNew) {
identifier = `${QSUPPORT_PLAYLIST_BASE}${sanitizeTitle.slice(0, 30)}_${id}`; identifier = `${QSUPPORT_PLAYLIST_BASE}${sanitizeTitle.slice(0, 30)}_${id}`;
} }

View File

@ -128,8 +128,6 @@ export const PublishIssue = ({ editId, editContent }: NewCrowdfundProps) => {
try { try {
if (!categoryListRef.current) throw new Error("No CategoryListRef found"); if (!categoryListRef.current) throw new Error("No CategoryListRef found");
if (!userAddress) throw new Error("Unable to locate user address"); if (!userAddress) throw new Error("Unable to locate user address");
if (!title) throw new Error("Please enter a title");
if (!description) throw new Error("Please enter a description"); if (!description) throw new Error("Please enter a description");
if (!categoryListRef.current?.getSelectedCategories()[0]) if (!categoryListRef.current?.getSelectedCategories()[0])
throw new Error("Please select a category"); throw new Error("Please select a category");
@ -157,18 +155,19 @@ export const PublishIssue = ({ editId, editContent }: NewCrowdfundProps) => {
return; return;
} }
let fileReferences = [];
let listOfPublishes = [];
const fullDescription = extractTextFromHTML(description);
const sanitizeTitle = title const sanitizeTitle = title
.replace(/[^a-zA-Z0-9\s-]/g, "") .replace(/[^a-zA-Z0-9\s-]/g, "")
.replace(/\s+/g, "-") .replace(/\s+/g, "-")
.replace(/-+/g, "-") .replace(/-+/g, "-")
.trim() .trim()
.toLowerCase(); .toLowerCase();
if (!sanitizeTitle) throw new Error("Please enter a title");
let fileReferences = [];
let listOfPublishes = [];
const fullDescription = extractTextFromHTML(description);
for (const publish of files) { for (const publish of files) {
const file = publish.file; const file = publish.file;

View File

@ -1,28 +1,24 @@
import { styled } from '@mui/system'; import { styled } from "@mui/system";
import { import { Box, Modal, Typography } from "@mui/material";
Box,
Modal,
Typography
} from '@mui/material';
export const StyledModal = styled(Modal)(({ theme }) => ({ export const StyledModal = styled(Modal)(({ theme }) => ({
display: 'flex', display: "flex",
alignItems: 'center', alignItems: "center",
justifyContent: 'center' justifyContent: "center",
})) }));
export const ModalContent = styled(Box)(({ theme }) => ({ export const ModalContent = styled(Box)(({ theme }) => ({
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.background.default,
padding: theme.spacing(4), padding: theme.spacing(4),
borderRadius: theme.spacing(1), borderRadius: theme.spacing(1),
width: '40%', width: "40%",
'&:focus': { "&:focus": {
outline: 'none' outline: "none",
} },
})) }));
export const ModalText = styled(Typography)(({ theme }) => ({ export const ModalText = styled(Typography)(({ theme }) => ({
fontFamily: "Raleway", fontFamily: "Raleway",
fontSize: "25px", fontSize: "25px",
color: theme.palette.text.primary, color: theme.palette.text.primary,
})); }));

View File

@ -1,18 +1,9 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Button, List, ListItem, Typography, useTheme } from "@mui/material";
import { import {
Box,
Button,
Modal,
Typography,
SelectChangeEvent,
ListItem,
List,
useTheme
} from "@mui/material";
import {
StyledModal,
ModalContent, ModalContent,
ModalText ModalText,
StyledModal,
} from "./BlockedNamesModal-styles"; } from "./BlockedNamesModal-styles";
interface PostModalProps { interface PostModalProps {
@ -22,7 +13,7 @@ interface PostModalProps {
export const BlockedNamesModal: React.FC<PostModalProps> = ({ export const BlockedNamesModal: React.FC<PostModalProps> = ({
open, open,
onClose onClose,
}) => { }) => {
const [blockedNames, setBlockedNames] = useState<string[]>([]); const [blockedNames, setBlockedNames] = useState<string[]>([]);
const theme = useTheme(); const theme = useTheme();
@ -31,7 +22,7 @@ export const BlockedNamesModal: React.FC<PostModalProps> = ({
const listName = `blockedNames`; const listName = `blockedNames`;
const response = await qortalRequest({ const response = await qortalRequest({
action: "GET_LIST_ITEMS", action: "GET_LIST_ITEMS",
list_name: listName list_name: listName,
}); });
setBlockedNames(response); setBlockedNames(response);
} catch (error) { } catch (error) {
@ -48,11 +39,11 @@ export const BlockedNamesModal: React.FC<PostModalProps> = ({
const response = await qortalRequest({ const response = await qortalRequest({
action: "DELETE_LIST_ITEM", action: "DELETE_LIST_ITEM",
list_name: "blockedNames", list_name: "blockedNames",
item: name item: name,
}); });
if (response === true) { if (response === true) {
setBlockedNames((prev) => prev.filter((n) => n !== name)); setBlockedNames(prev => prev.filter(n => n !== name));
} }
} catch (error) {} } catch (error) {}
}; };
@ -67,22 +58,22 @@ export const BlockedNamesModal: React.FC<PostModalProps> = ({
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
flex: "1", flex: "1",
overflow: "auto" overflow: "auto",
}} }}
> >
{blockedNames.map((name, index) => ( {blockedNames.map((name, index) => (
<ListItem <ListItem
key={name + index} key={name + index}
sx={{ sx={{
display: "flex" display: "flex",
}} }}
> >
<Typography>{name}</Typography> <Typography>{name}</Typography>
<Button <Button
sx={{ sx={{
backgroundColor: theme.palette.primary.light, backgroundColor: theme.palette.primary.main,
color: theme.palette.text.primary, color: theme.palette.text.primary,
fontFamily: "Raleway" fontFamily: "Raleway",
}} }}
onClick={() => removeFromBlockList(name)} onClick={() => removeFromBlockList(name)}
> >
@ -91,7 +82,15 @@ export const BlockedNamesModal: React.FC<PostModalProps> = ({
</ListItem> </ListItem>
))} ))}
</List> </List>
<Button variant="contained" color="primary" onClick={onClose}> <Button
variant="contained"
onClick={onClose}
sx={{
backgroundColor: theme.palette.primary.light,
color: theme.palette.text.primary,
fontFamily: "Raleway",
}}
>
Close Close
</Button> </Button>
</ModalContent> </ModalContent>

View File

@ -7,8 +7,9 @@ import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle"; import DialogTitle from "@mui/material/DialogTitle";
import localForage from "localforage"; import localForage from "localforage";
import { useTheme } from "@mui/material"; import { useTheme } from "@mui/material";
const generalLocal = localForage.createInstance({ const generalLocal = localForage.createInstance({
name: "q-share-general", name: "q-support-general",
}); });
export default function ConsentModal() { export default function ConsentModal() {
@ -44,13 +45,15 @@ export default function ConsentModal() {
<DialogTitle id="alert-dialog-title">Welcome</DialogTitle> <DialogTitle id="alert-dialog-title">Welcome</DialogTitle>
<DialogContent> <DialogContent>
<DialogContentText id="alert-dialog-description"> <DialogContentText id="alert-dialog-description">
Q-Share is currently in its first version and as such there could be Q-Support is currently in its first version and as such there could
some bugs. The Qortal community, along with its development team and be some bugs. The Qortal community, along with its development team
the creators of this application, cannot be held accountable for any and the creators of this application, cannot be held accountable for
content published or displayed. Also, they are not responsible for any content published or displayed. Also, they are not responsible
any loss of coin due to either bad actors or bugs in the for any loss of coin due to either bad actors or bugs in the
application. Furthermore, they bear no responsibility for any data application. Furthermore, they bear no responsibility for any data
loss that may occur as a result of using this application. Finally, they bear no responsibility for any of the content uploaded by users. loss that may occur as a result of using this application. Finally,
they bear no responsibility for any of the content uploaded by
users.
</DialogContentText> </DialogContentText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>

View File

@ -1,8 +1,5 @@
import React, { useState, useEffect } from 'react' import React, { useEffect, useState } from "react";
import { import {
Accordion,
AccordionDetails,
AccordionSummary,
Box, Box,
Button, Button,
LinearProgress, LinearProgress,
@ -11,30 +8,26 @@ import {
ListItemIcon, ListItemIcon,
Popover, Popover,
Typography, Typography,
useTheme useTheme,
} from '@mui/material' } from "@mui/material";
import { Movie } from '@mui/icons-material' import { useSelector } from "react-redux";
import { useSelector } from 'react-redux' import { RootState } from "../../state/store";
import { RootState } from '../../state/store' import { useLocation, useNavigate } from "react-router-dom";
import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import { DownloadingLight } from "../../assets/svgs/DownloadingLight";
import { useLocation, useNavigate } from 'react-router-dom' import { DownloadedLight } from "../../assets/svgs/DownloadedLight";
import { DownloadingLight } from '../../assets/svgs/DownloadingLight'
import { DownloadedLight } from '../../assets/svgs/DownloadedLight'
import AttachFileIcon from "@mui/icons-material/AttachFile"; import AttachFileIcon from "@mui/icons-material/AttachFile";
export const DownloadTaskManager: React.FC = () => { export const DownloadTaskManager: React.FC = () => {
const { downloads } = useSelector((state: RootState) => state.global) const { downloads } = useSelector((state: RootState) => state.global);
const location = useLocation() const location = useLocation();
const theme = useTheme() const theme = useTheme();
const [visible, setVisible] = useState(false) const [visible, setVisible] = useState(false);
const [hidden, setHidden] = useState(true) const [hidden, setHidden] = useState(true);
const navigate = useNavigate() const navigate = useNavigate();
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null); const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const [openDownload, setOpenDownload] = useState<boolean>(false); const [openDownload, setOpenDownload] = useState<boolean>(false);
const handleClick = (event?: React.MouseEvent<HTMLDivElement>) => { const handleClick = (event?: React.MouseEvent<HTMLDivElement>) => {
const target = event?.currentTarget as unknown as HTMLButtonElement | null; const target = event?.currentTarget as unknown as HTMLButtonElement | null;
setAnchorEl(target); setAnchorEl(target);
@ -50,155 +43,150 @@ export const DownloadTaskManager: React.FC = () => {
if (visible) { if (visible) {
setTimeout(() => { setTimeout(() => {
setHidden(true) setHidden(true);
setVisible(false) setVisible(false);
}, 3000) }, 3000);
} }
}, [visible]) }, [visible]);
useEffect(() => { useEffect(() => {
if (Object.keys(downloads).length === 0) return if (Object.keys(downloads).length === 0) return;
setVisible(true) setVisible(true);
setHidden(false) setHidden(false);
}, [downloads]) }, [downloads]);
if (!downloads || Object.keys(downloads).length === 0) return null;
let downloadInProgress = false;
if ( if (
!downloads || Object.keys(downloads).find(
Object.keys(downloads).length === 0 key =>
) downloads[key]?.status?.status !== "READY" &&
return null downloads[key]?.status?.status !== "DOWNLOADED"
)
) {
let downloadInProgress = false downloadInProgress = true;
if(Object.keys(downloads).find((key)=> (downloads[key]?.status?.status !== 'READY' && downloads[key]?.status?.status !== 'DOWNLOADED'))){
downloadInProgress = true
} }
return ( return (
<Box> <Box>
<Button onClick={(e: any) => { <Button
handleClick(e); onClick={(e: any) => {
setOpenDownload(true); handleClick(e);
}}> setOpenDownload(true);
{downloadInProgress ? ( }}
<DownloadingLight height='24px' width='24px' className='download-icon' /> >
) : ( {downloadInProgress ? (
<DownloadedLight height='24px' width='24px' /> <DownloadingLight
)} height="24px"
width="24px"
</Button> className="download-icon"
/>
<Popover ) : (
id={"download-popover"} <DownloadedLight height="24px" width="24px" />
open={openDownload} )}
anchorEl={anchorEl} </Button>
onClose={handleCloseDownload}
anchorOrigin={{ <Popover
vertical: "bottom", id={"download-popover"}
horizontal: "left" open={openDownload}
anchorEl={anchorEl}
onClose={handleCloseDownload}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
>
<List
sx={{
maxHeight: "50vh",
overflow: "auto",
width: "250px",
gap: "5px",
display: "flex",
flexDirection: "column",
}} }}
> >
<List {Object.keys(downloads).map((download: any) => {
sx={{ const downloadObj = downloads[download];
maxHeight: '50vh', const progress = downloads[download]?.status?.percentLoaded || 0;
overflow: 'auto', const status = downloads[download]?.status?.status;
width: '250px', const service = downloads[download]?.service;
gap: '5px', return (
display: 'flex', <ListItem
flexDirection: 'column', key={downloadObj?.identifier}
sx={{
}} display: "flex",
> flexDirection: "column",
{Object.keys(downloads) width: "100%",
.map((download: any) => { justifyContent: "center",
const downloadObj = downloads[download] background: theme.palette.primary.main,
const progress = downloads[download]?.status?.percentLoaded || 0 color: theme.palette.text.primary,
const status = downloads[download]?.status?.status cursor: "pointer",
const service = downloads[download]?.service padding: "2px",
return ( }}
<ListItem onClick={() => {
key={downloadObj?.identifier} const id = downloadObj?.properties?.jsonId;
sx={{ if (!id) return;
display: 'flex',
flexDirection: 'column',
width: '100%',
justifyContent: 'center',
background: theme.palette.primary.main,
color: theme.palette.text.primary,
cursor: 'pointer',
padding: '2px',
}}
onClick={() => {
const id = downloadObj?.properties?.jsonId
if (!id) return
navigate(
`/share/${downloadObj?.properties?.name}/${id}`
)
}}
>
<Box
sx={{
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between'
}}
>
<ListItemIcon>
<AttachFileIcon sx={{ color: theme.palette.text.primary }} />
</ListItemIcon>
<Box navigate(`/issue/${downloadObj?.properties?.name}/${id}`);
sx={{ width: '100px', marginLeft: 1, marginRight: 1 }} }}
> >
<LinearProgress <Box
variant="determinate" sx={{
value={progress} width: "100%",
sx={{ display: "flex",
borderRadius: '5px', alignItems: "center",
color: theme.palette.secondary.main justifyContent: "space-between",
}} }}
/> >
</Box> <ListItemIcon>
<Typography <AttachFileIcon
sx={{ sx={{ color: theme.palette.text.primary }}
fontFamily: 'Arial', />
color: theme.palette.text.primary </ListItemIcon>
}}
variant="caption" <Box sx={{ width: "100px", marginLeft: 1, marginRight: 1 }}>
> <LinearProgress
{`${progress?.toFixed(0)}%`}{' '} variant="determinate"
{status && status === 'REFETCHING' && '- refetching'} value={progress}
{status && status === 'DOWNLOADED' && '- building'}
</Typography>
</Box>
<Typography
sx={{ sx={{
fontSize: '10px', borderRadius: "5px",
width: '100%', color: theme.palette.secondary.main,
textAlign: 'end',
fontFamily: 'Arial',
color: theme.palette.text.primary,
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
}} }}
> />
{downloadObj?.identifier} </Box>
</Typography> <Typography
</ListItem> sx={{
) fontFamily: "Arial",
})} color: theme.palette.text.primary,
</List> }}
</Popover> variant="caption"
>
{`${progress?.toFixed(0)}%`}{" "}
{status && status === "REFETCHING" && "- refetching"}
{status && status === "DOWNLOADED" && "- building"}
</Typography>
</Box>
<Typography
sx={{
fontSize: "10px",
width: "100%",
textAlign: "end",
fontFamily: "Arial",
color: theme.palette.text.primary,
textOverflow: "ellipsis",
whiteSpace: "nowrap",
overflow: "hidden",
}}
>
{downloadObj?.identifier}
</Typography>
</ListItem>
);
})}
</List>
</Popover>
</Box> </Box>
);
) };
}

View File

@ -1,4 +1,4 @@
const useTestIdentifiers = false; const useTestIdentifiers = true;
export const QSUPPORT_FILE_BASE = useTestIdentifiers export const QSUPPORT_FILE_BASE = useTestIdentifiers
? "MYTEST_support_issue_" ? "MYTEST_support_issue_"

View File

@ -1,21 +1,10 @@
import React, { useCallback, useEffect, useRef, useState } from "react"; import React from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { RootState } from "../../state/store"; import { RootState } from "../../state/store";
import { Avatar, Box, Button, Typography, useTheme } from "@mui/material"; import { Box, useTheme } from "@mui/material";
import { useFetchFiles } from "../../hooks/useFetchFiles.tsx"; import { FileContainer } from "./IssueList-styles.tsx";
import LazyLoad from "../../components/common/LazyLoad";
import {
BottomParent,
NameContainer,
VideoCard,
VideoCardName,
VideoCardTitle,
FileContainer,
VideoUploadDate,
} from "./FileList-styles.tsx";
import ResponsiveImage from "../../components/ResponsiveImage"; import ResponsiveImage from "../../components/ResponsiveImage";
import { formatDate, formatTimestampSeconds } from "../../utils/time";
import { ChannelCard, ChannelTitle } from "./Home-styles"; import { ChannelCard, ChannelTitle } from "./Home-styles";
interface VideoListProps { interface VideoListProps {

View File

@ -15,7 +15,7 @@ import {
VideoCardName, VideoCardName,
VideoCardTitle, VideoCardTitle,
VideoUploadDate, VideoUploadDate,
} from "./FileList-styles.tsx"; } from "./IssueList-styles.tsx";
import { formatDate } from "../../utils/time"; import { formatDate } from "../../utils/time";
import { Video } from "../../state/features/fileSlice.ts"; import { Video } from "../../state/features/fileSlice.ts";
import { queue } from "../../wrappers/GlobalWrapper"; import { queue } from "../../wrappers/GlobalWrapper";
@ -149,7 +149,7 @@ export const FileListComponentLevel = ({ mode }: VideoListProps) => {
<> <>
<VideoCard <VideoCard
onClick={() => { onClick={() => {
navigate(`/share/${fileObj?.user}/${fileObj?.id}`); navigate(`/issue/${fileObj?.user}/${fileObj?.id}`);
}} }}
sx={{ sx={{
height: "100%", height: "100%",

View File

@ -2,11 +2,11 @@ import React, { useEffect, useRef, useState } from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../../state/store"; import { RootState } from "../../state/store";
import { FileList } from "./FileList.tsx"; import { IssueList } from "./IssueList.tsx";
import { Box, Button, Grid, Input, useTheme } from "@mui/material"; import { Box, Button, Grid, Input, useTheme } from "@mui/material";
import { useFetchFiles } from "../../hooks/useFetchFiles.tsx"; import { useFetchFiles } from "../../hooks/useFetchFiles.tsx";
import LazyLoad from "../../components/common/LazyLoad"; import LazyLoad from "../../components/common/LazyLoad";
import { FiltersCol, FiltersContainer } from "./FileList-styles.tsx"; import { FiltersCol, FiltersContainer } from "./IssueList-styles.tsx";
import { SubtitleContainer } from "./Home-styles"; import { SubtitleContainer } from "./Home-styles";
import { import {
changefilterName, changefilterName,
@ -315,7 +315,7 @@ export const Home = ({ mode }: HomeProps) => {
maxWidth: "1400px", maxWidth: "1400px",
}} }}
></SubtitleContainer> ></SubtitleContainer>
<FileList files={videos} /> <IssueList files={videos} />
<LazyLoad <LazyLoad
onLoadMore={getFilesHandler} onLoadMore={getFilesHandler}
isLoading={isLoading} isLoading={isLoading}

View File

@ -1,12 +1,12 @@
import { styled } from "@mui/system"; import { styled } from "@mui/system";
import { import {
Box,
Grid,
Typography,
Checkbox,
TextField,
InputLabel,
Autocomplete, Autocomplete,
Box,
Checkbox,
Grid,
InputLabel,
TextField,
Typography,
} from "@mui/material"; } from "@mui/material";
export const FileContainer = styled(Box)(({ theme }) => ({ export const FileContainer = styled(Box)(({ theme }) => ({
@ -283,6 +283,7 @@ export const BlockIconContainer = styled(Box)({
padding: "2px", padding: "2px",
borderRadius: "3px", borderRadius: "3px",
transition: "all 0.3s ease-in-out", transition: "all 0.3s ease-in-out",
fontSize: "18px",
"&:hover": { "&:hover": {
cursor: "pointer", cursor: "pointer",
transform: "scale(1.1)", transform: "scale(1.1)",

View File

@ -1,4 +1,4 @@
import { Avatar, Box, Skeleton, Tooltip } from "@mui/material"; import { Avatar, Box, Skeleton } from "@mui/material";
import { import {
BlockIconContainer, BlockIconContainer,
BottomParent, BottomParent,
@ -9,7 +9,7 @@ import {
VideoCardName, VideoCardName,
VideoCardTitle, VideoCardTitle,
VideoUploadDate, VideoUploadDate,
} from "./FileList-styles.tsx"; } from "./IssueList-styles.tsx";
import EditIcon from "@mui/icons-material/Edit"; import EditIcon from "@mui/icons-material/Edit";
import { import {
blockUser, blockUser,
@ -29,7 +29,7 @@ import { getIconsFromObject } from "../../constants/Categories/CategoryFunctions
interface FileListProps { interface FileListProps {
files: Video[]; files: Video[];
} }
export const FileList = ({ files }: FileListProps) => { export const IssueList = ({ files }: FileListProps) => {
const hashMapFiles = useSelector( const hashMapFiles = useSelector(
(state: RootState) => state.file.hashMapFiles (state: RootState) => state.file.hashMapFiles
); );
@ -40,7 +40,7 @@ export const FileList = ({ files }: FileListProps) => {
const navigate = useNavigate(); const navigate = useNavigate();
const blockUserFunc = async (user: string) => { const blockUserFunc = async (user: string) => {
if (user === "Q-Share") return; if (user === "Q-Support") return;
try { try {
const response = await qortalRequest({ const response = await qortalRequest({
@ -88,30 +88,30 @@ export const FileList = ({ files }: FileListProps) => {
}} }}
> >
{fileObj?.user === username && ( {fileObj?.user === username && (
<Tooltip title="Edit Issue Properties" placement="top"> <BlockIconContainer
<BlockIconContainer> onClick={() => {
<EditIcon dispatch(setEditFile(fileObj));
onClick={() => { }}
dispatch(setEditFile(fileObj)); >
}} <EditIcon />
/> Edit Issue
</BlockIconContainer> </BlockIconContainer>
</Tooltip>
)} )}
<Tooltip title="Block user content" placement="top"> {fileObj?.user !== username && (
<BlockIconContainer> <BlockIconContainer
<BlockIcon onClick={() => {
onClick={() => { blockUserFunc(fileObj?.user);
blockUserFunc(fileObj?.user); }}
}} >
/> <BlockIcon />
Block User
</BlockIconContainer> </BlockIconContainer>
</Tooltip> )}
</IconsBox> </IconsBox>
<VideoCard <VideoCard
onClick={() => { onClick={() => {
navigate(`/share/${fileObj?.user}/${fileObj?.id}`); navigate(`/issue/${fileObj?.user}/${fileObj?.id}`);
}} }}
sx={{ sx={{
height: "100%", height: "100%",