Upload files to "src/pages/Home"
This commit is contained in:
352
src/pages/Home/Home.tsx
Normal file
352
src/pages/Home/Home.tsx
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
import { Box, Grid, Input, useTheme } from "@mui/material";
|
||||||
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import {
|
||||||
|
AutocompleteQappNames,
|
||||||
|
getPublishedQappNames,
|
||||||
|
QappNamesRef,
|
||||||
|
} from "../../components/common/AutocompleteQappNames.tsx";
|
||||||
|
import {
|
||||||
|
CategoryList,
|
||||||
|
CategoryListRef,
|
||||||
|
getCategoriesFetchString,
|
||||||
|
} from "../../components/common/CategoryList/CategoryList.tsx";
|
||||||
|
import {
|
||||||
|
CategorySelect,
|
||||||
|
CategorySelectRef,
|
||||||
|
} from "../../components/common/CategoryList/CategorySelect.tsx";
|
||||||
|
import LazyLoad from "../../components/common/LazyLoad";
|
||||||
|
import { StatsData } from "../../components/StatsData.tsx";
|
||||||
|
import {
|
||||||
|
allCategories,
|
||||||
|
allCategoryData,
|
||||||
|
} from "../../constants/Categories/Categories.ts";
|
||||||
|
import { useFetchIssues } from "../../hooks/useFetchIssues.tsx";
|
||||||
|
import {
|
||||||
|
changefilterName,
|
||||||
|
changefilterSearch,
|
||||||
|
changeFilterType,
|
||||||
|
setQappNames,
|
||||||
|
} from "../../state/features/fileSlice.ts";
|
||||||
|
import { RootState } from "../../state/store";
|
||||||
|
import { SubtitleContainer, ThemeButton } from "./Home-styles";
|
||||||
|
import { FiltersCol, FiltersContainer } from "./IssueList-styles.tsx";
|
||||||
|
import { IssueList } from "./IssueList.tsx";
|
||||||
|
|
||||||
|
interface HomeProps {
|
||||||
|
mode?: string;
|
||||||
|
}
|
||||||
|
export const Home = ({ mode }: HomeProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isFiltering = useSelector((state: RootState) => state.file.isFiltering);
|
||||||
|
const filterValue = useSelector((state: RootState) => state.file.filterValue);
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
const filterType = useSelector((state: RootState) => state.file.filterType);
|
||||||
|
|
||||||
|
const setFilterType = payload => {
|
||||||
|
dispatch(changeFilterType(payload));
|
||||||
|
};
|
||||||
|
const filterSearch = useSelector(
|
||||||
|
(state: RootState) => state.file.filterSearch
|
||||||
|
);
|
||||||
|
const QappNames = useSelector(
|
||||||
|
(state: RootState) => state.file.publishedQappNames
|
||||||
|
);
|
||||||
|
const autocompleteRef = useRef<QappNamesRef>(null);
|
||||||
|
|
||||||
|
const setFilterSearch = payload => {
|
||||||
|
dispatch(changefilterSearch(payload));
|
||||||
|
};
|
||||||
|
const filterName = useSelector((state: RootState) => state.file.filterName);
|
||||||
|
|
||||||
|
const setFilterName = payload => {
|
||||||
|
dispatch(changefilterName(payload));
|
||||||
|
};
|
||||||
|
|
||||||
|
const isFilterMode = useRef(false);
|
||||||
|
const firstFetch = useRef(false);
|
||||||
|
const afterFetch = useRef(false);
|
||||||
|
const isFetching = useRef(false);
|
||||||
|
const prevVal = useRef("");
|
||||||
|
const categoryListRef = useRef<CategoryListRef>(null);
|
||||||
|
const categorySelectRef = useRef<CategorySelectRef>(null);
|
||||||
|
|
||||||
|
const [showCategoryList, setShowCategoryList] = useState<boolean>(true);
|
||||||
|
const [showCategorySelect, setShowCategorySelect] = useState<boolean>(true);
|
||||||
|
const { files: globalVideos } = useSelector((state: RootState) => state.file);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const filteredFiles = useSelector(
|
||||||
|
(state: RootState) => state.file.filteredFiles
|
||||||
|
);
|
||||||
|
|
||||||
|
const [QappNamesParam, setQappNamesParam] = useState<string[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getPublishedQappNames().then(QappNamesResult => {
|
||||||
|
dispatch(setQappNames(QappNamesResult));
|
||||||
|
setQappNamesParam(QappNamesResult);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const {
|
||||||
|
getIssues,
|
||||||
|
checkAndUpdateIssue,
|
||||||
|
getIssue,
|
||||||
|
hashMapFiles,
|
||||||
|
getNewIssues,
|
||||||
|
checkNewIssues,
|
||||||
|
getIssuesFiltered,
|
||||||
|
getIssuesCount,
|
||||||
|
} = useFetchIssues();
|
||||||
|
|
||||||
|
const getIssuesHandler = React.useCallback(
|
||||||
|
async (reset?: boolean, resetFilters?: boolean) => {
|
||||||
|
if (!firstFetch.current || !afterFetch.current) return;
|
||||||
|
if (isFetching.current) return;
|
||||||
|
isFetching.current = true;
|
||||||
|
const selectedCategories =
|
||||||
|
categoryListRef.current?.getSelectedCategories() || [];
|
||||||
|
const issueType = categorySelectRef?.current?.getSelectedCategory();
|
||||||
|
let categoriesString = getCategoriesFetchString(selectedCategories);
|
||||||
|
if (issueType) categoriesString = ":" + issueType + ";";
|
||||||
|
await getIssues(
|
||||||
|
{
|
||||||
|
name: filterName,
|
||||||
|
categories: categoriesString,
|
||||||
|
QappName: autocompleteRef?.current?.getQappNameFetchString(),
|
||||||
|
keywords: filterSearch,
|
||||||
|
type: filterType,
|
||||||
|
},
|
||||||
|
reset,
|
||||||
|
resetFilters
|
||||||
|
);
|
||||||
|
isFetching.current = false;
|
||||||
|
},
|
||||||
|
[
|
||||||
|
getIssues,
|
||||||
|
filterValue,
|
||||||
|
getIssuesFiltered,
|
||||||
|
isFiltering,
|
||||||
|
filterName,
|
||||||
|
filterSearch,
|
||||||
|
filterType,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
const searchOnEnter = e => {
|
||||||
|
if (e.keyCode == 13) {
|
||||||
|
getIssuesHandler(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isFiltering && filterValue !== prevVal?.current) {
|
||||||
|
prevVal.current = filterValue;
|
||||||
|
getIssuesHandler();
|
||||||
|
}
|
||||||
|
}, [filterValue, isFiltering, filteredFiles, getIssuesCount]);
|
||||||
|
|
||||||
|
const getFilesHandlerMount = React.useCallback(async () => {
|
||||||
|
if (firstFetch.current) return;
|
||||||
|
firstFetch.current = true;
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
await getIssues();
|
||||||
|
afterFetch.current = true;
|
||||||
|
isFetching.current = false;
|
||||||
|
|
||||||
|
setIsLoading(false);
|
||||||
|
}, [getIssues]);
|
||||||
|
|
||||||
|
let issues = globalVideos;
|
||||||
|
|
||||||
|
if (isFiltering) {
|
||||||
|
issues = filteredFiles;
|
||||||
|
isFilterMode.current = true;
|
||||||
|
} else {
|
||||||
|
isFilterMode.current = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
!firstFetch.current &&
|
||||||
|
!isFilterMode.current &&
|
||||||
|
globalVideos.length === 0
|
||||||
|
) {
|
||||||
|
isFetching.current = true;
|
||||||
|
getFilesHandlerMount();
|
||||||
|
} else {
|
||||||
|
firstFetch.current = true;
|
||||||
|
afterFetch.current = true;
|
||||||
|
}
|
||||||
|
}, [getFilesHandlerMount, globalVideos]);
|
||||||
|
|
||||||
|
const filtersToDefault = async () => {
|
||||||
|
setFilterType("videos");
|
||||||
|
setFilterSearch("");
|
||||||
|
setFilterName("");
|
||||||
|
categoryListRef.current?.clearCategories();
|
||||||
|
categorySelectRef.current?.clearCategory();
|
||||||
|
autocompleteRef.current?.setSelectedValue(null);
|
||||||
|
ReactDOM.flushSync(() => {
|
||||||
|
getIssuesHandler(true, true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid container sx={{ width: "100%" }}>
|
||||||
|
<FiltersCol item xs={12} md={2} sm={3}>
|
||||||
|
<FiltersContainer>
|
||||||
|
<StatsData />
|
||||||
|
<Input
|
||||||
|
id="standard-adornment-name"
|
||||||
|
onChange={e => {
|
||||||
|
setFilterSearch(e.target.value);
|
||||||
|
}}
|
||||||
|
onKeyDown={searchOnEnter}
|
||||||
|
value={filterSearch}
|
||||||
|
placeholder="Search"
|
||||||
|
sx={{
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
borderBottom: `1px solid ${theme.palette.text.primary}`,
|
||||||
|
"&&:before": {
|
||||||
|
borderBottom: "none",
|
||||||
|
},
|
||||||
|
"&&:after": {
|
||||||
|
borderBottom: "none",
|
||||||
|
},
|
||||||
|
"&&:hover:before": {
|
||||||
|
borderBottom: "none",
|
||||||
|
},
|
||||||
|
"&&.Mui-focused:before": {
|
||||||
|
borderBottom: "none",
|
||||||
|
},
|
||||||
|
"&&.Mui-focused": {
|
||||||
|
outline: "none",
|
||||||
|
},
|
||||||
|
fontSize: "20px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
id="standard-adornment-name"
|
||||||
|
onChange={e => {
|
||||||
|
setFilterName(e.target.value);
|
||||||
|
}}
|
||||||
|
onKeyDown={searchOnEnter}
|
||||||
|
value={filterName}
|
||||||
|
placeholder="User's Name (Exact)"
|
||||||
|
sx={{
|
||||||
|
marginTop: "20px",
|
||||||
|
borderBottom: `1px solid ${theme.palette.text.primary}`,
|
||||||
|
"&&:before": {
|
||||||
|
borderBottom: "none",
|
||||||
|
},
|
||||||
|
"&&:after": {
|
||||||
|
borderBottom: "none",
|
||||||
|
},
|
||||||
|
"&&:hover:before": {
|
||||||
|
borderBottom: "none",
|
||||||
|
},
|
||||||
|
"&&.Mui-focused:before": {
|
||||||
|
borderBottom: "none",
|
||||||
|
},
|
||||||
|
"&&.Mui-focused": {
|
||||||
|
outline: "none",
|
||||||
|
},
|
||||||
|
fontSize: "20px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{showCategoryList && (
|
||||||
|
<CategoryList
|
||||||
|
categoryData={allCategoryData}
|
||||||
|
ref={categoryListRef}
|
||||||
|
afterChange={value => {
|
||||||
|
setShowCategorySelect(!value[0]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{showCategorySelect && (
|
||||||
|
<CategorySelect
|
||||||
|
categoryData={allCategories}
|
||||||
|
ref={categorySelectRef}
|
||||||
|
sx={{ marginTop: "20px" }}
|
||||||
|
afterChange={value => {
|
||||||
|
setShowCategoryList(!value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{QappNamesParam.length > 0 && (
|
||||||
|
<AutocompleteQappNames
|
||||||
|
ref={autocompleteRef}
|
||||||
|
namesList={QappNamesParam}
|
||||||
|
sx={{ marginTop: "20px" }}
|
||||||
|
required={false}
|
||||||
|
afterChange={() => {
|
||||||
|
const currentSelectedCategories =
|
||||||
|
categoryListRef?.current?.getSelectedCategories();
|
||||||
|
categoryListRef?.current?.setSelectedCategories([
|
||||||
|
"3",
|
||||||
|
currentSelectedCategories[1],
|
||||||
|
currentSelectedCategories[2],
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ThemeButton
|
||||||
|
onClick={() => {
|
||||||
|
filtersToDefault();
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
marginTop: "20px",
|
||||||
|
fontWeight: 1000,
|
||||||
|
}}
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
reset
|
||||||
|
</ThemeButton>
|
||||||
|
<ThemeButton
|
||||||
|
onClick={() => {
|
||||||
|
getIssuesHandler(true);
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
marginTop: "20px",
|
||||||
|
fontWeight: 1000,
|
||||||
|
}}
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Search
|
||||||
|
</ThemeButton>
|
||||||
|
</FiltersContainer>
|
||||||
|
</FiltersCol>
|
||||||
|
<Grid item xs={12} md={10} sm={9}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
marginTop: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SubtitleContainer
|
||||||
|
sx={{
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
paddingLeft: "15px",
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: "1400px",
|
||||||
|
}}
|
||||||
|
></SubtitleContainer>
|
||||||
|
<IssueList issues={issues} />
|
||||||
|
<LazyLoad
|
||||||
|
onLoadMore={getIssuesHandler}
|
||||||
|
isLoading={isLoading}
|
||||||
|
></LazyLoad>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
};
|
244
src/pages/Home/IssueList.tsx
Normal file
244
src/pages/Home/IssueList.tsx
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
import BlockIcon from "@mui/icons-material/Block";
|
||||||
|
import EditIcon from "@mui/icons-material/Edit";
|
||||||
|
import { Avatar, Box, Skeleton, useTheme } from "@mui/material";
|
||||||
|
import React, { useMemo, useState } from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
import QORTicon from "../../assets/icons/CoinIcons/qort.png";
|
||||||
|
import { BountyDisplay } from "../../components/common/BountyDisplay.tsx";
|
||||||
|
import { IssueIcon, IssueIcons } from "../../components/common/IssueIcon.tsx";
|
||||||
|
import {
|
||||||
|
getIconsFromObject,
|
||||||
|
getnamesFromObject,
|
||||||
|
} from "../../constants/Categories/CategoryFunctions.ts";
|
||||||
|
import { fontSizeExLarge } from "../../constants/Misc.ts";
|
||||||
|
import {
|
||||||
|
blockUser,
|
||||||
|
Issue,
|
||||||
|
setEditFile,
|
||||||
|
} from "../../state/features/fileSlice.ts";
|
||||||
|
import { RootState } from "../../state/store.ts";
|
||||||
|
import { BountyData } from "../../utils/qortalRequests.ts";
|
||||||
|
import { formatDate } from "../../utils/time.ts";
|
||||||
|
import {
|
||||||
|
BlockIconContainer,
|
||||||
|
IconsBox,
|
||||||
|
IssueCard,
|
||||||
|
IssueContainer,
|
||||||
|
NameAndDateContainer,
|
||||||
|
VideoCardName,
|
||||||
|
VideoCardTitle,
|
||||||
|
VideoUploadDate,
|
||||||
|
} from "./IssueList-styles.tsx";
|
||||||
|
|
||||||
|
interface FileListProps {
|
||||||
|
issues: Issue[];
|
||||||
|
}
|
||||||
|
export const IssueList = ({ issues }: FileListProps) => {
|
||||||
|
const hashMapIssues = useSelector(
|
||||||
|
(state: RootState) => state.file.hashMapFiles
|
||||||
|
);
|
||||||
|
const theme = useTheme();
|
||||||
|
const [showIcons, setShowIcons] = useState(null);
|
||||||
|
const username = useSelector((state: RootState) => state.auth?.user?.name);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const blockUserFunc = async (user: string) => {
|
||||||
|
if (user === "Q-Support") return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await qortalRequest({
|
||||||
|
action: "ADD_LIST_ITEMS",
|
||||||
|
list_name: "blockedNames",
|
||||||
|
items: [user],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response === true) {
|
||||||
|
dispatch(blockUser(user));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredIssues = useMemo(() => {
|
||||||
|
return issues.filter((issue: any) => hashMapIssues[issue.id]?.isValid);
|
||||||
|
}, [issues, hashMapIssues]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IssueContainer>
|
||||||
|
{filteredIssues.map((issue: any, index: number) => {
|
||||||
|
const existingFile = hashMapIssues[issue?.id];
|
||||||
|
let hasHash = false;
|
||||||
|
let issueObj = issue;
|
||||||
|
if (existingFile) {
|
||||||
|
issueObj = existingFile;
|
||||||
|
hasHash = true;
|
||||||
|
}
|
||||||
|
const bountyData: BountyData = {
|
||||||
|
...issueObj.bountyData,
|
||||||
|
...issue.bountyData,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
width: "100%",
|
||||||
|
height: "75px",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
key={issueObj.id}
|
||||||
|
onMouseEnter={() => setShowIcons(issueObj.id)}
|
||||||
|
onMouseLeave={() => setShowIcons(null)}
|
||||||
|
>
|
||||||
|
{hasHash ? (
|
||||||
|
<>
|
||||||
|
<IconsBox
|
||||||
|
sx={{
|
||||||
|
opacity: showIcons === issueObj.id ? 1 : 0,
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{issueObj?.user === username && (
|
||||||
|
<BlockIconContainer
|
||||||
|
onClick={() => {
|
||||||
|
dispatch(setEditFile(issueObj));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<EditIcon />
|
||||||
|
Edit Issue
|
||||||
|
</BlockIconContainer>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{issueObj?.user !== username && (
|
||||||
|
<BlockIconContainer
|
||||||
|
onClick={() => {
|
||||||
|
blockUserFunc(issueObj?.user);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<BlockIcon />
|
||||||
|
Block User
|
||||||
|
</BlockIconContainer>
|
||||||
|
)}
|
||||||
|
</IconsBox>
|
||||||
|
<IssueCard
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`/issue/${issueObj?.user}/${issueObj?.id}`);
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
height: "100%",
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
width: "280px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IssueIcons
|
||||||
|
issueData={issueObj}
|
||||||
|
style={{ marginRight: "20px" }}
|
||||||
|
showBackupIcon={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "left",
|
||||||
|
alignItems: "center",
|
||||||
|
width: "250px",
|
||||||
|
fontSize: fontSizeExLarge,
|
||||||
|
fontFamily: "Cairo",
|
||||||
|
letterSpacing: "0.4px",
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
userSelect: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<BountyDisplay
|
||||||
|
bountyData={bountyData}
|
||||||
|
divStyle={{ marginLeft: "20px" }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<VideoCardTitle sx={{ fontWeight: "bold", width: "400px" }}>
|
||||||
|
{issueObj.title}
|
||||||
|
</VideoCardTitle>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{issue?.feeData?.isPaid && (
|
||||||
|
<IssueIcon
|
||||||
|
iconSrc={QORTicon}
|
||||||
|
style={{ marginRight: "20px" }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<NameAndDateContainer
|
||||||
|
sx={{ width: "200px", height: "100%" }}
|
||||||
|
onClick={e => {
|
||||||
|
e.stopPropagation();
|
||||||
|
navigate(`/channel/${issueObj?.user}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
width: "200px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
sx={{ height: 24, width: 24, marginRight: "10px" }}
|
||||||
|
src={`/arbitrary/THUMBNAIL/${issueObj?.user}/qortal_avatar`}
|
||||||
|
alt={`${issueObj?.user}'s avatar`}
|
||||||
|
/>
|
||||||
|
<VideoCardName
|
||||||
|
sx={{
|
||||||
|
":hover": {
|
||||||
|
textDecoration: "underline",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{issueObj?.user}
|
||||||
|
</VideoCardName>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{issueObj?.created && (
|
||||||
|
<VideoUploadDate>
|
||||||
|
{formatDate(issueObj.created)}
|
||||||
|
</VideoUploadDate>
|
||||||
|
)}
|
||||||
|
</NameAndDateContainer>
|
||||||
|
</IssueCard>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Skeleton
|
||||||
|
variant="rectangular"
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
paddingBottom: "10px",
|
||||||
|
objectFit: "contain",
|
||||||
|
visibility: "visible",
|
||||||
|
borderRadius: "8px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</IssueContainer>
|
||||||
|
);
|
||||||
|
};
|
Reference in New Issue
Block a user