diff --git a/.eslintrc.json b/.eslintrc.json index 5e580ced6..3e369153b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -8,7 +8,8 @@ "plugin:react/recommended", "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", - "google" + "google", + "prettier" ], "parser": "@typescript-eslint/parser", "parserOptions": { @@ -23,13 +24,7 @@ "@typescript-eslint" ], "rules": { - "indent": [ - "error", - 4, - { - "SwitchCase": 1 - } - ], + "indent":"off", "class-methods-use-this": "off", "react/prop-types": "off", "react/display-name": "off", @@ -48,7 +43,8 @@ "error", "always" ], - "space-before-function-paren": "off" + "space-before-function-paren": "off", + "operator-linebreak":["error","after", { "overrides": { "?": "before", ":": "before" } }] }, "settings": { "react": { diff --git a/.husky/.gitignore b/.husky/.gitignore deleted file mode 100644 index 31354ec13..000000000 --- a/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ diff --git a/.husky/pre-commit b/.husky/pre-commit index d2ae35e84..36af21989 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -yarn lint-staged +npx lint-staged diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..016ad1eec --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "tabWidth": 4, + "trailingComma": "es5", + "singleQuote": true, + "jsxBracketSameLine": true +} diff --git a/README.md b/README.md index 71da61b60..d0a973bd9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,13 @@ Web application for [ente](https://ente.io) built with lots of ❤️ and a litt ## Getting Started -First, run the development server: +First, pull and install dependencies +```bash +git submodule update --init --recursive +yarn install +``` + +Then run the development server: ```bash npm run dev diff --git a/package.json b/package.json index 8143b7451..69e4fa410 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,7 @@ "build-analyze": "ANALYZE=true next build", "postbuild": "next export", "start": "next start", - "lint-staged": "lint-staged", - "postinstall": "husky install" + "prepare": "husky install" }, "dependencies": { "@ente-io/next-with-workbox": "^1.0.3", @@ -18,7 +17,7 @@ "@stripe/stripe-js": "^1.13.2", "@typescript-eslint/eslint-plugin": "^4.25.0", "@typescript-eslint/parser": "^4.25.0", - "axios": "^0.20.0", + "axios": "^0.21.1", "bootstrap": "^4.5.2", "chrono-node": "^2.2.6", "comlink": "^4.3.0", @@ -32,6 +31,7 @@ "heic2any": "^0.0.3", "http-proxy-middleware": "^1.0.5", "is-electron": "^2.2.0", + "jszip": "3.7.1", "libsodium-wrappers": "^0.7.8", "localforage": "^1.9.0", "next": "^10.2.3", @@ -62,7 +62,6 @@ "@next/bundle-analyzer": "^9.5.3", "@types/debounce-promise": "^3.1.3", "@types/libsodium-wrappers": "^0.7.8", - "@types/localforage": "^0.0.34", "@types/node": "^14.6.4", "@types/photoswipe": "^4.1.1", "@types/react": "^16.9.49", @@ -74,20 +73,17 @@ "babel-plugin-styled-components": "^1.11.1", "eslint": "^7.27.0", "eslint-config-google": "^0.14.0", + "eslint-config-prettier": "^8.3.0", "eslint-plugin-react": "^7.23.2", - "husky": "^6.0.0", - "lint-staged": "^11.0.0", + "husky": "^7.0.1", + "lint-staged": "^11.1.2", + "prettier": "2.3.2", "typescript": "^4.1.3" }, "standard": { "parser": "babel-eslint" }, "lint-staged": { - "src/**/*.{js,jsx,ts,tsx}": "eslint" - }, - "husky": { - "hooks": { - "pre-commit": "yarn run lint-staged" - } + "src/**/*.{js,jsx,ts,tsx}": ["eslint --fix","prettier --write --ignore-unknown"] } } diff --git a/sentry.client.config.js b/sentry.client.config.js index 0b58a12e8..228a35171 100644 --- a/sentry.client.config.js +++ b/sentry.client.config.js @@ -1,13 +1,12 @@ import * as Sentry from '@sentry/nextjs'; import { getSentryTunnelUrl } from 'utils/common/apiUtil'; -import { getData, LS_KEYS } from 'utils/storage/localStorage'; +import { getUserAnonymizedID } from 'utils/user'; const SENTRY_DSN = process.env.NEXT_PUBLIC_SENTRY_DSN ?? 'https://860186db60c54c7fbacfe255124958e8@errors.ente.io/4'; const SENTRY_ENV = process.env.NEXT_PUBLIC_SENTRY_ENV ?? 'development'; -const userID = getData(LS_KEYS.USER)?.id; -Sentry.setUser({ id: userID }); +Sentry.setUser({ id: getUserAnonymizedID() }); Sentry.init({ dsn: SENTRY_DSN, enabled: SENTRY_ENV !== 'development', diff --git a/src/components/AddToCollectionBtn.tsx b/src/components/AddToCollectionBtn.tsx index c33923733..8acfdcbd6 100644 --- a/src/components/AddToCollectionBtn.tsx +++ b/src/components/AddToCollectionBtn.tsx @@ -25,8 +25,7 @@ export default function AddToCollectionBtn(props) { stroke="currentColor" strokeWidth="2" strokeLinecap="round" - strokeLinejoin="round" - > + strokeLinejoin="round"> diff --git a/src/components/ChangeEmail.tsx b/src/components/ChangeEmail.tsx new file mode 100644 index 000000000..7fae2aa7e --- /dev/null +++ b/src/components/ChangeEmail.tsx @@ -0,0 +1,175 @@ +import { Formik, FormikHelpers } from 'formik'; +import React, { useContext, useEffect, useRef, useState } from 'react'; +import { Button, Col, Form, FormControl } from 'react-bootstrap'; +import * as Yup from 'yup'; +import constants from 'utils/strings/constants'; +import SubmitButton from 'components/SubmitButton'; +import router from 'next/router'; +import { changeEmail, getOTTForEmailChange } from 'services/userService'; +import styled from 'styled-components'; +import { AppContext, FLASH_MESSAGE_TYPE } from 'pages/_app'; +import { getData, LS_KEYS, setData } from 'utils/storage/localStorage'; + +interface formValues { + email: string; + ott?: string; +} + +const EmailRow = styled.div` + display: flex; + flex-wrap: wrap; + border: 1px solid grey; + margin-bottom: 19px; + align-items: center; + text-align: left; + color: #fff; +`; + +interface Props { + showMessage: (value: boolean) => void; + setEmail: (email: string) => void; +} +function ChangeEmailForm(props: Props) { + const [loading, setLoading] = useState(false); + const [ottInputVisible, setShowOttInputVisibility] = useState(false); + const emailInputElement = useRef(null); + const ottInputRef = useRef(null); + const appContext = useContext(AppContext); + + useEffect(() => { + setTimeout(() => { + emailInputElement.current?.focus(); + }, 250); + }, []); + + useEffect(() => { + if (!ottInputVisible) { + props.showMessage(false); + } + }, [ottInputVisible]); + + const requestOTT = async ( + { email }: formValues, + { setFieldError }: FormikHelpers + ) => { + try { + setLoading(true); + await getOTTForEmailChange(email); + props.setEmail(email); + setShowOttInputVisibility(true); + props.showMessage(true); + setTimeout(() => { + ottInputRef.current?.focus(); + }, 250); + } catch (e) { + setFieldError('email', `${constants.EMAIl_ALREADY_OWNED}`); + } + setLoading(false); + }; + + const requestEmailChange = async ( + { email, ott }: formValues, + { setFieldError }: FormikHelpers + ) => { + try { + setLoading(true); + await changeEmail(email, ott); + setData(LS_KEYS.USER, { ...getData(LS_KEYS.USER), email }); + appContext.setDisappearingFlashMessage({ + message: constants.EMAIL_UDPATE_SUCCESSFUL, + type: FLASH_MESSAGE_TYPE.SUCCESS, + }); + router.push('/gallery'); + } catch (e) { + setFieldError('ott', `${constants.INCORRECT_CODE}`); + } + setLoading(false); + }; + + return ( + + initialValues={{ email: '' }} + validationSchema={Yup.object().shape({ + email: Yup.string() + .email(constants.EMAIL_ERROR) + .required(constants.REQUIRED), + })} + validateOnChange={false} + validateOnBlur={false} + onSubmit={!ottInputVisible ? requestOTT : requestEmailChange}> + {({ values, errors, touched, handleChange, handleSubmit }) => ( +
+ {!ottInputVisible ? ( + + + + {errors.email} + + + ) : ( + <> + + {values.email} + + + + + + + + {errors.ott} + + + + )} + + +
+ + + )} + + ); +} + +export default ChangeEmailForm; diff --git a/src/components/CollectionShare.tsx b/src/components/CollectionShare.tsx index 232fef8c0..4ff513bc2 100644 --- a/src/components/CollectionShare.tsx +++ b/src/components/CollectionShare.tsx @@ -34,7 +34,7 @@ function CollectionShare(props: Props) { const [loading, setLoading] = useState(false); const collectionShare = async ( { email }: formValues, - { resetForm, setFieldError }: FormikHelpers, + { resetForm, setFieldError }: FormikHelpers ) => { try { setLoading(true); @@ -89,8 +89,7 @@ function CollectionShare(props: Props) { fontSize: '1.2em', fontWeight: 900, }} - onClick={() => collectionUnshare(sharee)} - > + onClick={() => collectionUnshare(sharee)}> - @@ -100,8 +99,7 @@ function CollectionShare(props: Props) { + attributes={{ title: constants.SHARE_COLLECTION }}>
{constants.SHARE_WITH_PEOPLE}

@@ -114,8 +112,7 @@ function CollectionShare(props: Props) { })} validateOnChange={false} validateOnBlur={false} - onSubmit={collectionShare} - > + onSubmit={collectionShare}> {({ values, errors, @@ -128,15 +125,14 @@ function CollectionShare(props: Props) { + controlId="formHorizontalEmail"> + controlId="formHorizontalEmail"> ` - width:${(props) => props.width ?? '70%'}; +export const Label = styled.div<{ width?: string }>` + width: ${(props) => props.width ?? '70%'}; `; -export const Value = styled.div <{ width?: string }> ` - display:flex; - justify-content:flex-start; - align-items:center; - width:${(props) => props.width ?? '30%'}; +export const Value = styled.div<{ width?: string }>` + display: flex; + justify-content: flex-start; + align-items: center; + width: ${(props) => props.width ?? '30%'}; text-align: center; color: #ddd; `; diff --git a/src/components/DeleteBtn.tsx b/src/components/DeleteBtn.tsx index a59f9978b..6bf7bbae6 100644 --- a/src/components/DeleteBtn.tsx +++ b/src/components/DeleteBtn.tsx @@ -20,8 +20,7 @@ export default function DeleteBtn(props) { xmlns="http://www.w3.org/2000/svg" height={props.height} viewBox={props.viewBox} - width={props.width} - > + width={props.width}> diff --git a/src/components/EnteCard.tsx b/src/components/EnteCard.tsx new file mode 100644 index 000000000..3e1a2638d --- /dev/null +++ b/src/components/EnteCard.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Card } from 'react-bootstrap'; + +type Size = 'sm' | 'md' | 'lg'; + +const EnteCard = ({ + size, + children, + style, +}: { + size: Size; + children?: any; + style?: any; +}) => { + let minWidth: string; + let padding: string; + switch (size) { + case 'sm': + minWidth = '320px'; + padding = '0px'; + break; + case 'md': + minWidth = '460px'; + padding = '10px'; + break; + + default: + minWidth = '480px'; + padding = '10px'; + break; + } + return ( + + {children} + + ); +}; + +export default EnteCard; diff --git a/src/components/ExportFinished.tsx b/src/components/ExportFinished.tsx index f2f0faf97..dedae4d34 100644 --- a/src/components/ExportFinished.tsx +++ b/src/components/ExportFinished.tsx @@ -6,14 +6,13 @@ import constants from 'utils/strings/constants'; import { Label, Row, Value } from './Container'; import { ComfySpan } from './ExportInProgress'; - interface Props { - show: boolean - onHide: () => void - exportFolder: string - exportSize: string - lastExportTime: number - exportStats: ExportStats + show: boolean; + onHide: () => void; + exportFolder: string; + exportSize: string; + lastExportTime: number; + exportStats: ExportStats; updateExportFolder: (newFolder: string) => void; exportFiles: () => void; retryFailed: () => void; @@ -23,30 +22,69 @@ export default function ExportFinished(props: Props) { const totalFiles = props.exportStats.failed + props.exportStats.success; return ( <> -

+
- {formatDateTime(props.lastExportTime)} - - - - {props.exportStats.success} / {totalFiles} - - {props.exportStats.failed>0 && - - - - {props.exportStats.failed} / {totalFiles} + + {formatDateTime(props.lastExportTime)} - } + + + + + + {props.exportStats.success} / {totalFiles} + + + + {props.exportStats.failed > 0 && ( + + + + + {props.exportStats.failed} / {totalFiles} + + + + )}
-
- +
+
- {props.exportStats.failed !== 0 ? - : - - } + {props.exportStats.failed !== 0 ? ( + + ) : ( + + )}
); diff --git a/src/components/ExportInProgress.tsx b/src/components/ExportInProgress.tsx index 1083d907b..5faa2786b 100644 --- a/src/components/ExportInProgress.tsx +++ b/src/components/ExportInProgress.tsx @@ -5,42 +5,82 @@ import styled from 'styled-components'; import constants from 'utils/strings/constants'; export const ComfySpan = styled.span` - word-spacing:1rem; - color:#ddd; + word-spacing: 1rem; + color: #ddd; `; interface Props { - show: boolean - onHide: () => void - exportFolder: string - exportSize: string - exportStage: ExportStage - exportProgress: ExportProgress + show: boolean; + onHide: () => void; + exportFolder: string; + exportSize: string; + exportStage: ExportStage; + exportProgress: ExportProgress; resumeExport: () => void; - cancelExport: () => void + cancelExport: () => void; pauseExport: () => void; } export default function ExportInProgress(props: Props) { return ( <> -
+
- {props.exportProgress.current} / {props.exportProgress.total} files exported {props.exportStage === ExportStage.PAUSED && `(paused)`} + + {' '} + {props.exportProgress.current} /{' '} + {props.exportProgress.total}{' '} + {' '} + + {' '} + files exported{' '} + {props.exportStage === ExportStage.PAUSED && `(paused)`} +
-
- {props.exportStage === ExportStage.PAUSED ? - : - - } +
+ {props.exportStage === ExportStage.PAUSED ? ( + + ) : ( + + )}
- +
diff --git a/src/components/ExportInit.tsx b/src/components/ExportInit.tsx index d37cd3cbf..29a45ffc0 100644 --- a/src/components/ExportInit.tsx +++ b/src/components/ExportInit.tsx @@ -4,18 +4,18 @@ import { Button } from 'react-bootstrap'; import constants from 'utils/strings/constants'; interface Props { - show: boolean - onHide: () => void + show: boolean; + onHide: () => void; updateExportFolder: (newFolder: string) => void; - exportFolder: string - startExport: () => void + exportFolder: string; + startExport: () => void; exportSize: string; - selectExportDirectory: () => void + selectExportDirectory: () => void; } export default function ExportInit(props: Props) { return ( <> - + + onClick={props.startExport}> + {constants.START} + ); diff --git a/src/components/ExportModal.tsx b/src/components/ExportModal.tsx index c2a080477..a03d4b722 100644 --- a/src/components/ExportModal.tsx +++ b/src/components/ExportModal.tsx @@ -1,11 +1,16 @@ import isElectron from 'is-electron'; import React, { useEffect, useState } from 'react'; import { Button } from 'react-bootstrap'; -import exportService, { ExportProgress, ExportStage, ExportStats, ExportType } from 'services/exportService'; +import exportService, { + ExportProgress, + ExportStage, + ExportStats, + ExportType, +} from 'services/exportService'; import { getLocalFiles } from 'services/fileService'; import styled from 'styled-components'; import { sleep } from 'utils/common'; -import { getFileUID } from 'utils/export'; +import { getExportRecordFileUID } from 'utils/export'; import { getData, LS_KEYS, setData } from 'utils/storage/localStorage'; import constants from 'utils/strings/constants'; import { Label, Row, Value } from './Container'; @@ -18,38 +23,44 @@ import MessageDialog from './MessageDialog'; const FolderIconWrapper = styled.div` width: 15%; - margin-left: 10px; - cursor: pointer; + margin-left: 10px; + cursor: pointer; padding: 3px; border: 1px solid #444; - border-radius:15%; - &:hover{ - background-color:#444; + border-radius: 15%; + &:hover { + background-color: #444; } `; -const ExportFolderPathContainer =styled.span` - white-space: nowrap; +const ExportFolderPathContainer = styled.span` + white-space: nowrap; overflow: hidden; - text-overflow: ellipsis; + text-overflow: ellipsis; width: 200px; - + /* Beginning of string */ direction: rtl; text-align: left; `; interface Props { - show: boolean - onHide: () => void - usage: string + show: boolean; + onHide: () => void; + usage: string; } export default function ExportModal(props: Props) { const [exportStage, setExportStage] = useState(ExportStage.INIT); const [exportFolder, setExportFolder] = useState(''); const [exportSize, setExportSize] = useState(''); - const [exportProgress, setExportProgress] = useState({ current: 0, total: 0 }); - const [exportStats, setExportStats] = useState({ failed: 0, success: 0 }); + const [exportProgress, setExportProgress] = useState({ + current: 0, + total: 0, + }); + const [exportStats, setExportStats] = useState({ + failed: 0, + success: 0, + }); const [lastExportTime, setLastExportTime] = useState(0); // ==================== @@ -64,7 +75,9 @@ export default function ExportModal(props: Props) { exportService.ElectronAPIs.registerStopExportListener(stopExport); exportService.ElectronAPIs.registerPauseExportListener(pauseExport); exportService.ElectronAPIs.registerResumeExportListener(resumeExport); - exportService.ElectronAPIs.registerRetryFailedExportListener(retryFailedExport); + exportService.ElectronAPIs.registerRetryFailedExportListener( + retryFailedExport + ); }, []); useEffect(() => { @@ -76,7 +89,10 @@ export default function ExportModal(props: Props) { setExportStage(exportInfo?.stage ?? ExportStage.INIT); setLastExportTime(exportInfo?.lastAttemptTimestamp); setExportProgress(exportInfo?.progress ?? { current: 0, total: 0 }); - setExportStats({ success: exportInfo?.exportedFiles?.length ?? 0, failed: exportInfo?.failedFiles?.length ?? 0 }); + setExportStats({ + success: exportInfo?.exportedFiles?.length ?? 0, + failed: exportInfo?.failedFiles?.length ?? 0, + }); if (exportInfo?.stage === ExportStage.INPROGRESS) { resumeExport(); } @@ -96,10 +112,22 @@ export default function ExportModal(props: Props) { const failedFilesCnt = exportRecord.failedFiles.length; const syncedFilesCnt = localFiles.length; if (syncedFilesCnt > exportedFileCnt + failedFilesCnt) { - updateExportProgress({ current: exportedFileCnt + failedFilesCnt, total: syncedFilesCnt }); - const exportFileUIDs = new Set([...exportRecord.exportedFiles, ...exportRecord.failedFiles]); - const unExportedFiles = localFiles.filter((file) => !exportFileUIDs.has(getFileUID(file))); - exportService.addFilesQueuedRecord(exportFolder, unExportedFiles); + updateExportProgress({ + current: exportedFileCnt + failedFilesCnt, + total: syncedFilesCnt, + }); + const exportFileUIDs = new Set([ + ...exportRecord.exportedFiles, + ...exportRecord.failedFiles, + ]); + const unExportedFiles = localFiles.filter( + (file) => + !exportFileUIDs.has(getExportRecordFileUID(file)) + ); + exportService.addFilesQueuedRecord( + exportFolder, + unExportedFiles + ); updateExportStage(ExportStage.PAUSED); } } @@ -107,7 +135,6 @@ export default function ExportModal(props: Props) { main(); }, [props.show]); - useEffect(() => { setExportSize(props.usage); }, [props.usage]); @@ -162,7 +189,10 @@ export default function ExportModal(props: Props) { const startExport = async () => { await preExportRun(); updateExportProgress({ current: 0, total: 0 }); - const { paused } = await exportService.exportFiles(updateExportProgress, ExportType.NEW); + const { paused } = await exportService.exportFiles( + updateExportProgress, + ExportType.NEW + ); await postExportRun(paused); }; @@ -184,13 +214,15 @@ export default function ExportModal(props: Props) { const pausedStageProgress = exportRecord.progress; setExportProgress(pausedStageProgress); - const updateExportStatsWithOffset = ((progress: ExportProgress) => updateExportProgress( - { + const updateExportStatsWithOffset = (progress: ExportProgress) => + updateExportProgress({ current: pausedStageProgress.current + progress.current, total: pausedStageProgress.current + progress.total, - }, - )); - const { paused } = await exportService.exportFiles(updateExportStatsWithOffset, ExportType.PENDING); + }); + const { paused } = await exportService.exportFiles( + updateExportStatsWithOffset, + ExportType.PENDING + ); await postExportRun(paused); }; @@ -199,7 +231,10 @@ export default function ExportModal(props: Props) { await preExportRun(); updateExportProgress({ current: 0, total: exportStats.failed }); - const { paused } = await exportService.exportFiles(updateExportProgress, ExportType.RETRY_FAILED); + const { paused } = await exportService.exportFiles( + updateExportProgress, + ExportType.RETRY_FAILED + ); await postExportRun(paused); }; @@ -224,7 +259,8 @@ export default function ExportModal(props: Props) { switch (exportStage) { case ExportStage.INIT: return ( - ); - default: return (<>); + default: + return <>; } }; @@ -269,34 +307,50 @@ export default function ExportModal(props: Props) { onHide={props.onHide} attributes={{ title: constants.EXPORT_DATA, - }} - > -
+ }}> +
- {!exportFolder ? - () : - (<> + {!exportFolder ? ( + + ) : ( + <> {/* */} {exportFolder} {/* */} - {(exportStage === ExportStage.FINISHED || exportStage === ExportStage.INIT) && ( - + {(exportStage === ExportStage.FINISHED || + exportStage === ExportStage.INIT) && ( + )} - ) - } + + )} - {exportSize ? `${exportSize} GB` : } + + + {exportSize ? `${exportSize}` : } +
- + ); } diff --git a/src/components/FavButton.tsx b/src/components/FavButton.tsx index e442ceacf..32a988e8b 100644 --- a/src/components/FavButton.tsx +++ b/src/components/FavButton.tsx @@ -12,7 +12,8 @@ const HeartUI = styled.button<{ cursor: pointer; background-size: cover; border: none; - ${({ isClick, size }) => isClick && + ${({ isClick, size }) => + isClick && `background-position: -${ 28 * size }px;transition: background 1s steps(28);`} diff --git a/src/components/FlashMessageBar.tsx b/src/components/FlashMessageBar.tsx index e284fc743..6838d2b94 100644 --- a/src/components/FlashMessageBar.tsx +++ b/src/components/FlashMessageBar.tsx @@ -2,15 +2,19 @@ import { FlashMessage } from 'pages/_app'; import React from 'react'; import Alert from 'react-bootstrap/Alert'; - -export default function FlashMessageBar({ flashMessage, onClose }: { flashMessage: FlashMessage, onClose: () => void }) { +export default function FlashMessageBar({ + flashMessage, + onClose, +}: { + flashMessage: FlashMessage; + onClose: () => void; +}) { return ( + onClose={onClose}>
{flashMessage.message}
diff --git a/src/components/FullScreenDropZone.tsx b/src/components/FullScreenDropZone.tsx index 1fa12fafe..92f330be7 100644 --- a/src/components/FullScreenDropZone.tsx +++ b/src/components/FullScreenDropZone.tsx @@ -5,9 +5,9 @@ import CrossIcon from './icons/CrossIcon'; const CloseButtonWrapper = styled.div` position: absolute; - top:10px; - right:10px; - cursor:pointer; + top: 10px; + right: 10px; + cursor: pointer; `; const DropDiv = styled.div` flex: 1; @@ -62,14 +62,10 @@ export default function FullScreenDropZone(props: Props) { e.preventDefault(); props.showCollectionSelector(); }, - })} - > + })}> {isDragActive && ( - + diff --git a/src/components/IncognitoWarning.tsx b/src/components/IncognitoWarning.tsx index 5780e35c4..f6e449247 100644 --- a/src/components/IncognitoWarning.tsx +++ b/src/components/IncognitoWarning.tsx @@ -11,11 +11,8 @@ export default function IncognitoWarning() { title: constants.LOCAL_STORAGE_NOT_ACCESSIBLE, staticBackdrop: true, nonClosable: true, - }} - > -
- {constants.LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE} -
+ }}> +
{constants.LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE}
); } diff --git a/src/components/Login.tsx b/src/components/Login.tsx index cae5f138c..bee509bc1 100644 --- a/src/components/Login.tsx +++ b/src/components/Login.tsx @@ -17,7 +17,7 @@ interface formValues { } interface LoginProps { - signUp: () => void + signUp: () => void; } export default function Login(props: LoginProps) { @@ -39,7 +39,7 @@ export default function Login(props: LoginProps) { const loginUser = async ( { email }: formValues, - { setFieldError }: FormikHelpers, + { setFieldError }: FormikHelpers ) => { try { setWaiting(true); @@ -73,15 +73,8 @@ export default function Login(props: LoginProps) { })} validateOnChange={false} validateOnBlur={false} - onSubmit={loginUser} - > - {({ - values, - errors, - touched, - handleChange, - handleSubmit, - }) => ( + onSubmit={loginUser}> + {({ values, errors, touched, handleChange, handleSubmit }) => (

- diff --git a/src/components/MessageDialog.tsx b/src/components/MessageDialog.tsx index fa2378bfe..92ca4c5e9 100644 --- a/src/components/MessageDialog.tsx +++ b/src/components/MessageDialog.tsx @@ -7,7 +7,7 @@ export interface MessageAttributes { staticBackdrop?: boolean; nonClosable?: boolean; content?: any; - close?: { text?: string; variant?: string, action?: () => void }; + close?: { text?: string; variant?: string; action?: () => void }; proceed?: { text: string; action: () => void; @@ -38,21 +38,21 @@ export default function MessageDialog({ {...props} onHide={attributes.nonClosable ? () => null : props.onHide} centered - backdrop={attributes.staticBackdrop ? 'static' : 'true'} - > + backdrop={attributes.staticBackdrop ? 'static' : 'true'}> + closeButton={!attributes.nonClosable}> {attributes.title && ( - - {attributes.title} - + {attributes.title} )} {(children || attributes?.content) && ( - {children ||

{attributes.content}

} + {children || ( +

+ {attributes.content} +

+ )}
)} {(attributes.close || attributes.proceed) && ( @@ -61,13 +61,16 @@ export default function MessageDialog({ style={{ display: 'flex', flexWrap: 'wrap', - }} - > + }}> {attributes.close && ( )} {attributes.proceed && ( )} diff --git a/src/components/NavigationButton.tsx b/src/components/NavigationButton.tsx index 62a41ac9a..c8aefcd3b 100644 --- a/src/components/NavigationButton.tsx +++ b/src/components/NavigationButton.tsx @@ -15,11 +15,17 @@ const Wrapper = styled.button<{ direction: SCROLL_DIRECTION }>` color: #eee; z-index: 1; position: absolute; - ${(props) => (props.direction === SCROLL_DIRECTION.LEFT ? 'margin-right: 10px;' : 'margin-left: 10px;')} - ${(props) => (props.direction === SCROLL_DIRECTION.LEFT ? 'left: 0;' : 'right: 0;')} + ${(props) => + props.direction === SCROLL_DIRECTION.LEFT + ? 'margin-right: 10px;' + : 'margin-left: 10px;'} + ${(props) => + props.direction === SCROLL_DIRECTION.LEFT ? 'left: 0;' : 'right: 0;'} & > svg { - ${(props) => props.direction === SCROLL_DIRECTION.LEFT && 'transform:rotate(180deg);'} + ${(props) => + props.direction === SCROLL_DIRECTION.LEFT && + 'transform:rotate(180deg);'} border-radius: 50%; height: 30px; width: 30px; @@ -30,25 +36,33 @@ const Wrapper = styled.button<{ direction: SCROLL_DIRECTION }>` } &:hover { - color:#fff; + color: #fff; } &::after { content: ' '; - background: linear-gradient(to ${(props) => (props.direction === SCROLL_DIRECTION.LEFT ? 'right' : 'left')}, #191919 5%, rgba(255, 255, 255, 0) 80%); + background: linear-gradient( + to + ${(props) => + props.direction === SCROLL_DIRECTION.LEFT + ? 'right' + : 'left'}, + #191919 5%, + rgba(255, 255, 255, 0) 80% + ); position: absolute; top: 0; width: 40px; height: 40px; - ${(props) => (props.direction === SCROLL_DIRECTION.LEFT ? 'left: 40px;' : 'right: 40px;')} + ${(props) => + props.direction === SCROLL_DIRECTION.LEFT + ? 'left: 40px;' + : 'right: 40px;'} } `; const NavigationButton = ({ scrollDirection, ...rest }) => ( - + ); diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index 9aa0a3a4a..d03f21eb7 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -1,7 +1,6 @@ import router from 'next/router'; import { DeadCenter, - FILE_TYPE, GalleryContext, Search, SetFiles, @@ -10,7 +9,7 @@ import { import PreviewCard from './pages/gallery/PreviewCard'; import React, { useContext, useEffect, useRef, useState } from 'react'; import { Button } from 'react-bootstrap'; -import { File } from 'services/fileService'; +import { File, FILE_TYPE } from 'services/fileService'; import styled from 'styled-components'; import DownloadManager from 'services/downloadManager'; import constants from 'utils/strings/constants'; @@ -19,10 +18,14 @@ import { VariableSizeList as List } from 'react-window'; import PhotoSwipe from 'components/PhotoSwipe/PhotoSwipe'; import { isInsideBox, isSameDay as isSameDayAnyYear } from 'utils/search'; import { SetDialogMessage } from './MessageDialog'; -import { VIDEO_PLAYBACK_FAILED } from 'utils/common/errorUtil'; +import { CustomError } from 'utils/common/errorUtil'; import { - GAP_BTW_TILES, DATE_CONTAINER_HEIGHT, IMAGE_CONTAINER_MAX_HEIGHT, - IMAGE_CONTAINER_MAX_WIDTH, MIN_COLUMNS, SPACE_BTW_DATES, + GAP_BTW_TILES, + DATE_CONTAINER_HEIGHT, + IMAGE_CONTAINER_MAX_HEIGHT, + IMAGE_CONTAINER_MAX_WIDTH, + MIN_COLUMNS, + SPACE_BTW_DATES, } from 'types'; const NO_OF_PAGES = 2; @@ -68,21 +71,24 @@ const getTemplateColumns = (columns: number, groups?: number[]): string => { if (sum < columns) { groups[groups.length - 1] += columns - sum; } - return groups.map((x) => `repeat(${x}, 1fr)`).join(` ${SPACE_BTW_DATES}px `); + return groups + .map((x) => `repeat(${x}, 1fr)`) + .join(` ${SPACE_BTW_DATES}px `); } else { return `repeat(${columns}, 1fr)`; } }; -const ListContainer = styled.div<{ columns: number, groups?: number[] }>` +const ListContainer = styled.div<{ columns: number; groups?: number[] }>` display: grid; - grid-template-columns: ${({ columns, groups }) => getTemplateColumns(columns, groups)}; + grid-template-columns: ${({ columns, groups }) => + getTemplateColumns(columns, groups)}; grid-column-gap: ${GAP_BTW_TILES}px; padding: 0 24px; width: 100%; color: #fff; - @media(max-width: ${IMAGE_CONTAINER_MAX_WIDTH * 4}px) { + @media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * 4}px) { padding: 0 4px; } `; @@ -139,7 +145,7 @@ interface Props { search: Search; setSearchStats: setSearchStats; deleted?: number[]; - setDialogMessage: SetDialogMessage + setDialogMessage: SetDialogMessage; } const PhotoFrame = ({ @@ -303,14 +309,13 @@ const PhotoFrame = ({ video.preload = 'metadata'; video.src = url; video.currentTime = 3; - const t = setTimeout( - () => { - reject( - Error(`${VIDEO_PLAYBACK_FAILED} err: wait time exceeded`), - ); - }, - WAIT_FOR_VIDEO_PLAYBACK, - ); + const t = setTimeout(() => { + reject( + Error( + `${CustomError.VIDEO_PLAYBACK_FAILED} err: wait time exceeded` + ) + ); + }, WAIT_FOR_VIDEO_PLAYBACK); }); item.html = `