ente/src/pages/gallery/index.tsx

393 lines
14 KiB
TypeScript
Raw Normal View History

2021-02-17 08:35:19 +00:00
import React, { useEffect, useRef, useState } from 'react';
import { useRouter } from 'next/router';
2021-04-29 08:58:34 +00:00
import { clearKeys, getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
import {
File,
getLocalFiles,
deleteFiles,
syncFiles,
} from 'services/fileService';
2020-09-20 15:18:35 +00:00
import styled from 'styled-components';
2021-02-08 17:15:13 +00:00
import LoadingBar from 'react-top-loading-bar';
2020-11-28 18:11:24 +00:00
import Collections from './components/Collections';
import Upload from './components/Upload';
import {
Collection,
2021-02-08 16:15:21 +00:00
syncCollections,
CollectionAndItsLatestFile,
getCollectionsAndTheirLatestFile,
getFavItemIds,
2021-02-08 17:15:13 +00:00
getLocalCollections,
2021-03-15 17:30:49 +00:00
getNonEmptyCollections,
} from 'services/collectionService';
2021-01-24 20:59:58 +00:00
import constants from 'utils/strings/constants';
import { Alert } from 'react-bootstrap';
import billingService from 'services/billingService';
2021-03-12 12:30:33 +00:00
import PlanSelector from './components/PlanSelector';
import { checkSubscriptionPurchase } from 'utils/billingUtil';
2020-09-20 15:18:35 +00:00
import FullScreenDropZone from 'components/FullScreenDropZone';
import Sidebar from 'components/Sidebar';
import UploadButton from './components/UploadButton';
import { checkConnectivity } from 'utils/common';
2021-04-22 14:30:07 +00:00
import {
isFirstLogin,
justSignedUp,
setIsFirstLogin,
setJustSignedUp,
} from 'utils/storage';
import { logoutUser } from 'services/userService';
import AlertBanner from './components/AlertBanner';
2021-04-07 09:22:59 +00:00
import MessageDialog, { MessageAttributes } from 'components/MessageDialog';
2021-04-27 05:35:49 +00:00
import { useDropzone } from 'react-dropzone';
import EnteSpinner from 'components/EnteSpinner';
import CollectionNamer, {
CollectionNamerAttributes,
} from './components/CollectionNamer';
import CollectionSelector, {
CollectionSelectorAttributes,
} from './components/CollectionSelector';
2021-04-27 05:35:49 +00:00
import { LoadingOverlay } from 'components/LoadingOverlay';
import PhotoFrame from 'components/PhotoFrame';
import { getSelectedFileIds } from 'utils/file';
import { addFilesToCollection } from 'utils/collection';
import SelectedFileOptions from './components/SelectedFileOptions';
2021-04-29 08:43:18 +00:00
import { errorCodes } from 'utils/common/errorUtil';
2021-05-18 04:27:02 +00:00
import SearchButton from 'components/SearchButton';
2021-05-18 04:32:37 +00:00
import SearchBar from 'components/SearchBar';
2021-01-12 07:01:00 +00:00
export enum FILE_TYPE {
IMAGE,
VIDEO,
2021-02-08 17:15:13 +00:00
OTHERS,
2021-01-12 07:01:00 +00:00
}
2020-11-29 14:48:47 +00:00
2021-04-19 08:29:12 +00:00
export const DeadCenter = styled.div`
flex: 1;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
text-align: center;
flex-direction: column;
2020-11-28 18:11:24 +00:00
`;
export type selectedState = {
[k: number]: boolean;
2021-03-20 14:58:12 +00:00
count: number;
};
2021-05-18 14:20:38 +00:00
export type SetFiles = React.Dispatch<React.SetStateAction<File[]>>;
export type SetCollections = React.Dispatch<React.SetStateAction<Collection[]>>;
export type SetLoading = React.Dispatch<React.SetStateAction<Boolean>>;
2021-03-20 14:58:12 +00:00
export default function Gallery() {
const router = useRouter();
const [collections, setCollections] = useState<Collection[]>([]);
2021-05-11 12:12:17 +00:00
const [collectionsAndTheirLatestFile, setCollectionsAndTheirLatestFile] =
useState<CollectionAndItsLatestFile[]>([]);
const [files, setFiles] = useState<File[]>(null);
2021-01-20 12:05:04 +00:00
const [favItemIds, setFavItemIds] = useState<Set<number>>();
2021-03-29 07:52:20 +00:00
const [bannerMessage, setBannerMessage] = useState<string>(null);
2020-12-19 16:23:35 +00:00
const [sinceTime, setSinceTime] = useState(0);
const [isFirstLoad, setIsFirstLoad] = useState(false);
2021-03-20 14:58:12 +00:00
const [selected, setSelected] = useState<selectedState>({ count: 0 });
const [dialogMessage, setDialogMessage] = useState<MessageAttributes>();
const [dialogView, setDialogView] = useState(false);
const [planModalView, setPlanModalView] = useState(false);
const [loading, setLoading] = useState(false);
2021-05-11 12:12:17 +00:00
const [collectionSelectorAttributes, setCollectionSelectorAttributes] =
useState<CollectionSelectorAttributes>(null);
2021-04-27 05:35:49 +00:00
const [collectionSelectorView, setCollectionSelectorView] = useState(false);
2021-05-11 12:12:17 +00:00
const [collectionNamerAttributes, setCollectionNamerAttributes] =
useState<CollectionNamerAttributes>(null);
2021-04-27 05:35:49 +00:00
const [collectionNamerView, setCollectionNamerView] = useState(false);
const {
getRootProps,
getInputProps,
open: openFileUploader,
acceptedFiles,
} = useDropzone({
noClick: true,
noKeyboard: true,
accept: 'image/*, video/*, application/json, ',
});
2021-02-17 08:35:19 +00:00
const loadingBar = useRef(null);
2021-05-18 04:27:02 +00:00
const [searchView, setSearchView] = useState(false);
useEffect(() => {
const key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
if (!key) {
router.push('/');
2021-02-17 09:16:20 +00:00
return;
}
const main = async () => {
setIsFirstLoad(isFirstLogin());
if (justSignedUp()) {
2021-04-20 09:30:45 +00:00
setPlanModalView(true);
}
setIsFirstLogin(false);
const files = await getLocalFiles();
const collections = await getLocalCollections();
const nonEmptyCollections = getNonEmptyCollections(
collections,
files
);
2021-05-11 12:12:17 +00:00
const collectionsAndTheirLatestFile =
await getCollectionsAndTheirLatestFile(
nonEmptyCollections,
files
);
setFiles(files);
setCollections(nonEmptyCollections);
setCollectionsAndTheirLatestFile(collectionsAndTheirLatestFile);
const favItemIds = await getFavItemIds(files);
setFavItemIds(favItemIds);
await checkSubscriptionPurchase(setDialogMessage, router);
await syncWithRemote();
setIsFirstLoad(false);
2021-04-22 14:30:07 +00:00
setJustSignedUp(false);
};
main();
}, []);
useEffect(() => setDialogView(true), [dialogMessage]);
2021-05-11 12:12:17 +00:00
useEffect(
() => setCollectionSelectorView(true),
[collectionSelectorAttributes]
);
useEffect(() => setCollectionNamerView(true), [collectionNamerAttributes]);
const syncWithRemote = async () => {
try {
2021-03-29 09:33:28 +00:00
checkConnectivity();
loadingBar.current?.continuousStart();
await billingService.updatePlans();
await billingService.syncSubscription();
const collections = await syncCollections();
const { files, isUpdated } = await syncFiles(collections);
const nonEmptyCollections = getNonEmptyCollections(
collections,
files
);
2021-05-11 12:12:17 +00:00
const collectionAndItsLatestFile =
await getCollectionsAndTheirLatestFile(
nonEmptyCollections,
files
);
const favItemIds = await getFavItemIds(files);
setCollections(nonEmptyCollections);
if (isUpdated) {
setFiles(files);
}
setCollectionsAndTheirLatestFile(collectionAndItsLatestFile);
setFavItemIds(favItemIds);
setSinceTime(new Date().getTime());
} catch (e) {
2021-04-29 08:58:34 +00:00
switch (e.message) {
2021-04-29 08:43:18 +00:00
case errorCodes.ERR_SESSION_EXPIRED:
setBannerMessage(constants.SESSION_EXPIRED_MESSAGE);
setDialogMessage({
title: constants.SESSION_EXPIRED,
content: constants.SESSION_EXPIRED_MESSAGE,
staticBackdrop: true,
proceed: {
text: constants.LOGIN,
action: logoutUser,
variant: 'primary',
},
nonClosable: true,
2021-04-29 08:43:18 +00:00
});
break;
case errorCodes.ERR_KEY_MISSING:
2021-04-29 08:58:34 +00:00
clearKeys();
router.push('/credentials');
break;
}
} finally {
loadingBar.current?.complete();
}
2021-02-08 17:15:13 +00:00
};
2021-04-22 12:56:06 +00:00
const clearSelection = function () {
setSelected({ count: 0 });
};
2021-03-20 14:58:12 +00:00
2021-02-08 09:20:27 +00:00
const selectCollection = (id?: number) => {
const href = `/gallery?collection=${id || ''}`;
router.push(href, undefined, { shallow: true });
};
if (!files) {
return <div />;
}
2021-05-07 09:37:12 +00:00
const addToCollectionHelper = (
collectionName: string,
collection: Collection
) => {
2021-05-07 12:11:20 +00:00
loadingBar.current?.continuousStart();
2021-05-07 09:37:12 +00:00
addFilesToCollection(
setCollectionSelectorView,
selected,
files,
clearSelection,
syncWithRemote,
selectCollection,
collectionName,
collection
);
};
const showCreateCollectionModal = () =>
setCollectionNamerAttributes({
title: constants.CREATE_COLLECTION,
buttonText: constants.CREATE,
autoFilledName: '',
callback: (collectionName) =>
addToCollectionHelper(collectionName, null),
});
2021-05-07 09:37:12 +00:00
const deleteFileHelper = () => {
2021-05-07 12:11:20 +00:00
loadingBar.current?.continuousStart();
deleteFiles(
getSelectedFileIds(selected),
clearSelection,
syncWithRemote
);
2021-05-07 09:37:12 +00:00
};
const updateFiles = (files: File[]) => {
2021-05-18 14:20:38 +00:00
setFiles(files);
setSinceTime(new Date().getTime());
};
return (
<FullScreenDropZone
2021-04-27 05:35:49 +00:00
getRootProps={getRootProps}
getInputProps={getInputProps}
showCollectionSelector={setCollectionSelectorView.bind(null, true)}
>
{loading && (
<LoadingOverlay>
<EnteSpinner />
</LoadingOverlay>
)}
<LoadingBar color="#2dc262" ref={loadingBar} />
{isFirstLoad && (
2021-02-17 08:35:19 +00:00
<div className="text-center">
2021-03-09 10:36:23 +00:00
<Alert variant="success">
2021-02-17 08:35:19 +00:00
{constants.INITIAL_LOAD_DELAY_WARNING}
</Alert>
</div>
)}
2021-03-12 12:30:33 +00:00
<PlanSelector
modalView={planModalView}
closeModal={() => setPlanModalView(false)}
setDialogMessage={setDialogMessage}
setLoading={setLoading}
2021-03-29 09:33:28 +00:00
/>
<AlertBanner bannerMessage={bannerMessage} />
<MessageDialog
2021-05-11 12:12:17 +00:00
size={'lg'}
show={dialogView}
onHide={() => setDialogView(false)}
attributes={dialogMessage}
2021-03-12 12:30:33 +00:00
/>
2021-05-18 14:20:38 +00:00
<SearchBar
isOpen={searchView}
setOpen={setSearchView}
loadingBar={loadingBar.current}
setFiles={updateFiles}
2021-05-18 14:20:38 +00:00
setCollections={setCollections}
/>
<Collections
collections={collections}
2021-02-17 08:06:20 +00:00
selected={Number(router.query.collection)}
selectCollection={selectCollection}
2021-04-24 07:09:37 +00:00
syncWithRemote={syncWithRemote}
setDialogMessage={setDialogMessage}
2021-04-27 05:35:49 +00:00
setCollectionNamerAttributes={setCollectionNamerAttributes}
startLoadingBar={loadingBar.current?.continuousStart}
2021-04-27 05:35:49 +00:00
/>
<CollectionNamer
show={collectionNamerView}
onHide={setCollectionNamerView.bind(null, false)}
2021-04-27 05:35:49 +00:00
attributes={collectionNamerAttributes}
/>
<CollectionSelector
show={collectionSelectorView}
onHide={setCollectionSelectorView.bind(null, false)}
collectionsAndTheirLatestFile={collectionsAndTheirLatestFile}
directlyShowNextModal={
collectionsAndTheirLatestFile?.length === 0
}
2021-04-27 05:35:49 +00:00
attributes={collectionSelectorAttributes}
/>
<Upload
2021-04-27 05:35:49 +00:00
syncWithRemote={syncWithRemote}
2021-03-29 07:52:20 +00:00
setBannerMessage={setBannerMessage}
2021-04-27 05:35:49 +00:00
acceptedFiles={acceptedFiles}
existingFiles={files}
2021-04-27 05:35:49 +00:00
setCollectionSelectorAttributes={
setCollectionSelectorAttributes
}
closeCollectionSelector={setCollectionSelectorView.bind(
null,
false
)}
2021-04-27 05:35:49 +00:00
setLoading={setLoading}
setCollectionNamerAttributes={setCollectionNamerAttributes}
setDialogMessage={setDialogMessage}
/>
<Sidebar
files={files}
collections={collections}
2021-04-20 11:09:03 +00:00
setDialogMessage={setDialogMessage}
showPlanSelectorModal={() => setPlanModalView(true)}
/>
2021-04-27 05:35:49 +00:00
<UploadButton openFileUploader={openFileUploader} />
<PhotoFrame
files={files}
setFiles={setFiles}
syncWithRemote={syncWithRemote}
favItemIds={favItemIds}
sinceTime={sinceTime}
setSelected={setSelected}
selected={selected}
isFirstLoad={isFirstLoad}
openFileUploader={openFileUploader}
loadingBar={loadingBar}
searchMode={searchView}
/>
{files.length < 30 && (
2021-03-09 08:20:43 +00:00
<Alert
2021-03-09 10:36:23 +00:00
variant="success"
style={{
position: 'fixed',
bottom: '1%',
width: '100%',
textAlign: 'center',
marginBottom: '0px',
}}
2021-03-09 08:20:43 +00:00
>
{constants.INSTALL_MOBILE_APP()}
</Alert>
)}
2021-05-18 04:27:02 +00:00
{selected.count > 0 ? (
<SelectedFileOptions
addToCollectionHelper={addToCollectionHelper}
showCreateCollectionModal={showCreateCollectionModal}
setDialogMessage={setDialogMessage}
setCollectionSelectorAttributes={
setCollectionSelectorAttributes
2021-04-22 12:56:06 +00:00
}
deleteFileHelper={deleteFileHelper}
/>
2021-05-18 04:27:02 +00:00
) : (
<SearchButton
open={searchView}
onClick={() => setSearchView(true)}
2021-05-18 04:27:02 +00:00
/>
)}
</FullScreenDropZone>
);
}