2020-09-20 15:18:35 +00:00
|
|
|
import React, { useEffect, useState } from 'react';
|
2020-09-12 21:53:41 +00:00
|
|
|
import { useRouter } from 'next/router';
|
2020-09-19 21:20:10 +00:00
|
|
|
import Spinner from 'react-bootstrap/Spinner';
|
|
|
|
import { getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
|
2020-11-28 18:11:24 +00:00
|
|
|
import { collection, fetchCollections, file, getFile, getFiles, getPreview } from 'services/fileService';
|
2020-09-19 21:20:10 +00:00
|
|
|
import { getData, LS_KEYS } from 'utils/storage/localStorage';
|
|
|
|
import PreviewCard from './components/PreviewCard';
|
|
|
|
import { getActualKey } from 'utils/common/key';
|
2020-09-20 15:18:35 +00:00
|
|
|
import styled from 'styled-components';
|
2020-11-23 03:00:17 +00:00
|
|
|
import { PhotoSwipe } from 'react-photoswipe';
|
|
|
|
import { Options } from 'photoswipe';
|
2020-11-20 17:24:21 +00:00
|
|
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
|
|
|
import { FixedSizeList as List } from 'react-window';
|
2020-11-28 18:11:24 +00:00
|
|
|
import Collections from './components/Collections';
|
|
|
|
import SadFace from 'components/SadFace';
|
2020-09-20 15:18:35 +00:00
|
|
|
|
|
|
|
const Container = styled.div`
|
2020-11-20 17:24:21 +00:00
|
|
|
display: block;
|
|
|
|
flex: 1;
|
|
|
|
width: 100%;
|
2020-09-20 15:18:35 +00:00
|
|
|
flex-wrap: wrap;
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
|
|
.pswp-thumbnail {
|
|
|
|
display: inline-block;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
`;
|
2020-09-12 21:53:41 +00:00
|
|
|
|
2020-11-20 17:24:21 +00:00
|
|
|
const ListItem = styled.div`
|
2020-11-28 18:11:24 +00:00
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const DeadCenter = styled.div`
|
|
|
|
flex: 1;
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
color: #fff;
|
|
|
|
text-align: center;
|
|
|
|
flex-direction: column;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const ListContainer = styled.div`
|
|
|
|
@media (min-width: 1000px) {
|
|
|
|
width: 1000px;
|
|
|
|
}
|
|
|
|
|
|
|
|
@media (min-width: 450px) and (max-width: 1000px) {
|
|
|
|
max-width: 600px;
|
|
|
|
}
|
|
|
|
|
|
|
|
@media (max-width: 450px) {
|
|
|
|
max-width: 100%;
|
|
|
|
}
|
2020-11-20 17:24:21 +00:00
|
|
|
`;
|
|
|
|
|
2020-11-07 15:43:00 +00:00
|
|
|
const PAGE_SIZE = 12;
|
|
|
|
const COLUMNS = 3;
|
|
|
|
|
2020-09-12 21:53:41 +00:00
|
|
|
export default function Gallery() {
|
|
|
|
const router = useRouter();
|
2020-09-19 21:20:10 +00:00
|
|
|
const [loading, setLoading] = useState(false);
|
2020-11-28 18:11:24 +00:00
|
|
|
const [collections, setCollections] = useState<collection[]>([])
|
2020-11-07 11:10:49 +00:00
|
|
|
const [data, setData] = useState<file[]>();
|
2020-11-23 03:00:17 +00:00
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
const [options, setOptions] = useState<Options>({
|
|
|
|
history: false,
|
2020-11-25 14:14:05 +00:00
|
|
|
maxSpreadZoom: 5,
|
2020-11-23 03:00:17 +00:00
|
|
|
});
|
2020-11-24 04:40:02 +00:00
|
|
|
const fetching: { [k: number]: boolean } = {};
|
2020-09-12 21:53:41 +00:00
|
|
|
|
2020-09-20 15:18:35 +00:00
|
|
|
useEffect(() => {
|
2020-09-13 06:30:07 +00:00
|
|
|
const key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
|
2020-09-19 21:20:10 +00:00
|
|
|
const token = getData(LS_KEYS.USER).token;
|
2020-09-13 06:30:07 +00:00
|
|
|
if (!key) {
|
2020-09-12 21:53:41 +00:00
|
|
|
router.push("/");
|
|
|
|
}
|
2020-09-19 21:20:10 +00:00
|
|
|
const main = async () => {
|
|
|
|
setLoading(true);
|
|
|
|
const encryptionKey = await getActualKey();
|
2020-11-28 18:11:24 +00:00
|
|
|
const collections = await fetchCollections(token, encryptionKey);
|
|
|
|
const resp = await getFiles("0", token, "100", encryptionKey, collections);
|
2020-09-19 21:20:10 +00:00
|
|
|
setLoading(false);
|
2020-11-28 18:11:24 +00:00
|
|
|
setCollections(collections);
|
2020-11-23 03:00:17 +00:00
|
|
|
setData(resp.map(item => ({
|
|
|
|
...item,
|
|
|
|
w: window.innerWidth,
|
|
|
|
h: window.innerHeight,
|
|
|
|
})));
|
2020-09-19 21:20:10 +00:00
|
|
|
};
|
2020-11-28 18:11:24 +00:00
|
|
|
main();
|
2020-09-12 21:53:41 +00:00
|
|
|
}, []);
|
|
|
|
|
2020-09-19 21:20:10 +00:00
|
|
|
if (!data || loading) {
|
2020-09-20 15:18:35 +00:00
|
|
|
return <div className="text-center">
|
2020-11-25 13:42:24 +00:00
|
|
|
<Spinner animation="border" variant="primary" />
|
2020-09-20 15:18:35 +00:00
|
|
|
</div>
|
2020-09-12 21:53:41 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 03:00:17 +00:00
|
|
|
const updateUrl = (index: number) => (url: string) => {
|
2020-11-24 04:40:02 +00:00
|
|
|
data[index] = {
|
|
|
|
...data[index],
|
|
|
|
msrc: url,
|
|
|
|
w: window.innerWidth,
|
|
|
|
h: window.innerHeight,
|
|
|
|
}
|
2020-11-26 15:57:20 +00:00
|
|
|
if (data[index].metadata.fileType === 1 && !data[index].html) {
|
|
|
|
data[index].html = `
|
|
|
|
<div class="video-loading">
|
|
|
|
<img src="${url}" />
|
|
|
|
<div class="spinner-border text-light" role="status">
|
|
|
|
<span class="sr-only">Loading...</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
`;
|
|
|
|
delete data[index].src;
|
|
|
|
}
|
|
|
|
if (data[index].metadata.fileType === 0 && !data[index].src) {
|
2020-11-24 04:40:02 +00:00
|
|
|
data[index].src = url;
|
|
|
|
}
|
|
|
|
setData(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
const updateSrcUrl = (index: number, url: string) => {
|
2020-11-23 03:00:17 +00:00
|
|
|
data[index] = {
|
|
|
|
...data[index],
|
|
|
|
src: url,
|
2020-11-24 04:40:02 +00:00
|
|
|
w: window.innerWidth,
|
|
|
|
h: window.innerHeight,
|
2020-11-23 03:00:17 +00:00
|
|
|
}
|
2020-11-26 15:57:20 +00:00
|
|
|
if (data[index].metadata.fileType === 1) {
|
|
|
|
data[index].html = `
|
|
|
|
<video controls>
|
2020-11-26 17:35:26 +00:00
|
|
|
<source src="${url}" />
|
2020-11-26 15:57:20 +00:00
|
|
|
Your browser does not support the video tag.
|
|
|
|
</video>
|
|
|
|
`;
|
|
|
|
delete data[index].src;
|
|
|
|
}
|
2020-11-23 03:00:17 +00:00
|
|
|
setData(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleClose = () => {
|
|
|
|
setOpen(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
const onThumbnailClick = (index: number) => () => {
|
|
|
|
setOptions({
|
|
|
|
...options,
|
|
|
|
index,
|
|
|
|
});
|
|
|
|
setOpen(true);
|
|
|
|
}
|
|
|
|
|
2020-11-28 18:11:24 +00:00
|
|
|
const getThumbnail = (file: file[], index: number) => {
|
|
|
|
return (<PreviewCard
|
|
|
|
key={`tile-${file[index].id}`}
|
|
|
|
data={file[index]}
|
|
|
|
updateUrl={updateUrl(file[index].dataIndex)}
|
2020-11-23 03:00:17 +00:00
|
|
|
onClick={onThumbnailClick(index)}
|
2020-11-28 18:11:24 +00:00
|
|
|
/>);
|
|
|
|
}
|
2020-09-20 15:18:35 +00:00
|
|
|
|
2020-11-24 04:40:02 +00:00
|
|
|
const getSlideData = async (instance: any, index: number, item: file) => {
|
|
|
|
const token = getData(LS_KEYS.USER).token;
|
|
|
|
if (!item.msrc) {
|
|
|
|
const url = await getPreview(token, item);
|
|
|
|
updateUrl(index)(url);
|
|
|
|
item.msrc = url;
|
|
|
|
if (!item.src) {
|
|
|
|
item.src = url;
|
|
|
|
}
|
|
|
|
item.w = window.innerWidth;
|
|
|
|
item.h = window.innerHeight;
|
2020-11-24 04:49:18 +00:00
|
|
|
try {
|
2020-11-24 04:40:02 +00:00
|
|
|
instance.invalidateCurrItems();
|
|
|
|
instance.updateSize(true);
|
2020-11-24 04:49:18 +00:00
|
|
|
} catch (e) {
|
|
|
|
// ignore
|
2020-11-24 04:40:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((!item.src || item.src === item.msrc) && !fetching[index]) {
|
|
|
|
fetching[index] = true;
|
|
|
|
const url = await getFile(token, item);
|
|
|
|
updateSrcUrl(index, url);
|
2020-11-26 15:57:20 +00:00
|
|
|
if (item.metadata.fileType === 1) {
|
|
|
|
item.html = `
|
|
|
|
<video width="320" height="240" controls>
|
2020-11-26 17:35:26 +00:00
|
|
|
<source src="${url}" />
|
2020-11-26 15:57:20 +00:00
|
|
|
Your browser does not support the video tag.
|
|
|
|
</video>
|
|
|
|
`;
|
|
|
|
delete item.src;
|
|
|
|
item.w = window.innerWidth;
|
|
|
|
}
|
2020-11-24 04:40:02 +00:00
|
|
|
item.h = window.innerHeight;
|
2020-11-24 04:49:18 +00:00
|
|
|
try {
|
2020-11-24 04:40:02 +00:00
|
|
|
instance.invalidateCurrItems();
|
|
|
|
instance.updateSize(true);
|
2020-11-24 04:49:18 +00:00
|
|
|
} catch (e) {
|
|
|
|
// ignore
|
2020-11-24 04:40:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-28 18:11:24 +00:00
|
|
|
const selectCollection = (id?: string) => {
|
|
|
|
const href = `/gallery?collection=${id || ''}`;
|
|
|
|
router.push(href, undefined, { shallow: true });
|
|
|
|
}
|
|
|
|
|
|
|
|
const idSet = new Set();
|
|
|
|
const filteredData = data.map((item, index) => ({
|
|
|
|
...item,
|
|
|
|
dataIndex: index,
|
|
|
|
})).filter(item => {
|
|
|
|
if (!idSet.has(item.id)) {
|
|
|
|
if (!router.query.collection || router.query.collection === item.collectionID.toString()) {
|
|
|
|
idSet.add(item.id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
return (<>
|
|
|
|
<Collections
|
|
|
|
collections={collections}
|
|
|
|
selected={router.query.collection?.toString()}
|
|
|
|
selectCollection={selectCollection}
|
|
|
|
/>
|
|
|
|
{
|
|
|
|
filteredData.length
|
|
|
|
? <Container>
|
|
|
|
<AutoSizer>
|
|
|
|
{({ height, width }) => {
|
|
|
|
let columns;
|
|
|
|
if (width >= 1000) {
|
|
|
|
columns = 5;
|
|
|
|
} else if (width < 1000 && width >= 450) {
|
|
|
|
columns = 3;
|
|
|
|
} else if (width < 450 && width >= 300) {
|
|
|
|
columns = 2;
|
|
|
|
} else {
|
|
|
|
columns = 1;
|
2020-11-23 06:20:00 +00:00
|
|
|
}
|
2020-11-28 18:11:24 +00:00
|
|
|
return (
|
|
|
|
<List
|
|
|
|
itemSize={200}
|
|
|
|
height={height}
|
|
|
|
width={width}
|
|
|
|
itemCount={Math.ceil(filteredData.length / columns)}
|
|
|
|
>
|
|
|
|
{({ index, style }) => {
|
|
|
|
const arr = [];
|
|
|
|
for (let i = 0; i < columns; i++) {
|
|
|
|
arr.push(index * columns + i);
|
|
|
|
}
|
|
|
|
return (<ListItem style={style}>
|
|
|
|
<ListContainer>
|
|
|
|
{arr.map(i => filteredData[i] && getThumbnail(filteredData, i))}
|
|
|
|
</ListContainer>
|
|
|
|
</ListItem>);
|
|
|
|
}}
|
|
|
|
</List>
|
|
|
|
)
|
2020-11-23 06:20:00 +00:00
|
|
|
}}
|
2020-11-28 18:11:24 +00:00
|
|
|
</AutoSizer>
|
|
|
|
<PhotoSwipe
|
|
|
|
isOpen={open}
|
|
|
|
items={filteredData}
|
|
|
|
options={options}
|
|
|
|
onClose={handleClose}
|
|
|
|
gettingData={getSlideData}
|
|
|
|
/>
|
|
|
|
</Container>
|
|
|
|
: <DeadCenter>
|
|
|
|
<SadFace height={100} width={100} />
|
|
|
|
<div>No content found!</div>
|
|
|
|
</DeadCenter>
|
|
|
|
}
|
|
|
|
</>);
|
2020-09-12 21:53:41 +00:00
|
|
|
}
|