Pushkar Anand před 4 roky
rodič
revize
adb6af09ce
83 změnil soubory, kde provedl 2494 přidání a 1898 odebrání
  1. 50 0
      .eslintrc.json
  2. 1 0
      .husky/.gitignore
  3. 4 0
      .husky/pre-commit
  4. 1 1
      next.config.js
  5. 23 1
      package.json
  6. 2 2
      src/components/AddToCollectionBtn.tsx
  7. 2 2
      src/components/ArrowEast.tsx
  8. 2 2
      src/components/CloudUpload.tsx
  9. 31 31
      src/components/CollectionShare.tsx
  10. 1 1
      src/components/CrossIcon.tsx
  11. 1 1
      src/components/DateIcon.tsx
  12. 1 1
      src/components/EnteSpinner.tsx
  13. 2 3
      src/components/FavButton.tsx
  14. 2 3
      src/components/FullScreenDropZone.tsx
  15. 2 3
      src/components/LocationIcon.tsx
  16. 5 5
      src/components/MessageDialog.tsx
  17. 3 1
      src/components/NavigateNext.tsx
  18. 14 16
      src/components/NavigationButton.tsx
  19. 111 125
      src/components/PhotoFrame.tsx
  20. 23 33
      src/components/PhotoSwipe/PhotoSwipe.tsx
  21. 4 5
      src/components/RecoveryKeyModal.tsx
  22. 46 53
      src/components/SearchBar.tsx
  23. 1 1
      src/components/SearchIcon.tsx
  24. 13 13
      src/components/SetPasswordForm.tsx
  25. 60 66
      src/components/Sidebar.tsx
  26. 10 8
      src/components/SingleInputForm.tsx
  27. 6 4
      src/components/SubmitButton.tsx
  28. 4 3
      src/pages/404.js
  29. 11 12
      src/pages/_app.tsx
  30. 8 7
      src/pages/_document.tsx
  31. 56 55
      src/pages/_error.js
  32. 3 4
      src/pages/api/[...all].ts
  33. 12 15
      src/pages/changePassword/index.tsx
  34. 14 15
      src/pages/credentials/index.tsx
  35. 5 5
      src/pages/gallery/components/AddCollectionButton.tsx
  36. 2 2
      src/pages/gallery/components/AlertBanner.tsx
  37. 4 4
      src/pages/gallery/components/ChoiceModal.tsx
  38. 12 10
      src/pages/gallery/components/CollectionNamer.tsx
  39. 14 13
      src/pages/gallery/components/CollectionOptions.tsx
  40. 5 5
      src/pages/gallery/components/CollectionSelector.tsx
  41. 37 41
      src/pages/gallery/components/Collections.tsx
  42. 8 8
      src/pages/gallery/components/LinkButton.tsx
  43. 20 21
      src/pages/gallery/components/OptionIcon.tsx
  44. 83 87
      src/pages/gallery/components/PlanSelector.tsx
  45. 2 2
      src/pages/gallery/components/PreviewCard.tsx
  46. 26 33
      src/pages/gallery/components/SelectedFileOptions.tsx
  47. 48 52
      src/pages/gallery/components/Upload.tsx
  48. 1 1
      src/pages/gallery/components/UploadButton.tsx
  49. 26 24
      src/pages/gallery/components/UploadProgress.tsx
  50. 75 88
      src/pages/gallery/index.tsx
  51. 13 13
      src/pages/generate/index.tsx
  52. 15 14
      src/pages/index.tsx
  53. 11 11
      src/pages/recover/index.tsx
  54. 21 25
      src/pages/signup/index.tsx
  55. 18 26
      src/pages/verify/index.tsx
  56. 14 16
      src/services/HTTPService.ts
  57. 47 39
      src/services/billingService.ts
  58. 83 98
      src/services/collectionService.ts
  59. 79 82
      src/services/downloadManager.ts
  60. 22 19
      src/services/exportService.ts
  61. 27 30
      src/services/fileService.ts
  62. 23 29
      src/services/searchService.ts
  63. 220 225
      src/services/uploadService.ts
  64. 34 44
      src/services/userService.ts
  65. 54 54
      src/utils/billingUtil.ts
  66. 5 5
      src/utils/collection/index.ts
  67. 9 10
      src/utils/common/apiUtil.ts
  68. 15 18
      src/utils/common/errorUtil.ts
  69. 4 6
      src/utils/common/index.ts
  70. 8 11
      src/utils/common/key.ts
  71. 5 5
      src/utils/common/useLongPress.ts
  72. 26 34
      src/utils/crypto/index.ts
  73. 65 68
      src/utils/crypto/libsodium.ts
  74. 10 10
      src/utils/file/index.ts
  75. 12 14
      src/utils/search/index.ts
  76. 5 5
      src/utils/sentry/index.ts
  77. 5 7
      src/utils/storage/index.ts
  78. 3 2
      src/utils/storage/localForage.ts
  79. 1 1
      src/utils/strings/constants.ts
  80. 89 68
      src/utils/strings/englishConstants.tsx
  81. 6 5
      src/utils/strings/vernacularStrings.ts
  82. 6 3
      src/worker/crypto.worker.js
  83. 642 13
      yarn.lock

+ 50 - 0
.eslintrc.json

@@ -0,0 +1,50 @@
+{
+    "env": {
+        "browser": true,
+        "es2021": true,
+        "node": true
+    },
+    "extends": [
+        "plugin:react/recommended",
+        "eslint:recommended",
+        "plugin:@typescript-eslint/eslint-recommended",
+        "google"
+    ],
+    "parser": "@typescript-eslint/parser",
+    "parserOptions": {
+        "ecmaFeatures": {
+            "jsx": true
+        },
+        "ecmaVersion": 12,
+        "sourceType": "module"
+    },
+    "plugins": [
+        "react",
+        "@typescript-eslint"
+    ],
+    "rules": {
+        "indent": ["error", 4],
+        "class-methods-use-this": "off",
+        "react/prop-types": "off",
+        "react/display-name": "off",
+        "react/no-unescaped-entities": "off",
+        "no-unused-vars": "off",
+        "@typescript-eslint/no-unused-vars": ["error"],
+        "require-jsdoc": "off",
+        "valid-jsdoc": "off",
+        "max-len": "off",
+        "new-cap": "off",
+        "no-invalid-this": "off",
+        "eqeqeq": "error"
+    },
+    "settings": {
+        "react": {
+            "version": "detect"
+        }
+    },
+    "globals": {
+        "JSX": "readonly",
+        "NodeJS": "readonly",
+        "ReadableStreamDefaultController": "readonly"
+    }
+}

+ 1 - 0
.husky/.gitignore

@@ -0,0 +1 @@
+_

+ 4 - 0
.husky/pre-commit

@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")/_/husky.sh"
+
+yarn lint-staged

+ 1 - 1
next.config.js

@@ -30,7 +30,7 @@ module.exports = withWorkbox(withBundleAnalyzer({
     workbox: {
         swSrc: "src/serviceWorker.js",
     },
-    webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
+    webpack: (config, { isServer, webpack }) => {
         if (!isServer) {
             config.plugins.push(
                 new WorkerPlugin({

+ 23 - 1
package.json

@@ -4,10 +4,13 @@
   "private": true,
   "scripts": {
     "dev": "next dev",
+    "prebuild": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
     "build": "next build",
     "build-analyze": "ANALYZE=true next build",
     "postbuild": "next-on-netlify",
-    "start": "next start"
+    "start": "next start",
+    "lint-staged": "lint-staged",
+    "postinstall": "husky install"
   },
   "dependencies": {
     "@sentry/browser": "^5.21.3",
@@ -15,11 +18,17 @@
     "@sentry/node": "^5.21.3",
     "@sentry/webpack-plugin": "^1.12.1",
     "@stripe/stripe-js": "^1.13.2",
+    "@typescript-eslint/eslint-plugin": "^4.25.0",
+    "@typescript-eslint/parser": "^4.25.0",
     "axios": "^0.20.0",
     "bootstrap": "^4.5.2",
     "chrono-node": "^2.2.6",
     "comlink": "^4.3.0",
     "debounce-promise": "^3.1.2",
+    "eslint-config-airbnb": "^18.2.1",
+    "eslint-plugin-import": "^2.23.3",
+    "eslint-plugin-jsx-a11y": "^6.4.1",
+    "eslint-plugin-react-hooks": "^4.2.0",
     "exif-js": "^2.3.0",
     "formik": "^2.1.5",
     "heic2any": "^0.0.3",
@@ -66,10 +75,23 @@
     "@types/styled-components": "^5.1.3",
     "@types/yup": "^0.29.7",
     "babel-plugin-styled-components": "^1.11.1",
+    "eslint": "^7.27.0",
+    "eslint-config-google": "^0.14.0",
+    "eslint-plugin-react": "^7.23.2",
+    "husky": "^6.0.0",
+    "lint-staged": "^11.0.0",
     "typescript": "^4.1.3",
     "worker-plugin": "^5.0.0"
   },
   "standard": {
     "parser": "babel-eslint"
+  },
+  "lint-staged": {
+    "src/**/*.{js,jsx,ts,tsx}": "eslint"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "yarn run lint-staged"
+    }
   }
 }

+ 2 - 2
src/components/AddToCollectionBtn.tsx

@@ -27,8 +27,8 @@ export default function AddToCollectionBtn(props) {
                 strokeLinecap="round"
                 strokeLinejoin="round"
             >
-                <line x1="12" y1="5" x2="12" y2="19"></line>
-                <line x1="5" y1="12" x2="19" y2="12"></line>
+                <line x1="12" y1="5" x2="12" y2="19" />
+                <line x1="5" y1="12" x2="19" y2="12" />
             </svg>
         </Wrapper>
     );

+ 2 - 2
src/components/ArrowEast.tsx

@@ -9,8 +9,8 @@ export default function ArrowEast(props) {
             width={props.width}
             {...props}
         >
-            <rect fill="none" height="24" width="24"/>
-            <path d="M15,5l-1.41,1.41L18.17,11H2V13h16.17l-4.59,4.59L15,19l7-7L15,5z"/>
+            <rect fill="none" height="24" width="24" />
+            <path d="M15,5l-1.41,1.41L18.17,11H2V13h16.17l-4.59,4.59L15,19l7-7L15,5z" />
         </svg>
     );
 }

+ 2 - 2
src/components/CloudUpload.tsx

@@ -9,8 +9,8 @@ export default function CloudUpload(props) {
             width={props.width}
             fill="currentColor"
         >
-            <path d="M0 0h24v24H0V0z" fill="none"/>
-            <path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95C8.08 7.14 9.94 6 12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11c1.56.1 2.78 1.41 2.78 2.96 0 1.65-1.35 3-3 3zM8 13h2.55v3h2.9v-3H16l-4-4z"/>
+            <path d="M0 0h24v24H0V0z" fill="none" />
+            <path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95C8.08 7.14 9.94 6 12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11c1.56.1 2.78 1.41 2.78 2.96 0 1.65-1.35 3-3 3zM8 13h2.55v3h2.9v-3H16l-4-4z" />
         </svg>
     );
 }

+ 31 - 31
src/components/CollectionShare.tsx

@@ -1,20 +1,20 @@
-import React, { useEffect, useState } from 'react';
+import React, {useState} from 'react';
 import constants from 'utils/strings/constants';
-import MessageDialog from './MessageDialog';
-import { Formik, FormikHelpers } from 'formik';
+import {Formik, FormikHelpers} from 'formik';
 import * as Yup from 'yup';
 import Form from 'react-bootstrap/Form';
 import FormControl from 'react-bootstrap/FormControl';
-import { Button, Col, Table } from 'react-bootstrap';
-import { DeadCenter } from 'pages/gallery';
-import SubmitButton from './SubmitButton';
-import { User } from 'services/userService';
+import {Button, Col, Table} from 'react-bootstrap';
+import {DeadCenter} from 'pages/gallery';
+import {User} from 'services/userService';
 import {
     Collection,
     shareCollection,
     unshareCollection,
 } from 'services/collectionService';
-import { getData, LS_KEYS } from 'utils/storage/localStorage';
+import {getData, LS_KEYS} from 'utils/storage/localStorage';
+import SubmitButton from './SubmitButton';
+import MessageDialog from './MessageDialog';
 
 interface Props {
     show: boolean;
@@ -33,8 +33,8 @@ interface ShareeProps {
 function CollectionShare(props: Props) {
     const [loading, setLoading] = useState(false);
     const collectionShare = async (
-        { email }: formValues,
-        { resetForm, setFieldError }: FormikHelpers<formValues>
+        {email}: formValues,
+        {resetForm, setFieldError}: FormikHelpers<formValues>,
     ) => {
         try {
             setLoading(true);
@@ -53,17 +53,17 @@ function CollectionShare(props: Props) {
         } catch (e) {
             let errorMessage = null;
             switch (e?.status) {
-                case 400:
-                    errorMessage = constants.SHARING_BAD_REQUEST_ERROR;
-                    break;
-                case 402:
-                    errorMessage = constants.SHARING_DISABLED_FOR_FREE_ACCOUNTS;
-                    break;
-                case 404:
-                    errorMessage = constants.USER_DOES_NOT_EXIST;
-                    break;
-                default:
-                    errorMessage = `${constants.UNKNOWN_ERROR} ${e.message}`;
+            case 400:
+                errorMessage = constants.SHARING_BAD_REQUEST_ERROR;
+                break;
+            case 402:
+                errorMessage = constants.SHARING_DISABLED_FOR_FREE_ACCOUNTS;
+                break;
+            case 404:
+                errorMessage = constants.USER_DOES_NOT_EXIST;
+                break;
+            default:
+                errorMessage = `${constants.UNKNOWN_ERROR} ${e.message}`;
             }
             setFieldError('email', errorMessage);
         } finally {
@@ -75,7 +75,7 @@ function CollectionShare(props: Props) {
         await props.syncWithRemote();
     };
 
-    const ShareeRow = ({ sharee, collectionUnshare }: ShareeProps) => (
+    const ShareeRow = ({sharee, collectionUnshare}: ShareeProps) => (
         <tr>
             <td>{sharee.email}</td>
             <td>
@@ -91,7 +91,7 @@ function CollectionShare(props: Props) {
                     }}
                     onClick={() => collectionUnshare(sharee)}
                 >
-                    -
+                  -
                 </Button>
             </td>
         </tr>
@@ -100,12 +100,12 @@ function CollectionShare(props: Props) {
         <MessageDialog
             show={props.show}
             onHide={props.onHide}
-            attributes={{ title: constants.SHARE_COLLECTION }}
+            attributes={{title: constants.SHARE_COLLECTION}}
         >
-            <DeadCenter style={{ width: '85%', margin: 'auto' }}>
+            <DeadCenter style={{width: '85%', margin: 'auto'}}>
                 <p>{constants.SHARE_WITH_PEOPLE}</p>
                 <Formik<formValues>
-                    initialValues={{ email: '' }}
+                    initialValues={{email: ''}}
                     validationSchema={Yup.object().shape({
                         email: Yup.string()
                             .email(constants.EMAIL_ERROR)
@@ -135,9 +135,9 @@ function CollectionShare(props: Props) {
                                         value={values.email}
                                         onChange={handleChange('email')}
                                         isInvalid={Boolean(
-                                            touched.email && errors.email
+                                            touched.email && errors.email,
                                         )}
-                                        autoFocus={true}
+                                        autoFocus
                                         disabled={loading}
                                     />
                                     <FormControl.Feedback type="invalid">
@@ -152,7 +152,7 @@ function CollectionShare(props: Props) {
                                     <SubmitButton
                                         loading={loading}
                                         inline
-                                        buttonText={'+'}
+                                        buttonText="+"
                                     />
                                 </Form.Group>
                             </Form.Row>
@@ -166,7 +166,7 @@ function CollectionShare(props: Props) {
                         background: '#444',
                         width: '100%',
                     }}
-                ></div>
+                />
                 {props.collection?.sharees.length > 0 ? (
                     <>
                         <p>{constants.SHAREES}</p>
@@ -184,7 +184,7 @@ function CollectionShare(props: Props) {
                         </Table>
                     </>
                 ) : (
-                    <div style={{ marginTop: '12px' }}>
+                    <div style={{marginTop: '12px'}}>
                         {constants.ZERO_SHAREES()}
                     </div>
                 )}

+ 1 - 1
src/components/CrossIcon.tsx

@@ -8,7 +8,7 @@ export default function DateIcon(props) {
             viewBox={props.viewBox}
             width={props.width}
         >
-            <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"></path>
+            <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
         </svg>
     );
 }

+ 1 - 1
src/components/DateIcon.tsx

@@ -8,7 +8,7 @@ export default function DateIcon(props) {
             viewBox={props.viewBox}
             width={props.width}
         >
-            <path d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V10h14v10zm-4.5-7a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5z"></path>
+            <path d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V10h14v10zm-4.5-7a2.5 2.5 0 0 0 0 5 2.5 2.5 0 0 0 0-5z" />
         </svg>
     );
 }

+ 1 - 1
src/components/EnteSpinner.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import { Spinner } from 'react-bootstrap';
+import {Spinner} from 'react-bootstrap';
 
 export default function EnteSpinner(props) {
     return (

+ 2 - 3
src/components/FavButton.tsx

@@ -12,13 +12,12 @@ 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);`}
 `;
 
-export default function FavButton({ isClick, onClick, size }) {
+export default function FavButton({isClick, onClick, size}) {
     return <HeartUI isClick={isClick} onClick={onClick} size={size} />;
 }

+ 2 - 3
src/components/FullScreenDropZone.tsx

@@ -1,13 +1,12 @@
-import React, { useState } from 'react';
+import React, {useState} from 'react';
 import styled from 'styled-components';
 import constants from 'utils/strings/constants';
 
 export const getColor = (props) => {
     if (props.isDragActive) {
         return '#00e676';
-    } else {
-        return '#191919';
     }
+    return '#191919';
 };
 
 export const enableBorder = (props) => (props.isDragActive ? 'solid' : 'none');

+ 2 - 3
src/components/LocationIcon.tsx

@@ -1,5 +1,4 @@
 import React from 'react';
-import styled from 'styled-components';
 
 export default function LocationIcon(props) {
     return (
@@ -9,8 +8,8 @@ export default function LocationIcon(props) {
             viewBox={props.viewBox}
             width={props.width}
         >
-            <path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zM7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.88-2.88 7.19-5 9.88C9.92 16.21 7 11.85 7 9z"></path>
-            <circle cx="12" cy="9" r="2.5"></circle>
+            <path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zM7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.88-2.88 7.19-5 9.88C9.92 16.21 7 11.85 7 9z" />
+            <circle cx="12" cy="9" r="2.5" />
         </svg>
     );
 }

+ 5 - 5
src/components/MessageDialog.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import { Button, Modal } from 'react-bootstrap';
+import {Button, Modal} from 'react-bootstrap';
 import constants from 'utils/strings/constants';
 
 export interface MessageAttributes {
@@ -41,7 +41,7 @@ export default function MessageDialog({
             backdrop={attributes.staticBackdrop ? 'static' : 'true'}
         >
             <Modal.Header
-                style={{ borderBottom: 'none' }}
+                style={{borderBottom: 'none'}}
                 closeButton={!attributes.nonClosable}
             >
                 {attributes.title && (
@@ -51,12 +51,12 @@ export default function MessageDialog({
                 )}
             </Modal.Header>
             {(children || attributes?.content) && (
-                <Modal.Body style={{ borderTop: '1px solid #444' }}>
-                    {children ? children : <h5>{attributes.content}</h5>}
+                <Modal.Body style={{borderTop: '1px solid #444'}}>
+                    {children || <h5>{attributes.content}</h5>}
                 </Modal.Body>
             )}
             {(attributes.close || attributes.proceed) && (
-                <Modal.Footer style={{ borderTop: 'none' }}>
+                <Modal.Footer style={{borderTop: 'none'}}>
                     <div
                         style={{
                             display: 'flex',

+ 3 - 1
src/components/NavigateNext.tsx

@@ -8,8 +8,10 @@ export default function NavigateNext(props) {
             viewBox="0 0 24 24"
             width="24px"
             fill="currentColor"
+            {...props}
         >
-            <path d="M0 0h24v24H0z" fill="none"/><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
+            <path d="M0 0h24v24H0z" fill="none" />
+            <path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
         </svg>
     );
 }

+ 14 - 16
src/components/NavigationButton.tsx

@@ -1,4 +1,4 @@
-import React, { useEffect, useLayoutEffect, useState } from 'react';
+import React from 'react';
 import styled from 'styled-components';
 import NavigateNext from './NavigateNext';
 
@@ -20,11 +20,11 @@ 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;
@@ -40,23 +40,21 @@ const Wrapper = styled.button<{ direction: SCROLL_DIRECTION }>`
 
     &::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 }) => {
-    return (
-        <Wrapper
-            direction={scrollDirection}
-            {...rest}
-        >
-            <NavigateNext />
-        </Wrapper>
-    );
-};
+const NavigationButton = ({scrollDirection, ...rest}: Props) => (
+    <Wrapper
+        direction={scrollDirection}
+        {...rest}
+    >
+        <NavigateNext />
+    </Wrapper>
+);
 export default NavigationButton;

+ 111 - 125
src/components/PhotoFrame.tsx

@@ -7,17 +7,17 @@ import {
     setSearchStats,
 } from 'pages/gallery';
 import PreviewCard from 'pages/gallery/components/PreviewCard';
-import React, { useEffect, useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { File } from 'services/fileService';
+import React, {useEffect, useState} from 'react';
+import {Button} from 'react-bootstrap';
+import {File} from 'services/fileService';
 import styled from 'styled-components';
 import DownloadManager from 'services/downloadManager';
 import constants from 'utils/strings/constants';
 import AutoSizer from 'react-virtualized-auto-sizer';
-import { VariableSizeList as List } from 'react-window';
+import {VariableSizeList as List} from 'react-window';
 import PhotoSwipe from 'components/PhotoSwipe/PhotoSwipe';
+import {isInsideBox, isSameDay as isSameDayAnyYear} from 'utils/search';
 import CloudUpload from './CloudUpload';
-import { isInsideBox, isSameDay as isSameDayAnyYear } from 'utils/search';
 
 const DATE_CONTAINER_HEIGHT = 45;
 const IMAGE_CONTAINER_HEIGHT = 200;
@@ -205,20 +205,18 @@ const PhotoFrame = ({
             count: checked ? selected.count + 1 : selected.count - 1,
         }));
     };
-    const getThumbnail = (file: File[], index: number) => {
-        return (
-            <PreviewCard
-                key={`tile-${file[index].id}`}
-                file={file[index]}
-                updateUrl={updateUrl(file[index].dataIndex)}
-                onClick={onThumbnailClick(index)}
-                selectable
-                onSelect={handleSelect(file[index].id)}
-                selected={selected[file[index].id]}
-                selectOnClick={selected.count > 0}
-            />
-        );
-    };
+    const getThumbnail = (file: File[], index: number) => (
+        <PreviewCard
+            key={`tile-${file[index].id}`}
+            file={file[index]}
+            updateUrl={updateUrl(file[index].dataIndex)}
+            onClick={onThumbnailClick(index)}
+            selectable
+            onSelect={handleSelect(file[index].id)}
+            selected={selected[file[index].id]}
+            selectOnClick={selected.count > 0}
+        />
+    );
 
     const getSlideData = async (instance: any, index: number, item: File) => {
         if (!item.msrc) {
@@ -263,7 +261,7 @@ const PhotoFrame = ({
         }
     };
 
-    let idSet = new Set();
+    const idSet = new Set();
     const filteredData = files
         .map((item, index) => ({
             ...item,
@@ -273,7 +271,7 @@ const PhotoFrame = ({
             if (
                 search.date &&
                 !isSameDayAnyYear(search.date)(
-                    new Date(item.metadata.creationTime / 1000)
+                    new Date(item.metadata.creationTime / 1000),
                 )
             ) {
                 return false;
@@ -297,17 +295,15 @@ const PhotoFrame = ({
             return false;
         });
 
-    const isSameDay = (first, second) => {
-        return (
-            first.getFullYear() === second.getFullYear() &&
+    const isSameDay = (first, second) => (
+        first.getFullYear() === second.getFullYear() &&
             first.getMonth() === second.getMonth() &&
             first.getDate() === second.getDate()
-        );
-    };
+    );
 
     return (
         <>
-            {!isFirstLoad && files.length == 0 && !searchMode ? (
+            {!isFirstLoad && files.length === 0 && !searchMode ? (
                 <EmptyScreen>
                     <CloudUpload width={150} height={150} />
                     <Button
@@ -326,7 +322,7 @@ const PhotoFrame = ({
             ) : filteredData.length ? (
                 <Container>
                     <AutoSizer>
-                        {({ height, width }) => {
+                        {({height, width}) => {
                             let columns;
                             if (width >= 1000) {
                                 columns = 5;
@@ -345,35 +341,33 @@ const PhotoFrame = ({
                                 if (
                                     !isSameDay(
                                         new Date(
-                                            item.metadata.creationTime / 1000
+                                            item.metadata.creationTime / 1000,
                                         ),
-                                        new Date(currentDate)
+                                        new Date(currentDate),
                                     )
                                 ) {
-                                    currentDate =
-                                        item.metadata.creationTime / 1000;
-                                    const dateTimeFormat =
-                                        new Intl.DateTimeFormat('en-IN', {
-                                            weekday: 'short',
-                                            year: 'numeric',
-                                            month: 'long',
-                                            day: 'numeric',
-                                        });
+                                    currentDate = item.metadata.creationTime / 1000;
+                                    const dateTimeFormat = new Intl.DateTimeFormat('en-IN', {
+                                        weekday: 'short',
+                                        year: 'numeric',
+                                        month: 'long',
+                                        day: 'numeric',
+                                    });
                                     timeStampList.push({
                                         itemType: ITEM_TYPE.TIME,
                                         date: isSameDay(
                                             new Date(currentDate),
-                                            new Date()
-                                        )
-                                            ? 'Today'
-                                            : isSameDay(
-                                                  new Date(currentDate),
-                                                  new Date(Date.now() - A_DAY)
-                                              )
-                                            ? 'Yesterday'
-                                            : dateTimeFormat.format(
-                                                  currentDate
-                                              ),
+                                            new Date(),
+                                        ) ?
+                                            'Today' :
+                                            isSameDay(
+                                                new Date(currentDate),
+                                                new Date(Date.now() - A_DAY),
+                                            ) ?
+                                                'Yesterday' :
+                                                dateTimeFormat.format(
+                                                    currentDate,
+                                                ),
                                     });
                                     timeStampList.push({
                                         itemType: ITEM_TYPE.TILE,
@@ -381,20 +375,18 @@ const PhotoFrame = ({
                                         itemStartIndex: index,
                                     });
                                     listItemIndex = 1;
+                                } else if (listItemIndex < columns) {
+                                    timeStampList[
+                                        timeStampList.length - 1
+                                    ].items.push(item);
+                                    listItemIndex++;
                                 } else {
-                                    if (listItemIndex < columns) {
-                                        timeStampList[
-                                            timeStampList.length - 1
-                                        ].items.push(item);
-                                        listItemIndex++;
-                                    } else {
-                                        listItemIndex = 1;
-                                        timeStampList.push({
-                                            itemType: ITEM_TYPE.TILE,
-                                            items: [item],
-                                            itemStartIndex: index,
-                                        });
-                                    }
+                                    listItemIndex = 1;
+                                    timeStampList.push({
+                                        itemType: ITEM_TYPE.TILE,
+                                        items: [item],
+                                        itemStartIndex: index,
+                                    });
                                 }
                             });
                             files.length < 30 &&
@@ -416,58 +408,55 @@ const PhotoFrame = ({
                                     ),
                                 });
                             const extraRowsToRender = Math.ceil(
-                                (NO_OF_PAGES * height) / IMAGE_CONTAINER_HEIGHT
+                                (NO_OF_PAGES * height) / IMAGE_CONTAINER_HEIGHT,
                             );
                             return (
                                 <List
-                                    itemSize={(index) =>
-                                        timeStampList[index].itemType ===
-                                        ITEM_TYPE.TILE
-                                            ? IMAGE_CONTAINER_HEIGHT
-                                            : DATE_CONTAINER_HEIGHT
-                                    }
+                                    itemSize={(index) => (timeStampList[index].itemType ===
+                                        ITEM_TYPE.TILE ?
+                                        IMAGE_CONTAINER_HEIGHT :
+                                        DATE_CONTAINER_HEIGHT)}
                                     height={height}
                                     width={width}
                                     itemCount={timeStampList.length}
                                     key={`${router.query.collection}-${columns}-${sinceTime}`}
                                     overscanCount={extraRowsToRender}
                                 >
-                                    {({ index, style }) => {
-                                        return (
-                                            <ListItem
-                                                style={
+                                    {({index, style}) => (
+                                        <ListItem
+                                            style={
+                                                timeStampList[index]
+                                                    .itemType ===
+                                                    ITEM_TYPE.BANNER ?
+                                                    {
+                                                        ...style,
+                                                        top: Math.max(
+                                                            Number(
+                                                                style.top,
+                                                            ),
+                                                            height - 45,
+                                                        ),
+                                                        height:
+                                                                  width < 450 ?
+                                                                      Number(
+                                                                          style.height,
+                                                                      ) * 2 :
+                                                                      style.height,
+                                                    } :
+                                                    style
+                                            }
+                                        >
+                                            <ListContainer
+                                                columns={
                                                     timeStampList[index]
                                                         .itemType ===
-                                                    ITEM_TYPE.BANNER
-                                                        ? {
-                                                              ...style,
-                                                              top: Math.max(
-                                                                  Number(
-                                                                      style.top
-                                                                  ),
-                                                                  height - 45
-                                                              ),
-                                                              height:
-                                                                  width < 450
-                                                                      ? Number(
-                                                                            style.height
-                                                                        ) * 2
-                                                                      : style.height,
-                                                          }
-                                                        : style
+                                                        ITEM_TYPE.TILE ?
+                                                        columns :
+                                                        1
                                                 }
                                             >
-                                                <ListContainer
-                                                    columns={
-                                                        timeStampList[index]
-                                                            .itemType ===
-                                                        ITEM_TYPE.TILE
-                                                            ? columns
-                                                            : 1
-                                                    }
-                                                >
-                                                    {timeStampList[index]
-                                                        .itemType ===
+                                                {timeStampList[index]
+                                                    .itemType ===
                                                     ITEM_TYPE.TIME ? (
                                                         <DateContainer>
                                                             {
@@ -477,35 +466,32 @@ const PhotoFrame = ({
                                                             }
                                                         </DateContainer>
                                                     ) : timeStampList[index]
-                                                          .itemType ===
+                                                        .itemType ===
                                                       ITEM_TYPE.BANNER ? (
-                                                        <>
-                                                            {
-                                                                timeStampList[
-                                                                    index
-                                                                ].banner
-                                                            }
-                                                        </>
-                                                    ) : (
-                                                        timeStampList[
-                                                            index
-                                                        ].items.map(
-                                                            (item, idx) => {
-                                                                return getThumbnail(
+                                                            <>
+                                                                {
+                                                                    timeStampList[
+                                                                        index
+                                                                    ].banner
+                                                                }
+                                                            </>
+                                                        ) : (
+                                                            timeStampList[
+                                                                index
+                                                            ].items.map(
+                                                                (item, idx) => getThumbnail(
                                                                     filteredData,
                                                                     timeStampList[
                                                                         index
                                                                     ]
                                                                         .itemStartIndex +
-                                                                        idx
-                                                                );
-                                                            }
-                                                        )
-                                                    )}
-                                                </ListContainer>
-                                            </ListItem>
-                                        );
-                                    }}
+                                                                        idx,
+                                                                ),
+                                                            )
+                                                        )}
+                                            </ListContainer>
+                                        </ListItem>
+                                    )}
                                 </List>
                             );
                         }}

+ 23 - 33
src/components/PhotoSwipe/PhotoSwipe.tsx

@@ -1,16 +1,16 @@
-import React, { useEffect, useRef, useState } from 'react';
+import React, {useEffect, useRef, useState} from 'react';
 import Photoswipe from 'photoswipe';
 import PhotoswipeUIDefault from 'photoswipe/dist/photoswipe-ui-default';
 import classnames from 'classnames';
-import events from './events';
 import FavButton from 'components/FavButton';
 import {
     addToFavorites,
     removeFromFavorites,
 } from 'services/collectionService';
-import { File } from 'services/fileService';
+import {File} from 'services/fileService';
 import constants from 'utils/strings/constants';
 import DownloadManger from 'services/downloadManager';
+import events from './events';
 
 interface Iprops {
     isOpen: boolean;
@@ -28,7 +28,7 @@ function PhotoSwipe(props: Iprops) {
     let pswpElement;
     const [photoSwipe, setPhotoSwipe] = useState<Photoswipe<any>>();
 
-    const { isOpen } = props;
+    const {isOpen} = props;
     const [isFav, setIsFav] = useState(false);
     const needUpdate = useRef(false);
 
@@ -59,32 +59,31 @@ function PhotoSwipe(props: Iprops) {
     }
 
     const openPhotoSwipe = () => {
-        const { items, currentIndex } = props;
+        const {items, currentIndex} = props;
         const options = {
             history: false,
             maxSpreadZoom: 5,
             index: currentIndex,
             showHideOpacity: true,
-            getDoubleTapZoom: function(isMouseClick, item) {
-                if(isMouseClick) {
+            getDoubleTapZoom(isMouseClick, item) {
+                if (isMouseClick) {
                     return 2.5;
-                } else {
-                    // zoom to original if initial zoom is less than 0.7x,
-                    // otherwise to 1.5x, to make sure that double-tap gesture always zooms image
-                    return item.initialZoomLevel < 0.7 ? 1 : 1.5;
                 }
+                // zoom to original if initial zoom is less than 0.7x,
+                // otherwise to 1.5x, to make sure that double-tap gesture always zooms image
+                return item.initialZoomLevel < 0.7 ? 1 : 1.5;
             },
         };
-        let photoSwipe = new Photoswipe(
+        const photoSwipe = new Photoswipe(
             pswpElement,
             PhotoswipeUIDefault,
             items,
-            options
+            options,
         );
         events.forEach((event) => {
             const callback = props[event];
             if (callback || event === 'destroy') {
-                photoSwipe.listen(event, function (...args) {
+                photoSwipe.listen(event, function(...args) {
                     if (callback) {
                         args.unshift(this);
                         callback(...args);
@@ -101,38 +100,29 @@ function PhotoSwipe(props: Iprops) {
         setPhotoSwipe(photoSwipe);
     };
 
-    const updateItems = (items = []) => {
-        photoSwipe.items = [];
-        items.forEach((item) => {
-            photoSwipe.items.push(item);
-        });
-        photoSwipe.invalidateCurrItems();
-        photoSwipe.updateSize(true);
-    };
-
     const closePhotoSwipe = () => {
         if (photoSwipe) photoSwipe.close();
     };
 
     const handleClose = () => {
-        const { onClose } = props;
+        const {onClose} = props;
         if (typeof onClose === 'function') {
             onClose(needUpdate.current);
         }
-        var videoTags = document.getElementsByTagName('video');
-        for (var videoTag of videoTags) {
+        const videoTags = document.getElementsByTagName('video');
+        for (const videoTag of videoTags) {
             videoTag.pause();
         }
     };
     const isInFav = (file) => {
-        const { favItemIds } = props;
+        const {favItemIds} = props;
         if (favItemIds && file) {
             return favItemIds.has(file.id);
-        } else return false;
+        } return false;
     };
 
     const onFavClick = async (file) => {
-        const { favItemIds } = props;
+        const {favItemIds} = props;
         if (!isInFav(file)) {
             favItemIds.add(file.id);
             addToFavorites(file);
@@ -145,19 +135,19 @@ function PhotoSwipe(props: Iprops) {
         needUpdate.current = true;
     };
     const downloadFile = async (file) => {
-        const { loadingBar } = props;
+        const {loadingBar} = props;
         const a = document.createElement('a');
         a.style.display = 'none';
         loadingBar.current.continuousStart();
         a.href = await DownloadManger.getFile(file);
         loadingBar.current.complete();
-        a.download = file.metadata['title'];
+        a.download = file.metadata.title;
         document.body.appendChild(a);
         a.click();
         a.remove();
     };
-    const { id } = props;
-    let { className } = props;
+    const {id} = props;
+    let {className} = props;
     className = classnames(['pswp', className]).trim();
     return (
         <div

+ 4 - 5
src/components/RecoveryKeyModal.tsx

@@ -1,7 +1,6 @@
-import React, { useEffect, useState } from 'react';
-import { downloadAsFile } from 'utils/file';
-import { getRecoveryKey } from 'utils/crypto';
-import { setJustSignedUp } from 'utils/storage';
+import React, {useEffect, useState} from 'react';
+import {downloadAsFile} from 'utils/file';
+import {getRecoveryKey} from 'utils/crypto';
 import constants from 'utils/strings/constants';
 import MessageDialog from './MessageDialog';
 import EnteSpinner from './EnteSpinner';
@@ -11,7 +10,7 @@ interface Props {
     onHide: () => void;
     somethingWentWrong: any;
 }
-function RecoveryKeyModal({ somethingWentWrong, ...props }: Props) {
+function RecoveryKeyModal({somethingWentWrong, ...props}: Props) {
     const [recoveryKey, setRecoveryKey] = useState(null);
     useEffect(() => {
         if (!props.show) {

+ 46 - 53
src/components/SearchBar.tsx

@@ -1,10 +1,10 @@
-import { Search, SearchStats, SetCollections } from 'pages/gallery';
-import React, { useEffect, useState, useRef } from 'react';
+import {Search, SearchStats, SetCollections} from 'pages/gallery';
+import React, {useEffect, useState, useRef} from 'react';
 import styled from 'styled-components';
 import AsyncSelect from 'react-select/async';
-import { components } from 'react-select';
+import {components} from 'react-select';
 import debounce from 'debounce-promise';
-import { File } from 'services/fileService';
+import {File} from 'services/fileService';
 import {
     Bbox,
     getHolidaySuggestion,
@@ -12,7 +12,7 @@ import {
     parseHumanDate,
     searchLocation,
 } from 'services/searchService';
-import { getFormattedDate } from 'utils/search';
+import {getFormattedDate} from 'utils/search';
 import constants from 'utils/strings/constants';
 import LocationIcon from './LocationIcon';
 import DateIcon from './DateIcon';
@@ -97,19 +97,17 @@ export default function SearchBar(props: Props) {
     }, [props.isOpen]);
 
     useEffect(() => {
-        window.addEventListener('resize', () =>
-            setWindowWidth(window.innerWidth)
-        );
+        window.addEventListener('resize', () => setWindowWidth(window.innerWidth));
     });
-    //==========================
+    // = =========================
     // Functionality
-    //==========================
+    // = =========================
     const getAutoCompleteSuggestions = async (searchPhrase: string) => {
         searchPhrase = searchPhrase.trim();
         if (!searchPhrase?.length) {
             return [];
         }
-        let option = [
+        const option = [
             ...getHolidaySuggestion(searchPhrase),
             ...getYearSuggestion(searchPhrase),
         ];
@@ -121,19 +119,18 @@ export default function SearchBar(props: Props) {
                 type: SuggestionType.DATE,
                 value: searchedDate,
                 label: getFormattedDate(searchedDate),
-            }))
+            })),
         );
 
         const searchResults = await searchLocation(searchPhrase);
         option.push(
             ...searchResults.map(
-                (searchResult) =>
-                    ({
-                        type: SuggestionType.LOCATION,
-                        value: searchResult.bbox,
-                        label: searchResult.place,
-                    } as Suggestion)
-            )
+                (searchResult) => ({
+                    type: SuggestionType.LOCATION,
+                    value: searchResult.bbox,
+                    label: searchResult.place,
+                } as Suggestion),
+            ),
         );
         return option;
     };
@@ -148,19 +145,16 @@ export default function SearchBar(props: Props) {
         props.setOpen(true);
 
         switch (selectedOption.type) {
-            case SuggestionType.DATE:
-                const searchedDate = selectedOption.value as DateValue;
-
-                props.setSearch({
-                    date: searchedDate,
-                });
-                break;
-            case SuggestionType.LOCATION:
-                const bbox = selectedOption.value as Bbox;
-                props.setSearch({
-                    location: bbox,
-                });
-                break;
+        case SuggestionType.DATE:
+            props.setSearch({
+                date: selectedOption.value as DateValue,
+            });
+            break;
+        case SuggestionType.LOCATION:
+            props.setSearch({
+                location: selectedOption.value as Bbox,
+            });
+            break;
         }
     };
     const resetSearch = () => {
@@ -176,22 +170,21 @@ export default function SearchBar(props: Props) {
         }
     };
 
-    //==========================
+    // = =========================
     // UI
-    //==========================
+    // = =========================
 
-    const getIconByType = (type: SuggestionType) =>
-        type === SuggestionType.DATE ? <DateIcon /> : <LocationIcon />;
+    const getIconByType = (type: SuggestionType) => (type === SuggestionType.DATE ? <DateIcon /> : <LocationIcon />);
 
     const LabelWithIcon = (props: { type: SuggestionType; label: string }) => (
-        <div style={{ display: 'flex', alignItems: 'center' }}>
-            <span style={{ paddingRight: '10px', paddingBottom: '4px' }}>
+        <div style={{display: 'flex', alignItems: 'center'}}>
+            <span style={{paddingRight: '10px', paddingBottom: '4px'}}>
                 {getIconByType(props.type)}
             </span>
             <span>{props.label}</span>
         </div>
     );
-    const { Option, Control } = components;
+    const {Option, Control} = components;
 
     const OptionWithIcon = (props) => (
         <Option {...props}>
@@ -201,15 +194,15 @@ export default function SearchBar(props: Props) {
     const ControlWithIcon = (props) => (
         <Control {...props}>
             <span
-                className={'icon'}
+                className="icon"
                 style={{
                     paddingLeft: '10px',
                     paddingBottom: '4px',
                 }}
             >
-                {props.getValue().length == 0 || props.menuIsOpen ? (
+                {props.getValue().length === 0 || props.menuIsOpen ? (
                     <SearchIcon />
-                ) : props.getValue()[0].type == SuggestionType.DATE ? (
+                ) : props.getValue()[0].type === SuggestionType.DATE ? (
                     <DateIcon />
                 ) : (
                     <LocationIcon />
@@ -220,16 +213,16 @@ export default function SearchBar(props: Props) {
     );
 
     const customStyles = {
-        control: (style, { isFocused }) => ({
+        control: (style, {isFocused}) => ({
             ...style,
-            backgroundColor: '#282828',
-            color: '#d1d1d1',
-            borderColor: isFocused ? '#2dc262' : '#444',
-            boxShadow: 'none',
+            'backgroundColor': '#282828',
+            'color': '#d1d1d1',
+            'borderColor': isFocused ? '#2dc262' : '#444',
+            'boxShadow': 'none',
             ':hover': {
-                borderColor: '#2dc262',
-                cursor: 'text',
-                '&>.icon': { color: '#2dc262' },
+                'borderColor': '#2dc262',
+                'cursor': 'text',
+                '&>.icon': {color: '#2dc262'},
             },
         }),
         input: (style) => ({
@@ -241,7 +234,7 @@ export default function SearchBar(props: Props) {
             marginTop: '10px',
             backgroundColor: '#282828',
         }),
-        option: (style, { isFocused }) => ({
+        option: (style, {isFocused}) => ({
             ...style,
             backgroundColor: isFocused && '#343434',
         }),
@@ -300,10 +293,10 @@ export default function SearchBar(props: Props) {
                             noOptionsMessage={() => null}
                         />
                     </div>
-                    <div style={{ width: '24px' }}>
+                    <div style={{width: '24px'}}>
                         {props.isOpen && (
                             <div
-                                style={{ cursor: 'pointer' }}
+                                style={{cursor: 'pointer'}}
                                 onClick={resetSearch}
                             >
                                 <CrossIcon />

+ 1 - 1
src/components/SearchIcon.tsx

@@ -8,7 +8,7 @@ export default function SearchIcon(props) {
             viewBox={props.viewBox}
             width={props.width}
         >
-            <path d="M20.49 19l-5.73-5.73C15.53 12.2 16 10.91 16 9.5A6.5 6.5 0 1 0 9.5 16c1.41 0 2.7-.47 3.77-1.24L19 20.49 20.49 19zM5 9.5C5 7.01 7.01 5 9.5 5S14 7.01 14 9.5 11.99 14 9.5 14 5 11.99 5 9.5z"></path>
+            <path d="M20.49 19l-5.73-5.73C15.53 12.2 16 10.91 16 9.5A6.5 6.5 0 1 0 9.5 16c1.41 0 2.7-.47 3.77-1.24L19 20.49 20.49 19zM5 9.5C5 7.01 7.01 5 9.5 5S14 7.01 14 9.5 11.99 14 9.5 14 5 11.99 5 9.5z" />
         </svg>
     );
 }

+ 13 - 13
src/components/SetPasswordForm.tsx

@@ -1,9 +1,9 @@
-import React, { useState } from 'react';
+import React, {useState} from 'react';
 import Container from 'components/Container';
 import Card from 'react-bootstrap/Card';
 import Form from 'react-bootstrap/Form';
 import constants from 'utils/strings/constants';
-import { Formik, FormikHelpers } from 'formik';
+import {Formik, FormikHelpers} from 'formik';
 import * as Yup from 'yup';
 import Button from 'react-bootstrap/Button';
 import SubmitButton from './SubmitButton';
@@ -21,11 +21,11 @@ function SetPasswordForm(props: Props) {
     const [loading, setLoading] = useState(false);
     const onSubmit = async (
         values: formValues,
-        { setFieldError }: FormikHelpers<formValues>
+        {setFieldError}: FormikHelpers<formValues>,
     ) => {
         setLoading(true);
         try {
-            const { passphrase, confirm } = values;
+            const {passphrase, confirm} = values;
             if (passphrase === confirm) {
                 await props.callback(passphrase, setFieldError);
             } else {
@@ -34,7 +34,7 @@ function SetPasswordForm(props: Props) {
         } catch (e) {
             setFieldError(
                 'passphrase',
-                `${constants.UNKNOWN_ERROR} ${e.message}`
+                `${constants.UNKNOWN_ERROR} ${e.message}`,
             );
         } finally {
             setLoading(false);
@@ -42,20 +42,20 @@ function SetPasswordForm(props: Props) {
     };
     return (
         <Container>
-            <Card style={{ maxWidth: '540px', padding: '20px' }}>
+            <Card style={{maxWidth: '540px', padding: '20px'}}>
                 <Card.Body>
                     <div
                         className="text-center"
-                        style={{ marginBottom: '40px' }}
+                        style={{marginBottom: '40px'}}
                     >
                         <p>{constants.ENTER_ENC_PASSPHRASE}</p>
                         {constants.PASSPHRASE_DISCLAIMER()}
                     </div>
                     <Formik<formValues>
-                        initialValues={{ passphrase: '', confirm: '' }}
+                        initialValues={{passphrase: '', confirm: ''}}
                         validationSchema={Yup.object().shape({
                             passphrase: Yup.string().required(
-                                constants.REQUIRED
+                                constants.REQUIRED,
                             ),
                             confirm: Yup.string().required(constants.REQUIRED),
                         })}
@@ -79,9 +79,9 @@ function SetPasswordForm(props: Props) {
                                         onChange={handleChange('passphrase')}
                                         isInvalid={Boolean(
                                             touched.passphrase &&
-                                                errors.passphrase
+                                                errors.passphrase,
                                         )}
-                                        autoFocus={true}
+                                        autoFocus
                                         disabled={loading}
                                     />
                                     <Form.Control.Feedback type="invalid">
@@ -97,7 +97,7 @@ function SetPasswordForm(props: Props) {
                                         value={values.confirm}
                                         onChange={handleChange('confirm')}
                                         isInvalid={Boolean(
-                                            touched.confirm && errors.confirm
+                                            touched.confirm && errors.confirm,
                                         )}
                                         disabled={loading}
                                     />
@@ -115,7 +115,7 @@ function SetPasswordForm(props: Props) {
                     {props.back && (
                         <div
                             className="text-center"
-                            style={{ marginTop: '20px' }}
+                            style={{marginTop: '20px'}}
                         >
                             <Button variant="link" onClick={props.back}>
                                 {constants.GO_BACK}

+ 60 - 66
src/components/Sidebar.tsx

@@ -1,12 +1,12 @@
-import React, { useEffect, useState } from 'react';
+import React, {useEffect, useState} from 'react';
 
-import { slide as Menu } from 'react-burger-menu';
-import billingService, { Subscription } from 'services/billingService';
+import {slide as Menu} from 'react-burger-menu';
+import billingService, {Subscription} from 'services/billingService';
 import constants from 'utils/strings/constants';
-import { getData, LS_KEYS, setData } from 'utils/storage/localStorage';
-import { getToken } from 'utils/common/key';
-import { getEndpoint } from 'utils/common/apiUtil';
-import { Button } from 'react-bootstrap';
+import {getData, LS_KEYS, setData} from 'utils/storage/localStorage';
+import {getToken} from 'utils/common/key';
+import {getEndpoint} from 'utils/common/apiUtil';
+import {Button} from 'react-bootstrap';
 import {
     isSubscriptionActive,
     convertBytesToGBs,
@@ -17,17 +17,17 @@ import {
 } from 'utils/billingUtil';
 
 import exportService from 'services/exportService';
-import { File } from 'services/fileService';
+import {File} from 'services/fileService';
 import isElectron from 'is-electron';
-import { Collection } from 'services/collectionService';
-import { useRouter } from 'next/router';
-import RecoveryKeyModal from './RecoveryKeyModal';
-import EnteSpinner from './EnteSpinner';
+import {Collection} from 'services/collectionService';
+import {useRouter} from 'next/router';
 import LinkButton from 'pages/gallery/components/LinkButton';
-import { downloadApp } from 'utils/common';
-import { logoutUser } from 'services/userService';
-import { SetDialogMessage } from './MessageDialog';
-import { LogoImage } from 'pages/_app';
+import {downloadApp} from 'utils/common';
+import {logoutUser} from 'services/userService';
+import {LogoImage} from 'pages/_app';
+import {SetDialogMessage} from './MessageDialog';
+import EnteSpinner from './EnteSpinner';
+import RecoveryKeyModal from './RecoveryKeyModal';
 
 interface Props {
     files: File[];
@@ -45,7 +45,6 @@ export default function Sidebar(props: Props) {
     }, []);
     const [isOpen, setIsOpen] = useState(false);
     const [recoverModalView, setRecoveryModalView] = useState(false);
-    const [accountDeleteModalView, setAccountDeleteModalView] = useState(false);
     useEffect(() => {
         const main = async () => {
             if (!isOpen) {
@@ -60,13 +59,12 @@ export default function Sidebar(props: Props) {
     }, [isOpen]);
 
     function openFeedbackURL() {
-        const feedbackURL: string =
-            getEndpoint() + '/users/feedback?token=' + getToken();
-        var win = window.open(feedbackURL, '_blank');
+        const feedbackURL: string = `${getEndpoint()}/users/feedback?token=${getToken()}`;
+        const win = window.open(feedbackURL, '_blank');
         win.focus();
     }
     function openSupportMail() {
-        var a = document.createElement('a');
+        const a = document.createElement('a');
         a.href = 'mailto:contact@ente.io';
         a.target = '_blank';
         a.rel = 'noreferrer noopener';
@@ -103,9 +101,9 @@ export default function Sidebar(props: Props) {
             onStateChange={(state) => setIsOpen(state.isOpen)}
             itemListElement="div"
         >
-            <div style={{ display: 'flex', textAlign: 'center' }}>
+            <div style={{display: 'flex', textAlign: 'center'}}>
                 <LogoImage
-                    style={{ height: '24px', padding: '3px' }}
+                    style={{height: '24px', padding: '3px'}}
                     alt="logo"
                     src="/icon.svg"
                 />
@@ -119,26 +117,26 @@ export default function Sidebar(props: Props) {
             >
                 {user?.email}
             </div>
-            <div style={{ flex: 1, overflow: 'auto', paddingTop: '0' }}>
-                <div style={{ outline: 'none' }}>
-                    <div style={{ display: 'flex' }}>
-                        <h5 style={{ margin: '4px 0 12px 2px' }}>
+            <div style={{flex: 1, overflow: 'auto', paddingTop: '0'}}>
+                <div style={{outline: 'none'}}>
+                    <div style={{display: 'flex'}}>
+                        <h5 style={{margin: '4px 0 12px 2px'}}>
                             {constants.SUBSCRIPTION_PLAN}
                         </h5>
                     </div>
-                    <div style={{ color: '#959595' }}>
+                    <div style={{color: '#959595'}}>
                         {isSubscriptionActive(subscription) ? (
                             isOnFreePlan(subscription) ? (
                                 constants.FREE_SUBSCRIPTION_INFO(
-                                    subscription?.expiryTime
+                                    subscription?.expiryTime,
                                 )
                             ) : isSubscriptionCancelled(subscription) ? (
                                 constants.RENEWAL_CANCELLED_SUBSCRIPTION_INFO(
-                                    subscription?.expiryTime
+                                    subscription?.expiryTime,
                                 )
                             ) : (
                                 constants.RENEWAL_ACTIVE_SUBSCRIPTION_INFO(
-                                    subscription?.expiryTime
+                                    subscription?.expiryTime,
                                 )
                             )
                         ) : (
@@ -150,25 +148,25 @@ export default function Sidebar(props: Props) {
                             size="sm"
                             onClick={onManageClick}
                         >
-                            {isSubscribed(subscription)
-                                ? constants.MANAGE
-                                : constants.SUBSCRIBE}
+                            {isSubscribed(subscription) ?
+                                constants.MANAGE :
+                                constants.SUBSCRIBE}
                         </Button>
                     </div>
                 </div>
-                <div style={{ outline: 'none', marginTop: '30px' }}></div>
+                <div style={{outline: 'none', marginTop: '30px'}} />
                 <div>
-                    <h5 style={{ marginBottom: '12px' }}>
+                    <h5 style={{marginBottom: '12px'}}>
                         {constants.USAGE_DETAILS}
                     </h5>
-                    <div style={{ color: '#959595' }}>
+                    <div style={{color: '#959595'}}>
                         {usage ? (
                             constants.USAGE_INFO(
                                 usage,
-                                Number(convertBytesToGBs(subscription?.storage))
+                                Number(convertBytesToGBs(subscription?.storage)),
                             )
                         ) : (
-                            <div style={{ textAlign: 'center' }}>
+                            <div style={{textAlign: 'center'}}>
                                 <EnteSpinner
                                     style={{
                                         borderWidth: '2px',
@@ -189,13 +187,13 @@ export default function Sidebar(props: Props) {
                     }}
                 />
                 <LinkButton
-                    style={{ marginTop: '30px' }}
+                    style={{marginTop: '30px'}}
                     onClick={openFeedbackURL}
                 >
                     {constants.REQUEST_FEATURE}
                 </LinkButton>
                 <LinkButton
-                    style={{ marginTop: '30px' }}
+                    style={{marginTop: '30px'}}
                     onClick={openSupportMail}
                 >
                     {constants.SUPPORT}
@@ -204,30 +202,28 @@ export default function Sidebar(props: Props) {
                     <RecoveryKeyModal
                         show={recoverModalView}
                         onHide={() => setRecoveryModalView(false)}
-                        somethingWentWrong={() =>
-                            props.setDialogMessage({
-                                title: constants.RECOVER_KEY_GENERATION_FAILED,
-                                close: { variant: 'danger' },
-                            })
-                        }
+                        somethingWentWrong={() => props.setDialogMessage({
+                            title: constants.RECOVER_KEY_GENERATION_FAILED,
+                            close: {variant: 'danger'},
+                        })}
                     />
                     <LinkButton
-                        style={{ marginTop: '30px' }}
+                        style={{marginTop: '30px'}}
                         onClick={() => setRecoveryModalView(true)}
                     >
                         {constants.DOWNLOAD_RECOVERY_KEY}
                     </LinkButton>
                 </>
                 <LinkButton
-                    style={{ marginTop: '30px' }}
+                    style={{marginTop: '30px'}}
                     onClick={() => {
-                        setData(LS_KEYS.SHOW_BACK_BUTTON, { value: true });
+                        setData(LS_KEYS.SHOW_BACK_BUTTON, {value: true});
                         router.push('changePassword');
                     }}
                 >
                     {constants.CHANGE_PASSWORD}
                 </LinkButton>
-                <LinkButton style={{ marginTop: '30px' }} onClick={exportFiles}>
+                <LinkButton style={{marginTop: '30px'}} onClick={exportFiles}>
                     {constants.EXPORT}
                 </LinkButton>
                 <div
@@ -240,22 +236,20 @@ export default function Sidebar(props: Props) {
                 />
                 <LinkButton
                     variant="danger"
-                    style={{ marginTop: '30px' }}
-                    onClick={() =>
-                        props.setDialogMessage({
-                            title: `${constants.CONFIRM} ${constants.LOGOUT}`,
-                            content: constants.LOGOUT_MESSAGE,
-                            staticBackdrop: true,
-                            proceed: {
-                                text: constants.LOGOUT,
-                                action: logoutUser,
-                                variant: 'danger',
-                            },
-                            close: { text: constants.CANCEL },
-                        })
-                    }
+                    style={{marginTop: '30px'}}
+                    onClick={() => props.setDialogMessage({
+                        title: `${constants.CONFIRM} ${constants.LOGOUT}`,
+                        content: constants.LOGOUT_MESSAGE,
+                        staticBackdrop: true,
+                        proceed: {
+                            text: constants.LOGOUT,
+                            action: logoutUser,
+                            variant: 'danger',
+                        },
+                        close: {text: constants.CANCEL},
+                    })}
                 >
-                    logout
+                  logout
                 </LinkButton>
                 <div
                     style={{

+ 10 - 8
src/components/SingleInputForm.tsx

@@ -1,7 +1,7 @@
-import React, { useState } from 'react';
+import React, {useState} from 'react';
 import constants from 'utils/strings/constants';
-import { Form } from 'react-bootstrap';
-import { Formik, FormikHelpers } from 'formik';
+import {Form} from 'react-bootstrap';
+import {Formik, FormikHelpers} from 'formik';
 import * as Yup from 'yup';
 import SubmitButton from './SubmitButton';
 
@@ -19,7 +19,7 @@ export default function SingleInputForm(props: Props) {
     const [loading, SetLoading] = useState(false);
     const submitForm = async (
         values: formValues,
-        { setFieldError }: FormikHelpers<formValues>
+        {setFieldError}: FormikHelpers<formValues>,
     ) => {
         SetLoading(true);
         await props.callback(values.passphrase, setFieldError);
@@ -27,7 +27,7 @@ export default function SingleInputForm(props: Props) {
     };
     return (
         <Formik<formValues>
-            initialValues={{ passphrase: '' }}
+            initialValues={{passphrase: ''}}
             onSubmit={submitForm}
             validationSchema={Yup.object().shape({
                 passphrase: Yup.string().required(constants.REQUIRED),
@@ -35,7 +35,9 @@ export default function SingleInputForm(props: Props) {
             validateOnChange={false}
             validateOnBlur={false}
         >
-            {({ values, touched, errors, handleChange, handleSubmit }) => (
+            {({
+                values, touched, errors, handleChange, handleSubmit,
+            }) => (
                 <Form noValidate onSubmit={handleSubmit}>
                     <Form.Group>
                         <Form.Control
@@ -44,10 +46,10 @@ export default function SingleInputForm(props: Props) {
                             value={values.passphrase}
                             onChange={handleChange('passphrase')}
                             isInvalid={Boolean(
-                                touched.passphrase && errors.passphrase
+                                touched.passphrase && errors.passphrase,
                             )}
                             disabled={loading}
-                            autoFocus={true}
+                            autoFocus
                         />
                         <Form.Control.Feedback type="invalid">
                             {errors.passphrase}

+ 6 - 4
src/components/SubmitButton.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import { Button, Spinner } from 'react-bootstrap';
+import {Button, Spinner} from 'react-bootstrap';
 
 interface Props {
     loading: boolean;
@@ -7,20 +7,22 @@ interface Props {
     inline?: any;
     disabled?: boolean;
 }
-const SubmitButton = ({ loading, buttonText, inline, disabled }: Props) => (
+const SubmitButton = ({
+    loading, buttonText, inline, disabled,
+}: Props) => (
     <Button
         className="submitButton"
         variant="outline-success"
         type="submit"
         block={!inline}
         disabled={loading || disabled}
-        style={{ padding: '6px 1em' }}
+        style={{padding: '6px 1em'}}
     >
         {loading ? (
             <Spinner
                 as="span"
                 animation="border"
-                style={{ width: '22px', height: '22px', borderWidth: '0.20em' }}
+                style={{width: '22px', height: '22px', borderWidth: '0.20em'}}
             />
         ) : (
             buttonText

+ 4 - 3
src/pages/404.js

@@ -1,6 +1,7 @@
-import Error from 'next/error'
+import React from 'react';
+import Error from 'next/error';
 
 export default function NotFound() {
-  // Opinionated: do not record an exception in Sentry for 404
-  return <Error statusCode={404} />
+    // Opinionated: do not record an exception in Sentry for 404
+    return <Error statusCode={404} />;
 }

+ 11 - 12
src/pages/_app.tsx

@@ -1,15 +1,14 @@
-import React, { useEffect, useState } from 'react';
-import styled, { createGlobalStyle } from 'styled-components';
+import React, {useEffect, useState} from 'react';
+import styled, {createGlobalStyle} from 'styled-components';
 import Navbar from 'components/Navbar';
 import constants from 'utils/strings/constants';
-import { useRouter } from 'next/router';
+import {useRouter} from 'next/router';
 import Container from 'components/Container';
 import Head from 'next/head';
 import 'bootstrap/dist/css/bootstrap.min.css';
 import 'photoswipe/dist/photoswipe.css';
-import { Workbox } from 'workbox-window';
-import { sentryInit } from '../utils/sentry';
 import EnteSpinner from 'components/EnteSpinner';
+import {sentryInit} from '../utils/sentry';
 
 const GlobalStyles = createGlobalStyle`
 /* ubuntu-regular - latin */
@@ -306,11 +305,11 @@ export interface BannerMessage {
 }
 
 sentryInit();
-export default function App({ Component, pageProps, err }) {
+export default function App({Component, err}) {
     const router = useRouter();
     const [loading, setLoading] = useState(false);
     const [offline, setOffline] = useState(
-        typeof window !== 'undefined' && !window.navigator.onLine
+        typeof window !== 'undefined' && !window.navigator.onLine,
     );
     useEffect(() => {
         //     // if (
@@ -326,12 +325,12 @@ export default function App({ Component, pageProps, err }) {
         if ('serviceWorker' in navigator) {
             navigator.serviceWorker
                 .getRegistrations()
-                .then(function (registrations) {
-                    for (let registration of registrations) {
+                .then((registrations) => {
+                    for (const registration of registrations) {
                         registration.unregister();
                     }
                 })
-                .catch(function (err) {
+                .catch((err) => {
                     console.log('Service Worker registration failed: ', err);
                 });
         }
@@ -343,7 +342,7 @@ export default function App({ Component, pageProps, err }) {
     useEffect(() => {
         console.log(
             `%c${constants.CONSOLE_WARNING_STOP}`,
-            'color: red; font-size: 52px;'
+            'color: red; font-size: 52px;',
         );
         console.log(`%c${constants.CONSOLE_WARNING_DESC}`, 'font-size: 20px;');
 
@@ -382,7 +381,7 @@ export default function App({ Component, pageProps, err }) {
             <Navbar>
                 <FlexContainer>
                     <LogoImage
-                        style={{ height: '24px', padding: '3px' }}
+                        style={{height: '24px', padding: '3px'}}
                         alt="logo"
                         src="/icon.svg"
                     />

+ 8 - 7
src/pages/_document.tsx

@@ -1,5 +1,8 @@
-import Document, { Html, Head, Main, NextScript } from 'next/document';
-import { ServerStyleSheet } from 'styled-components';
+import React from 'react';
+import Document, {
+    Html, Head, Main, NextScript,
+} from 'next/document';
+import {ServerStyleSheet} from 'styled-components';
 
 export default class MyDocument extends Document {
     static async getInitialProps(ctx) {
@@ -7,11 +10,9 @@ export default class MyDocument extends Document {
         const originalRenderPage = ctx.renderPage;
 
         try {
-            ctx.renderPage = () =>
-                originalRenderPage({
-                    enhanceApp: (App) => (props) =>
-                        sheet.collectStyles(<App {...props} />),
-                });
+            ctx.renderPage = () => originalRenderPage({
+                enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />),
+            });
 
             const initialProps = await Document.getInitialProps(ctx);
             return {

+ 56 - 55
src/pages/_error.js

@@ -1,60 +1,61 @@
-import NextErrorComponent from 'next/error'
-import * as Sentry from '@sentry/node'
+import React from 'react';
+import NextErrorComponent from 'next/error';
+import * as Sentry from '@sentry/node';
 
-const MyError = ({ statusCode, hasGetInitialPropsRun, err }) => {
-  if (!hasGetInitialPropsRun && err) {
+const MyError = ({statusCode, hasGetInitialPropsRun, err}) => {
+    if (!hasGetInitialPropsRun && err) {
     // getInitialProps is not called in case of
     // https://github.com/vercel/next.js/issues/8592. As a workaround, we pass
     // err via _app.js so it can be captured
-    Sentry.captureException(err)
+        Sentry.captureException(err);
     // Flushing is not required in this case as it only happens on the client
-  }
-
-  return <NextErrorComponent statusCode={statusCode} />
-}
-
-MyError.getInitialProps = async ({ res, err, asPath }) => {
-  const errorInitialProps = await NextErrorComponent.getInitialProps({
-    res,
-    err,
-  })
-
-  // Workaround for https://github.com/vercel/next.js/issues/8592, mark when
-  // getInitialProps has run
-  errorInitialProps.hasGetInitialPropsRun = true
-
-  // Running on the server, the response object (`res`) is available.
-  //
-  // Next.js will pass an err on the server if a page's data fetching methods
-  // threw or returned a Promise that rejected
-  //
-  // Running on the client (browser), Next.js will provide an err if:
-  //
-  //  - a page's `getInitialProps` threw or returned a Promise that rejected
-  //  - an exception was thrown somewhere in the React lifecycle (render,
-  //    componentDidMount, etc) that was caught by Next.js's React Error
-  //    Boundary. Read more about what types of exceptions are caught by Error
-  //    Boundaries: https://reactjs.org/docs/error-boundaries.html
-
-  if (err) {
-    Sentry.captureException(err)
-
-    // Flushing before returning is necessary if deploying to Vercel, see
-    // https://vercel.com/docs/platform/limits#streaming-responses
-    await Sentry.flush(2000)
-
-    return errorInitialProps
-  }
-
-  // If this point is reached, getInitialProps was called without any
-  // information about what the error might be. This is unexpected and may
-  // indicate a bug introduced in Next.js, so record it in Sentry
-  Sentry.captureException(
-    new Error(`_error.js getInitialProps missing data at path: ${asPath}`)
-  )
-  await Sentry.flush(2000)
-
-  return errorInitialProps
-}
-
-export default MyError
+    }
+
+    return <NextErrorComponent statusCode={statusCode} />;
+};
+
+MyError.getInitialProps = async ({res, err, asPath}) => {
+    const errorInitialProps = await NextErrorComponent.getInitialProps({
+        res,
+        err,
+    });
+
+    // Workaround for https://github.com/vercel/next.js/issues/8592, mark when
+    // getInitialProps has run
+    errorInitialProps.hasGetInitialPropsRun = true;
+
+    // Running on the server, the response object (`res`) is available.
+    //
+    // Next.js will pass an err on the server if a page's data fetching methods
+    // threw or returned a Promise that rejected
+    //
+    // Running on the client (browser), Next.js will provide an err if:
+    //
+    //  - a page's `getInitialProps` threw or returned a Promise that rejected
+    //  - an exception was thrown somewhere in the React lifecycle (render,
+    //    componentDidMount, etc) that was caught by Next.js's React Error
+    //    Boundary. Read more about what types of exceptions are caught by Error
+    //    Boundaries: https://reactjs.org/docs/error-boundaries.html
+
+    if (err) {
+        Sentry.captureException(err);
+
+        // Flushing before returning is necessary if deploying to Vercel, see
+        // https://vercel.com/docs/platform/limits#streaming-responses
+        await Sentry.flush(2000);
+
+        return errorInitialProps;
+    }
+
+    // If this point is reached, getInitialProps was called without any
+    // information about what the error might be. This is unexpected and may
+    // indicate a bug introduced in Next.js, so record it in Sentry
+    Sentry.captureException(
+        new Error(`_error.js getInitialProps missing data at path: ${asPath}`),
+    );
+    await Sentry.flush(2000);
+
+    return errorInitialProps;
+};
+
+export default MyError;

+ 3 - 4
src/pages/api/[...all].ts

@@ -1,4 +1,4 @@
-import { createProxyMiddleware } from 'http-proxy-middleware';
+import {createProxyMiddleware} from 'http-proxy-middleware';
 
 export const config = {
     api: {
@@ -6,11 +6,10 @@ export const config = {
     },
 };
 
-const API_ENDPOINT =
-    process.env.NEXT_PUBLIC_ENTE_ENDPOINT || 'https://api.staging.ente.io';
+const API_ENDPOINT = process.env.NEXT_PUBLIC_ENTE_ENDPOINT || 'https://api.staging.ente.io';
 
 export default createProxyMiddleware({
     target: API_ENDPOINT,
     changeOrigin: true,
-    pathRewrite: { '^/api': '/' },
+    pathRewrite: {'^/api': '/'},
 });

+ 12 - 15
src/pages/changePassword/index.tsx

@@ -1,15 +1,14 @@
-import React, { useState, useEffect, useContext } from 'react';
+import React, {useState, useEffect} from 'react';
 import constants from 'utils/strings/constants';
-import { getData, LS_KEYS, setData } from 'utils/storage/localStorage';
-import { useRouter } from 'next/router';
-import { getKey, SESSION_KEYS, setKey } from 'utils/storage/sessionStorage';
-import { B64EncryptionResult } from 'services/uploadService';
+import {getData, LS_KEYS, setData} from 'utils/storage/localStorage';
+import {useRouter} from 'next/router';
+import {B64EncryptionResult} from 'services/uploadService';
 import CryptoWorker, {
     setSessionKeys,
     generateAndSaveIntermediateKeyAttributes,
 } from 'utils/crypto';
-import { getActualKey } from 'utils/common/key';
-import { logoutUser, setKeys, UpdatedKey } from 'services/userService';
+import {getActualKey} from 'utils/common/key';
+import {setKeys, UpdatedKey} from 'services/userService';
 import SetPasswordForm from 'components/SetPasswordForm';
 
 export interface KEK {
@@ -21,7 +20,6 @@ export interface KEK {
 export default function Generate() {
     const [token, setToken] = useState<string>();
     const router = useRouter();
-    const key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
 
     useEffect(() => {
         const user = getData(LS_KEYS.USER);
@@ -44,8 +42,7 @@ export default function Generate() {
             setFieldError('confirm', constants.PASSWORD_GENERATION_FAILED);
             return;
         }
-        const encryptedKeyAttributes: B64EncryptionResult =
-            await cryptoWorker.encryptToB64(key, kek.key);
+        const encryptedKeyAttributes: B64EncryptionResult = await cryptoWorker.encryptToB64(key, kek.key);
         const updatedKey: UpdatedKey = {
             kekSalt,
             encryptedKey: encryptedKeyAttributes.encryptedData,
@@ -60,14 +57,14 @@ export default function Generate() {
         await generateAndSaveIntermediateKeyAttributes(
             passphrase,
             updatedKeyAttributes,
-            key
+            key,
         );
 
         setSessionKeys(key);
         redirectToGallery();
     };
     const redirectToGallery = () => {
-        setData(LS_KEYS.SHOW_BACK_BUTTON, { value: false });
+        setData(LS_KEYS.SHOW_BACK_BUTTON, {value: false});
         router.push('/gallery');
     };
     return (
@@ -75,9 +72,9 @@ export default function Generate() {
             callback={onSubmit}
             buttonText={constants.CHANGE_PASSWORD}
             back={
-                getData(LS_KEYS.SHOW_BACK_BUTTON)?.value
-                    ? redirectToGallery
-                    : null
+                getData(LS_KEYS.SHOW_BACK_BUTTON)?.value ?
+                    redirectToGallery :
+                    null
             }
         />
     );

+ 14 - 15
src/pages/credentials/index.tsx

@@ -1,20 +1,19 @@
-import React, { useEffect, useState } from 'react';
-import styled from 'styled-components';
+import React, {useEffect, useState} from 'react';
 
 import constants from 'utils/strings/constants';
-import { getData, LS_KEYS, setData } from 'utils/storage/localStorage';
-import { useRouter } from 'next/router';
-import { KeyAttributes } from 'types';
-import { SESSION_KEYS, getKey } from 'utils/storage/sessionStorage';
+import {getData, LS_KEYS} from 'utils/storage/localStorage';
+import {useRouter} from 'next/router';
+import {KeyAttributes} from 'types';
+import {SESSION_KEYS, getKey} from 'utils/storage/sessionStorage';
 import CryptoWorker, {
     generateAndSaveIntermediateKeyAttributes,
     setSessionKeys,
 } from 'utils/crypto';
-import { logoutUser } from 'services/userService';
-import { isFirstLogin } from 'utils/storage';
+import {logoutUser} from 'services/userService';
+import {isFirstLogin} from 'utils/storage';
 import SingleInputForm from 'components/SingleInputForm';
 import Container from 'components/Container';
-import { Button, Card } from 'react-bootstrap';
+import {Button, Card} from 'react-bootstrap';
 
 export default function Credentials() {
     const router = useRouter();
@@ -43,20 +42,20 @@ export default function Credentials() {
                 passphrase,
                 keyAttributes.kekSalt,
                 keyAttributes.opsLimit,
-                keyAttributes.memLimit
+                keyAttributes.memLimit,
             );
 
             try {
                 const key: string = await cryptoWorker.decryptB64(
                     keyAttributes.encryptedKey,
                     keyAttributes.keyDecryptionNonce,
-                    kek
+                    kek,
                 );
                 if (isFirstLogin()) {
                     await generateAndSaveIntermediateKeyAttributes(
                         passphrase,
                         keyAttributes,
-                        key
+                        key,
                     );
                 }
                 setSessionKeys(key);
@@ -68,7 +67,7 @@ export default function Credentials() {
         } catch (e) {
             setFieldError(
                 'passphrase',
-                `${constants.UNKNOWN_ERROR} ${e.message}`
+                `${constants.UNKNOWN_ERROR} ${e.message}`,
             );
         }
     };
@@ -77,11 +76,11 @@ export default function Credentials() {
         <>
             <Container>
                 <Card
-                    style={{ minWidth: '320px', padding: '40px 30px' }}
+                    style={{minWidth: '320px', padding: '40px 30px'}}
                     className="text-center"
                 >
                     <Card.Body>
-                        <Card.Title style={{ marginBottom: '24px' }}>
+                        <Card.Title style={{marginBottom: '24px'}}>
                             {constants.ENTER_PASSPHRASE}
                         </Card.Title>
                         <SingleInputForm

+ 5 - 5
src/pages/gallery/components/AddCollectionButton.tsx

@@ -1,8 +1,8 @@
 import React from 'react';
-import { Card } from 'react-bootstrap';
+import {Card} from 'react-bootstrap';
 import styled from 'styled-components';
 import constants from 'utils/strings/constants';
-import { CollectionIcon } from './CollectionSelector';
+import {CollectionIcon} from './CollectionSelector';
 
 const ImageContainer = styled.div`
     min-height: 192px;
@@ -15,12 +15,12 @@ const ImageContainer = styled.div`
     cursor: pointer;
 `;
 
-export default function AddCollectionButton({ showNextModal }) {
+export default function AddCollectionButton({showNextModal}) {
     return (
-        <CollectionIcon style={{ margin: '10px' }} onClick={showNextModal}>
+        <CollectionIcon style={{margin: '10px'}} onClick={showNextModal}>
             <Card>
                 <ImageContainer>+</ImageContainer>
-                <Card.Text style={{ textAlign: 'center' }}>
+                <Card.Text style={{textAlign: 'center'}}>
                     {constants.CREATE_COLLECTION}
                 </Card.Text>
             </Card>

+ 2 - 2
src/pages/gallery/components/AlertBanner.tsx

@@ -1,10 +1,10 @@
 import React from 'react';
 import Alert from 'react-bootstrap/Alert';
 
-export default function AlertBanner({ bannerMessage }) {
+export default function AlertBanner({bannerMessage}) {
     return (
         <Alert
-            variant={'danger'}
+            variant="danger"
             style={{
                 display: bannerMessage ? 'block' : 'none',
                 textAlign: 'center',

+ 4 - 4
src/pages/gallery/components/ChoiceModal.tsx

@@ -1,8 +1,8 @@
 import MessageDialog from 'components/MessageDialog';
 import React from 'react';
-import { Button, Modal } from 'react-bootstrap';
+import {Button} from 'react-bootstrap';
 import constants from 'utils/strings/constants';
-import { UPLOAD_STRATEGY } from './Upload';
+import {UPLOAD_STRATEGY} from './Upload';
 
 interface Props {
     uploadFiles;
@@ -17,9 +17,9 @@ function ChoiceModal({
 }: Props) {
     return (
         <MessageDialog
-            size={'lg'}
+            size="lg"
             {...props}
-            attributes={{ title: constants.MULTI_FOLDER_UPLOAD }}
+            attributes={{title: constants.MULTI_FOLDER_UPLOAD}}
         >
             <p>{constants.UPLOAD_STRATEGY_CHOICE}</p>
             <div

+ 12 - 10
src/pages/gallery/components/CollectionNamer.tsx

@@ -1,7 +1,7 @@
-import React, { useEffect, useRef } from 'react';
-import { Form } from 'react-bootstrap';
+import React, {useEffect, useRef} from 'react';
+import {Form} from 'react-bootstrap';
 import constants from 'utils/strings/constants';
-import { Formik } from 'formik';
+import {Formik} from 'formik';
 import * as Yup from 'yup';
 import SubmitButton from 'components/SubmitButton';
 import MessageDialog from 'components/MessageDialog';
@@ -26,7 +26,7 @@ interface formValues {
     albumName: string;
 }
 
-export default function CollectionNamer({ attributes, ...props }: Props) {
+export default function CollectionNamer({attributes, ...props}: Props) {
     const collectionNameInputRef = useRef(null);
     useEffect(() => {
         if (attributes) {
@@ -40,7 +40,7 @@ export default function CollectionNamer({ attributes, ...props }: Props) {
             <MessageDialog show={false} onHide={() => null} attributes={{}} />
         );
     }
-    const onSubmit = ({ albumName }: formValues) => {
+    const onSubmit = ({albumName}: formValues) => {
         attributes.callback(albumName);
         props.onHide();
     };
@@ -48,13 +48,13 @@ export default function CollectionNamer({ attributes, ...props }: Props) {
         <MessageDialog
             show={props.show}
             onHide={props.onHide}
-            size={'sm'}
+            size="sm"
             attributes={{
                 title: attributes?.title,
             }}
         >
             <Formik<formValues>
-                initialValues={{ albumName: attributes.autoFilledName }}
+                initialValues={{albumName: attributes.autoFilledName}}
                 validationSchema={Yup.object().shape({
                     albumName: Yup.string().required(constants.REQUIRED),
                 })}
@@ -62,7 +62,9 @@ export default function CollectionNamer({ attributes, ...props }: Props) {
                 validateOnBlur={false}
                 onSubmit={onSubmit}
             >
-                {({ values, touched, errors, handleChange, handleSubmit }) => (
+                {({
+                    values, touched, errors, handleChange, handleSubmit,
+                }) => (
                     <Form noValidate onSubmit={handleSubmit}>
                         <Form.Group>
                             <Form.Control
@@ -71,11 +73,11 @@ export default function CollectionNamer({ attributes, ...props }: Props) {
                                 value={values.albumName}
                                 onChange={handleChange('albumName')}
                                 isInvalid={Boolean(
-                                    touched.albumName && errors.albumName
+                                    touched.albumName && errors.albumName,
                                 )}
                                 placeholder={constants.ENTER_ALBUM_NAME}
                                 ref={collectionNameInputRef}
-                                autoFocus={true}
+                                autoFocus
                             />
 
                             <Form.Control.Feedback

+ 14 - 13
src/pages/gallery/components/CollectionOptions.tsx

@@ -1,13 +1,14 @@
-import { SetDialogMessage } from 'components/MessageDialog';
-import { ListGroup, Popover } from 'react-bootstrap';
+import React from 'react';
+import {SetDialogMessage} from 'components/MessageDialog';
+import {ListGroup, Popover} from 'react-bootstrap';
 import {
     Collection,
     deleteCollection,
     renameCollection,
 } from 'services/collectionService';
-import { getSelectedCollection } from 'utils/collection';
+import {getSelectedCollection} from 'utils/collection';
 import constants from 'utils/strings/constants';
-import { SetCollectionNamerAttributes } from './CollectionNamer';
+import {SetCollectionNamerAttributes} from './CollectionNamer';
 import LinkButton from './LinkButton';
 
 interface Props {
@@ -23,7 +24,7 @@ interface Props {
 const CollectionOptions = (props: Props) => {
     const collectionRename = async (
         selectedCollection: Collection,
-        newName: string
+        newName: string,
     ) => {
         if (selectedCollection.name !== newName) {
             await renameCollection(selectedCollection, newName);
@@ -36,16 +37,16 @@ const CollectionOptions = (props: Props) => {
             buttonText: constants.RENAME,
             autoFilledName: getSelectedCollection(
                 props.selectedCollectionID,
-                props.collections
+                props.collections,
             )?.name,
             callback: (newName) => {
                 props.startLoadingBar();
                 collectionRename(
                     getSelectedCollection(
                         props.selectedCollectionID,
-                        props.collections
+                        props.collections,
                     ),
-                    newName
+                    newName,
                 );
             },
         });
@@ -63,7 +64,7 @@ const CollectionOptions = (props: Props) => {
                         props.selectedCollectionID,
                         props.syncWithRemote,
                         props.redirectToAll,
-                        props.setDialogMessage
+                        props.setDialogMessage,
                     );
                 },
                 variant: 'danger',
@@ -76,7 +77,7 @@ const CollectionOptions = (props: Props) => {
 
     const MenuLink = (props) => (
         <LinkButton
-            style={{ fontSize: '14px', fontWeight: 700, padding: '8px 1em' }}
+            style={{fontSize: '14px', fontWeight: 700, padding: '8px 1em'}}
             {...props}
         >
             {props.children}
@@ -94,9 +95,9 @@ const CollectionOptions = (props: Props) => {
         </ListGroup.Item>
     );
     return (
-        <Popover id="collection-options" style={{ borderRadius: '10px' }}>
-            <Popover.Content style={{ padding: 0, border: 'none' }}>
-                <ListGroup style={{ borderRadius: '8px' }}>
+        <Popover id="collection-options" style={{borderRadius: '10px'}}>
+            <Popover.Content style={{padding: 0, border: 'none'}}>
+                <ListGroup style={{borderRadius: '8px'}}>
                     <MenuItem>
                         <MenuLink onClick={showRenameCollectionModal}>
                             {constants.RENAME}

+ 5 - 5
src/pages/gallery/components/CollectionSelector.tsx

@@ -1,9 +1,9 @@
-import React, { useEffect } from 'react';
-import { Card, Modal } from 'react-bootstrap';
+import React, {useEffect} from 'react';
+import {Card, Modal} from 'react-bootstrap';
+import styled from 'styled-components';
+import {CollectionAndItsLatestFile} from 'services/collectionService';
 import AddCollectionButton from './AddCollectionButton';
 import PreviewCard from './PreviewCard';
-import styled from 'styled-components';
-import { CollectionAndItsLatestFile } from 'services/collectionService';
 
 export const CollectionIcon = styled.div`
     width: 200px;
@@ -67,7 +67,7 @@ function CollectionSelector({
                     </Card.Text>
                 </Card>
             </CollectionIcon>
-        )
+        ),
     );
 
     return (

+ 37 - 41
src/pages/gallery/components/Collections.tsx

@@ -1,18 +1,20 @@
 import CollectionShare from 'components/CollectionShare';
-import { SetDialogMessage } from 'components/MessageDialog';
+import {SetDialogMessage} from 'components/MessageDialog';
 import NavigationButton, {
     SCROLL_DIRECTION,
 } from 'components/NavigationButton';
-import React, { useCallback, useEffect, useRef, useState } from 'react';
-import { OverlayTrigger } from 'react-bootstrap';
-import { Collection, CollectionType } from 'services/collectionService';
-import { User } from 'services/userService';
+import React, {
+    useEffect, useRef, useState,
+} from 'react';
+import {OverlayTrigger} from 'react-bootstrap';
+import {Collection, CollectionType} from 'services/collectionService';
+import {User} from 'services/userService';
 import styled from 'styled-components';
-import { getSelectedCollection } from 'utils/collection';
-import { getData, LS_KEYS } from 'utils/storage/localStorage';
-import { SetCollectionNamerAttributes } from './CollectionNamer';
+import {getSelectedCollection} from 'utils/collection';
+import {getData, LS_KEYS} from 'utils/storage/localStorage';
+import {SetCollectionNamerAttributes} from './CollectionNamer';
 import CollectionOptions from './CollectionOptions';
-import OptionIcon, { OptionIconWrapper } from './OptionIcon';
+import OptionIcon, {OptionIconWrapper} from './OptionIcon';
 
 interface CollectionProps {
     collections: Collection[];
@@ -61,8 +63,7 @@ const Chip = styled.button<{ active: boolean }>`
     padding-left: 24px;
     margin: 3px;
     border: none;
-    background-color: ${(props) =>
-        props.active ? '#fff' : 'rgba(255, 255, 255, 0.3)'};
+    background-color: ${(props) => (props.active ? '#fff' : 'rgba(255, 255, 255, 0.3)')};
     outline: none !important;
     &:hover {
         background-color: ${(props) => !props.active && '#bbbbbb'};
@@ -74,12 +75,10 @@ const Chip = styled.button<{ active: boolean }>`
 `;
 
 export default function Collections(props: CollectionProps) {
-    const { selected, collections, selectCollection } = props;
-    const [selectedCollectionID, setSelectedCollectionID] =
-        useState<number>(null);
+    const {selected, collections, selectCollection} = props;
+    const [selectedCollectionID, setSelectedCollectionID] = useState<number>(null);
     const collectionRef = useRef<HTMLDivElement>(null);
-    const [collectionShareModalView, setCollectionShareModalView] =
-        useState(false);
+    const [collectionShareModalView, setCollectionShareModalView] = useState(false);
     const [scrollObj, setScrollObj] = useState<{
         scrollLeft?: number;
         scrollWidth?: number;
@@ -88,9 +87,8 @@ export default function Collections(props: CollectionProps) {
 
     const updateScrollObj = () => {
         if (collectionRef.current) {
-            const { scrollLeft, scrollWidth, clientWidth } =
-                collectionRef.current;
-            setScrollObj({ scrollLeft, scrollWidth, clientWidth });
+            const {scrollLeft, scrollWidth, clientWidth} = collectionRef.current;
+            setScrollObj({scrollLeft, scrollWidth, clientWidth});
         }
     };
 
@@ -139,7 +137,7 @@ export default function Collections(props: CollectionProps) {
                     onHide={() => setCollectionShareModalView(false)}
                     collection={getSelectedCollection(
                         selectedCollectionID,
-                        props.collections
+                        props.collections,
                     )}
                     syncWithRemote={props.syncWithRemote}
                 />
@@ -152,7 +150,7 @@ export default function Collections(props: CollectionProps) {
                     )}
                     <Wrapper ref={collectionRef} onScroll={updateScrollObj}>
                         <Chip active={!selected} onClick={clickHandler()}>
-                            All
+                        All
                             <div
                                 style={{
                                     display: 'inline-block',
@@ -167,28 +165,26 @@ export default function Collections(props: CollectionProps) {
                                 onClick={clickHandler(item)}
                             >
                                 {item.name}
-                                {item.type != CollectionType.favorites &&
+                                {item.type !== CollectionType.favorites &&
                                 item.owner.id === user?.id ? (
-                                    <OverlayTrigger
-                                        rootClose
-                                        trigger="click"
-                                        placement="bottom"
-                                        overlay={collectionOptions}
-                                    >
-                                        <OptionIcon
-                                            onClick={() =>
-                                                setSelectedCollectionID(item.id)
-                                            }
+                                        <OverlayTrigger
+                                            rootClose
+                                            trigger="click"
+                                            placement="bottom"
+                                            overlay={collectionOptions}
+                                        >
+                                            <OptionIcon
+                                                onClick={() => setSelectedCollectionID(item.id)}
+                                            />
+                                        </OverlayTrigger>
+                                    ) : (
+                                        <div
+                                            style={{
+                                                display: 'inline-block',
+                                                width: '24px',
+                                            }}
                                         />
-                                    </OverlayTrigger>
-                                ) : (
-                                    <div
-                                        style={{
-                                            display: 'inline-block',
-                                            width: '24px',
-                                        }}
-                                    />
-                                )}
+                                    )}
                             </Chip>
                         ))}
                     </Wrapper>

+ 8 - 8
src/pages/gallery/components/LinkButton.tsx

@@ -14,14 +14,14 @@ type Props = React.PropsWithChildren<{
 export default function LinkButton(props: Props) {
     function getButtonColor(variant: string) {
         switch (variant) {
-            case ButtonVariant.success:
-                return '#2dc262';
-            case ButtonVariant.danger:
-                return '#c93f3f';
-            case ButtonVariant.secondary:
-                return '#858585';
-            default:
-                return '#d1d1d1';
+        case ButtonVariant.success:
+            return '#2dc262';
+        case ButtonVariant.danger:
+            return '#c93f3f';
+        case ButtonVariant.secondary:
+            return '#858585';
+        default:
+            return '#d1d1d1';
         }
     }
     return (

+ 20 - 21
src/pages/gallery/components/OptionIcon.tsx

@@ -1,3 +1,4 @@
+import React from 'react';
 import styled from 'styled-components';
 
 export const OptionIconWrapper = styled.div`
@@ -9,26 +10,24 @@ export const OptionIconWrapper = styled.div`
 interface Props {
     onClick: () => void;
 }
-const OptionIcon = ({ onClick }: Props) => {
-    return (
-        <OptionIconWrapper
-            onClick={(e) => {
-                onClick();
-                e.stopPropagation();
-            }}
-            style={{ marginBottom: "2px" }}
+const OptionIcon = ({onClick}: Props) => (
+    <OptionIconWrapper
+        onClick={(e) => {
+            onClick();
+            e.stopPropagation();
+        }}
+        style={{marginBottom: '2px'}}
+    >
+        <svg
+            xmlns="http://www.w3.org/2000/svg"
+            height="20px"
+            width="24px"
+            viewBox="0 0 24 24"
+            fill="#000000"
         >
-            <svg
-                xmlns="http://www.w3.org/2000/svg"
-                height="20px"
-                width="24px"
-                viewBox="0 0 24 24"
-                fill="#000000"
-            >
-                <path d="M0 0h24v24H0V0z" fill="none" />
-                <path fill="#666" d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
-            </svg>
-        </OptionIconWrapper>
-    );
-};
+            <path d="M0 0h24v24H0V0z" fill="none" />
+            <path fill="#666" d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
+        </svg>
+    </OptionIconWrapper>
+);
 export default OptionIcon;

+ 83 - 87
src/pages/gallery/components/PlanSelector.tsx

@@ -1,8 +1,8 @@
-import React, { useEffect, useState } from 'react';
-import { Form, Modal, Button } from 'react-bootstrap';
+import React, {useEffect, useState} from 'react';
+import {Form, Modal, Button} from 'react-bootstrap';
 import constants from 'utils/strings/constants';
 import styled from 'styled-components';
-import billingService, { Plan, Subscription } from 'services/billingService';
+import billingService, {Plan, Subscription} from 'services/billingService';
 import {
     convertBytesToGBs,
     getPlans,
@@ -17,11 +17,11 @@ import {
     hasPaidSubscription,
     isOnFreePlan,
 } from 'utils/billingUtil';
-import { DeadCenter, SetLoading } from '..';
-import LinkButton from './LinkButton';
-import { reverseString } from 'utils/common';
-import { SetDialogMessage } from 'components/MessageDialog';
+import {reverseString} from 'utils/common';
+import {SetDialogMessage} from 'components/MessageDialog';
 import ArrowEast from 'components/ArrowEast';
+import LinkButton from './LinkButton';
+import {DeadCenter, SetLoading} from '..';
 
 export const PlanIcon = styled.div<{ selected: boolean }>`
     border-radius: 20px;
@@ -79,11 +79,9 @@ function PlanSelector(props: Props) {
     const plans = getPlans();
     const [planPeriod, setPlanPeriod] = useState<PLAN_PERIOD>(PLAN_PERIOD.YEAR);
     const togglePeriod = () => {
-        setPlanPeriod((prevPeriod) =>
-            prevPeriod == PLAN_PERIOD.MONTH
-                ? PLAN_PERIOD.YEAR
-                : PLAN_PERIOD.MONTH
-        );
+        setPlanPeriod((prevPeriod) => (prevPeriod === PLAN_PERIOD.MONTH ?
+            PLAN_PERIOD.YEAR :
+            PLAN_PERIOD.MONTH));
     };
     useEffect(() => {
         if (!plans && props.modalView) {
@@ -105,12 +103,12 @@ function PlanSelector(props: Props) {
             props.setDialogMessage({
                 title: constants.ERROR,
                 content: constants.CANCEL_SUBSCRIPTION_ON_MOBILE,
-                close: { variant: 'danger' },
+                close: {variant: 'danger'},
             });
         } else if (hasStripeSubscription(subscription)) {
             props.setDialogMessage({
                 title: `${constants.CONFIRM} ${reverseString(
-                    constants.UPDATE_SUBSCRIPTION
+                    constants.UPDATE_SUBSCRIPTION,
                 )}`,
                 content: constants.UPDATE_SUBSCRIPTION_MESSAGE,
                 staticBackdrop: true,
@@ -121,11 +119,11 @@ function PlanSelector(props: Props) {
                         plan,
                         props.setDialogMessage,
                         props.setLoading,
-                        props.closeModal
+                        props.closeModal,
                     ),
                     variant: 'success',
                 },
-                close: { text: constants.CANCEL },
+                close: {text: constants.CANCEL},
             });
         } else {
             try {
@@ -135,7 +133,7 @@ function PlanSelector(props: Props) {
                 props.setDialogMessage({
                     title: constants.ERROR,
                     content: constants.SUBSCRIPTION_PURCHASE_FAILED,
-                    close: { variant: 'danger' },
+                    close: {variant: 'danger'},
                 });
             } finally {
                 props.setLoading(false);
@@ -144,7 +142,7 @@ function PlanSelector(props: Props) {
     }
 
     const PlanIcons: JSX.Element[] = plans
-        ?.filter((plan) => plan.period == planPeriod)
+        ?.filter((plan) => plan.period === planPeriod)
         ?.map((plan) => (
             <PlanIcon
                 key={plan.stripeID}
@@ -157,7 +155,7 @@ function PlanSelector(props: Props) {
                             color: '#ECECEC',
                             fontWeight: 900,
                             fontSize: '72px',
-                            lineHeight: '72px'
+                            lineHeight: '72px',
                         }}
                     >
                         {convertBytesToGBs(plan.storage, 0)}
@@ -170,22 +168,24 @@ function PlanSelector(props: Props) {
                         }}
                     >
                         {' '}
-                        GB
+                    GB
                     </span>
                 </div>
                 <div
-                    className={`bold-text`}
-                    style={{ color: '#aaa', lineHeight: '36px', fontSize: '20px' }}
-                >{`${plan.price} / ${plan.period}`}</div>
+                    className="bold-text"
+                    style={{color: '#aaa', lineHeight: '36px', fontSize: '20px'}}
+                >
+                    {`${plan.price} / ${plan.period}`}
+                </div>
                 <Button
                     variant="outline-success"
                     block
-                    style={{ marginTop: '30px'}}
+                    style={{marginTop: '30px'}}
                     disabled={isUserSubscribedPlan(plan, subscription)}
                     onClick={async () => (await onPlanSelect(plan))}
                 >
                     {constants.CHOOSE_PLAN_BTN}
-                    <ArrowEast style={{ marginLeft: '10px' }} />
+                    <ArrowEast style={{marginLeft: '10px'}} />
                 </Button>
             </PlanIcon>
         ));
@@ -195,7 +195,7 @@ function PlanSelector(props: Props) {
             onHide={props.closeModal}
             size="xl"
             centered
-            backdrop={hasPaidSubscription(subscription) ? 'true' : `static`}
+            backdrop={hasPaidSubscription(subscription) ? 'true' : 'static'}
         >
             <Modal.Header closeButton>
                 <Modal.Title
@@ -206,32 +206,32 @@ function PlanSelector(props: Props) {
                     }}
                 >
                     <span>
-                        {hasPaidSubscription(subscription)
-                            ? constants.MANAGE_PLAN
-                            : constants.CHOOSE_PLAN}
+                        {hasPaidSubscription(subscription) ?
+                            constants.MANAGE_PLAN :
+                            constants.CHOOSE_PLAN}
                     </span>
                 </Modal.Title>
             </Modal.Header>
-            <Modal.Body style={{ marginTop: '20px' }}>
+            <Modal.Body style={{marginTop: '20px'}}>
                 <DeadCenter>
-                    <div style={{ display: 'flex' }}>
+                    <div style={{display: 'flex'}}>
                         <span
-                            className={`bold-text`}
-                            style={{ fontSize: '20px' }}
+                            className="bold-text"
+                            style={{fontSize: '20px'}}
                         >
                             {constants.MONTHLY}
                         </span>
 
                         <Form.Switch
                             checked={planPeriod === PLAN_PERIOD.YEAR}
-                            id={`plan-period-toggler`}
-                            style={{ margin: '-4px 0 20px 15px' }}
-                            className={`custom-switch-md`}
+                            id="plan-period-toggler"
+                            style={{margin: '-4px 0 20px 15px'}}
+                            className="custom-switch-md"
                             onChange={togglePeriod}
                         />
                         <span
-                            className={`bold-text`}
-                            style={{ fontSize: '20px' }}
+                            className="bold-text"
+                            style={{fontSize: '20px'}}
                         >
                             {constants.YEARLY}
                         </span>
@@ -248,64 +248,60 @@ function PlanSelector(props: Props) {
                 >
                     {plans && PlanIcons}
                 </div>
-                <DeadCenter style={{ marginBottom: '30px' }}>
+                <DeadCenter style={{marginBottom: '30px'}}>
                     {hasStripeSubscription(subscription) ? (
                         <>
                             {isSubscriptionCancelled(subscription) ? (
                                 <LinkButton
                                     variant="success"
-                                    onClick={() =>
-                                        props.setDialogMessage({
-                                            title:
+                                    onClick={() => props.setDialogMessage({
+                                        title:
                                                 constants.CONFIRM_ACTIVATE_SUBSCRIPTION,
-                                            content: constants.ACTIVATE_SUBSCRIPTION_MESSAGE(
-                                                subscription.expiryTime
-                                            ),
-                                            staticBackdrop: true,
-                                            proceed: {
-                                                text:
+                                        content: constants.ACTIVATE_SUBSCRIPTION_MESSAGE(
+                                            subscription.expiryTime,
+                                        ),
+                                        staticBackdrop: true,
+                                        proceed: {
+                                            text:
                                                     constants.ACTIVATE_SUBSCRIPTION,
-                                                action: activateSubscription.bind(
-                                                    null,
-                                                    props.setDialogMessage,
-                                                    props.closeModal,
-                                                    props.setLoading
-                                                ),
-                                                variant: 'success',
-                                            },
-                                            close: {
-                                                text: constants.CANCEL,
-                                            },
-                                        })
-                                    }
+                                            action: activateSubscription.bind(
+                                                null,
+                                                props.setDialogMessage,
+                                                props.closeModal,
+                                                props.setLoading,
+                                            ),
+                                            variant: 'success',
+                                        },
+                                        close: {
+                                            text: constants.CANCEL,
+                                        },
+                                    })}
                                 >
                                     {constants.ACTIVATE_SUBSCRIPTION}
                                 </LinkButton>
                             ) : (
                                 <LinkButton
                                     variant="danger"
-                                    onClick={() =>
-                                        props.setDialogMessage({
-                                            title:
+                                    onClick={() => props.setDialogMessage({
+                                        title:
                                                 constants.CONFIRM_CANCEL_SUBSCRIPTION,
-                                            content: constants.CANCEL_SUBSCRIPTION_MESSAGE(),
-                                            staticBackdrop: true,
-                                            proceed: {
-                                                text:
+                                        content: constants.CANCEL_SUBSCRIPTION_MESSAGE(),
+                                        staticBackdrop: true,
+                                        proceed: {
+                                            text:
                                                     constants.CANCEL_SUBSCRIPTION,
-                                                action: cancelSubscription.bind(
-                                                    null,
-                                                    props.setDialogMessage,
-                                                    props.closeModal,
-                                                    props.setLoading
-                                                ),
-                                                variant: 'danger',
-                                            },
-                                            close: {
-                                                text: constants.CANCEL,
-                                            },
-                                        })
-                                    }
+                                            action: cancelSubscription.bind(
+                                                null,
+                                                props.setDialogMessage,
+                                                props.closeModal,
+                                                props.setLoading,
+                                            ),
+                                            variant: 'danger',
+                                        },
+                                        close: {
+                                            text: constants.CANCEL,
+                                        },
+                                    })}
                                 >
                                     {constants.CANCEL_SUBSCRIPTION}
                                 </LinkButton>
@@ -315,9 +311,9 @@ function PlanSelector(props: Props) {
                                 onClick={updatePaymentMethod.bind(
                                     null,
                                     props.setDialogMessage,
-                                    props.setLoading
+                                    props.setLoading,
                                 )}
-                                style={{ marginTop: '20px' }}
+                                style={{marginTop: '20px'}}
                             >
                                 {constants.MANAGEMENT_PORTAL}
                             </LinkButton>
@@ -326,11 +322,11 @@ function PlanSelector(props: Props) {
                         <LinkButton
                             variant="primary"
                             onClick={props.closeModal}
-                            style={{ color: 'rgb(121, 121, 121)', marginTop: '20px' }}
+                            style={{color: 'rgb(121, 121, 121)', marginTop: '20px'}}
                         >
-                            {isOnFreePlan(subscription)
-                                ? constants.SKIP
-                                : constants.CLOSE}
+                            {isOnFreePlan(subscription) ?
+                                constants.SKIP :
+                                constants.CLOSE}
                         </LinkButton>
                     )}
                 </DeadCenter>

+ 2 - 2
src/pages/gallery/components/PreviewCard.tsx

@@ -1,5 +1,5 @@
-import React, { useEffect, useRef, useState } from 'react';
-import { File } from 'services/fileService';
+import React, {useEffect, useRef, useState} from 'react';
+import {File} from 'services/fileService';
 import styled from 'styled-components';
 import PlayCircleOutline from 'components/PlayCircleOutline';
 import DownloadManager from 'services/downloadManager';

+ 26 - 33
src/pages/gallery/components/SelectedFileOptions.tsx

@@ -1,9 +1,9 @@
 import AddToCollectionBtn from 'components/AddToCollectionBtn';
 import DeleteBtn from 'components/DeleteBtn';
-import { SetDialogMessage } from 'components/MessageDialog';
+import {SetDialogMessage} from 'components/MessageDialog';
 import React from 'react';
 import constants from 'utils/strings/constants';
-import { SetCollectionSelectorAttributes } from './CollectionSelector';
+import {SetCollectionSelectorAttributes} from './CollectionSelector';
 
 interface Props {
     addToCollectionHelper: (collectionName, collection) => void;
@@ -18,36 +18,29 @@ const SelectedFileOptions = ({
     setDialogMessage,
     setCollectionSelectorAttributes,
     deleteFileHelper,
-}: Props) => {
-    return (
-        <>
-            <AddToCollectionBtn
-                onClick={() =>
-                    setCollectionSelectorAttributes({
-                        callback: (collection) =>
-                            addToCollectionHelper(null, collection),
-                        showNextModal: showCreateCollectionModal,
-                        title: 'add to collection',
-                    })
-                }
-            />
-            <DeleteBtn
-                onClick={() =>
-                    setDialogMessage({
-                        title: constants.CONFIRM_DELETE_FILE,
-                        content: constants.DELETE_FILE_MESSAGE,
-                        staticBackdrop: true,
-                        proceed: {
-                            action: deleteFileHelper,
-                            text: constants.DELETE,
-                            variant: 'danger',
-                        },
-                        close: { text: constants.CANCEL },
-                    })
-                }
-            />
-        </>
-    );
-};
+}: Props) => (
+    <>
+        <AddToCollectionBtn
+            onClick={() => setCollectionSelectorAttributes({
+                callback: (collection) => addToCollectionHelper(null, collection),
+                showNextModal: showCreateCollectionModal,
+                title: 'add to collection',
+            })}
+        />
+        <DeleteBtn
+            onClick={() => setDialogMessage({
+                title: constants.CONFIRM_DELETE_FILE,
+                content: constants.DELETE_FILE_MESSAGE,
+                staticBackdrop: true,
+                proceed: {
+                    action: deleteFileHelper,
+                    text: constants.DELETE,
+                    variant: 'danger',
+                },
+                close: {text: constants.CANCEL},
+            })}
+        />
+    </>
+);
 
 export default SelectedFileOptions;

+ 48 - 52
src/pages/gallery/components/Upload.tsx

@@ -1,15 +1,15 @@
-import React, { useEffect, useState } from 'react';
-import { FileWithCollection, UPLOAD_STAGES } from 'services/uploadService';
+import React, {useEffect, useState} from 'react';
+import UploadService, {FileWithCollection, UPLOAD_STAGES} from 'services/uploadService';
+import {createAlbum} from 'services/collectionService';
+import {File} from 'services/fileService';
+import constants from 'utils/strings/constants';
+import {SetDialogMessage} from 'components/MessageDialog';
 import UploadProgress from './UploadProgress';
-import UploadService from 'services/uploadService';
-import { createAlbum } from 'services/collectionService';
+
 import ChoiceModal from './ChoiceModal';
-import { File } from 'services/fileService';
-import constants from 'utils/strings/constants';
-import { SetCollectionNamerAttributes } from './CollectionNamer';
-import { SetCollectionSelectorAttributes } from './CollectionSelector';
-import { SetLoading } from '..';
-import { SetDialogMessage } from 'components/MessageDialog';
+import {SetCollectionNamerAttributes} from './CollectionNamer';
+import {SetCollectionSelectorAttributes} from './CollectionSelector';
+import {SetLoading} from '..';
 
 interface Props {
     syncWithRemote: () => Promise<void>;
@@ -36,18 +36,17 @@ interface AnalysisResult {
 export default function Upload(props: Props) {
     const [progressView, setProgressView] = useState(false);
     const [uploadStage, setUploadStage] = useState<UPLOAD_STAGES>(
-        UPLOAD_STAGES.START
+        UPLOAD_STAGES.START,
     );
-    const [fileCounter, setFileCounter] = useState({ current: 0, total: 0 });
+    const [fileCounter, setFileCounter] = useState({current: 0, total: 0});
     const [fileProgress, setFileProgress] = useState(new Map<string, number>());
     const [percentComplete, setPercentComplete] = useState(0);
     const [choiceModalView, setChoiceModalView] = useState(false);
-    const [fileAnalysisResult, setFileAnalysisResult] =
-        useState<AnalysisResult>(null);
+    const [fileAnalysisResult, setFileAnalysisResult] = useState<AnalysisResult>(null);
     useEffect(() => {
         if (props.acceptedFiles?.length > 0) {
             props.setLoading(true);
-            let fileAnalysisResult = analyseUploadFiles();
+            const fileAnalysisResult = analyseUploadFiles();
             if (!fileAnalysisResult) {
                 setFileAnalysisResult(fileAnalysisResult);
             }
@@ -60,9 +59,9 @@ export default function Upload(props: Props) {
         }
     }, [props.acceptedFiles]);
 
-    const uploadInit = function () {
+    const uploadInit = function() {
         setUploadStage(UPLOAD_STAGES.START);
-        setFileCounter({ current: 0, total: 0 });
+        setFileCounter({current: 0, total: 0});
         setFileProgress(new Map<string, number>());
         setPercentComplete(0);
     };
@@ -75,29 +74,29 @@ export default function Upload(props: Props) {
                 props.closeCollectionSelector();
                 await uploadFilesToNewCollections(
                     UPLOAD_STRATEGY.SINGLE_COLLECTION,
-                    collectionName
+                    collectionName,
                 );
             },
         });
     };
 
     const nextModal = (fileAnalysisResult: AnalysisResult) => {
-        fileAnalysisResult?.multipleFolders
-            ? setChoiceModalView(true)
-            : showCreateCollectionModal(fileAnalysisResult);
+        fileAnalysisResult?.multipleFolders ?
+            setChoiceModalView(true) :
+            showCreateCollectionModal(fileAnalysisResult);
         setFileAnalysisResult(fileAnalysisResult);
     };
 
     function analyseUploadFiles() {
-        if (props.acceptedFiles.length == 0) {
+        if (props.acceptedFiles.length === 0) {
             return null;
         }
-        const paths: string[] = props.acceptedFiles.map((file) => file['path']);
+        const paths: string[] = props.acceptedFiles.map((file) => file.path);
         paths.sort();
-        let firstPath = paths[0],
-            lastPath = paths[paths.length - 1],
-            L = firstPath.length,
-            i = 0;
+        const firstPath = paths[0];
+        const lastPath = paths[paths.length - 1];
+        const L = firstPath.length;
+        let i = 0;
         const firstFileFolder = firstPath.substr(0, firstPath.lastIndexOf('/'));
         const lastFileFolder = lastPath.substr(0, lastPath.lastIndexOf('/'));
         while (i < L && firstPath.charAt(i) === lastPath.charAt(i)) i++;
@@ -105,7 +104,7 @@ export default function Upload(props: Props) {
         if (commonPathPrefix) {
             commonPathPrefix = commonPathPrefix.substr(
                 1,
-                commonPathPrefix.lastIndexOf('/') - 1
+                commonPathPrefix.lastIndexOf('/') - 1,
             );
         }
         return {
@@ -114,15 +113,15 @@ export default function Upload(props: Props) {
         };
     }
     function getCollectionWiseFiles() {
-        let collectionWiseFiles = new Map<string, any>();
-        for (let file of props.acceptedFiles) {
-            const filePath = file['path'];
+        const collectionWiseFiles = new Map<string, any>();
+        for (const file of props.acceptedFiles) {
+            const filePath = file.path;
             const folderPath = filePath.substr(0, filePath.lastIndexOf('/'));
             const folderName = folderPath.substr(
-                folderPath.lastIndexOf('/') + 1
+                folderPath.lastIndexOf('/') + 1,
             );
             if (!collectionWiseFiles.has(folderName)) {
-                collectionWiseFiles.set(folderName, new Array<File>());
+                collectionWiseFiles.set(folderName, []);
             }
             collectionWiseFiles.get(folderName).push(file);
         }
@@ -134,11 +133,10 @@ export default function Upload(props: Props) {
             uploadInit();
             setProgressView(true);
 
-            let filesWithCollectionToUpload: FileWithCollection[] =
-                props.acceptedFiles.map((file) => ({
-                    file,
-                    collection,
-                }));
+            const filesWithCollectionToUpload: FileWithCollection[] = props.acceptedFiles.map((file) => ({
+                file,
+                collection,
+            }));
             await uploadFiles(filesWithCollectionToUpload);
         } catch (e) {
             console.error('Failed to upload files to existing collections', e);
@@ -147,23 +145,23 @@ export default function Upload(props: Props) {
 
     const uploadFilesToNewCollections = async (
         strategy: UPLOAD_STRATEGY,
-        collectionName
+        collectionName,
     ) => {
         try {
             uploadInit();
             setProgressView(true);
-            let filesWithCollectionToUpload = new Array<FileWithCollection>();
+            const filesWithCollectionToUpload = [];
             try {
-                if (strategy == UPLOAD_STRATEGY.SINGLE_COLLECTION) {
-                    let collection = await createAlbum(collectionName);
+                if (strategy === UPLOAD_STRATEGY.SINGLE_COLLECTION) {
+                    const collection = await createAlbum(collectionName);
 
                     return await uploadFilesToExistingCollection(collection);
                 }
                 const collectionWiseFiles = getCollectionWiseFiles();
-                for (let [collectionName, files] of collectionWiseFiles) {
-                    let collection = await createAlbum(collectionName);
-                    for (let file of files) {
-                        filesWithCollectionToUpload.push({ collection, file });
+                for (const [collectionName, files] of collectionWiseFiles) {
+                    const collection = await createAlbum(collectionName);
+                    for (const file of files) {
+                        filesWithCollectionToUpload.push({collection, file});
                     }
                 }
             } catch (e) {
@@ -171,7 +169,7 @@ export default function Upload(props: Props) {
                 props.setDialogMessage({
                     title: constants.ERROR,
                     staticBackdrop: true,
-                    close: { variant: 'danger' },
+                    close: {variant: 'danger'},
                     content: constants.CREATE_ALBUM_FAILED,
                 });
                 throw e;
@@ -183,7 +181,7 @@ export default function Upload(props: Props) {
     };
 
     const uploadFiles = async (
-        filesWithCollectionToUpload: FileWithCollection[]
+        filesWithCollectionToUpload: FileWithCollection[],
     ) => {
         try {
             props.setUploadInProgress(true);
@@ -196,7 +194,7 @@ export default function Upload(props: Props) {
                     setFileCounter,
                     setUploadStage,
                     setFileProgress,
-                }
+                },
             );
             props.setUploadInProgress(false);
         } catch (err) {
@@ -214,9 +212,7 @@ export default function Upload(props: Props) {
                 show={choiceModalView}
                 onHide={() => setChoiceModalView(false)}
                 uploadFiles={uploadFilesToNewCollections}
-                showCollectionCreateModal={() =>
-                    showCreateCollectionModal(fileAnalysisResult)
-                }
+                showCollectionCreateModal={() => showCreateCollectionModal(fileAnalysisResult)}
             />
             <UploadProgress
                 now={percentComplete}

+ 1 - 1
src/pages/gallery/components/UploadButton.tsx

@@ -11,7 +11,7 @@ const Wrapper = styled.div`
     min-height: 64px;
     right: 32px;
 `;
-function UploadButton({ openFileUploader }) {
+function UploadButton({openFileUploader}) {
     return (
         <Wrapper onClick={openFileUploader}>
             <svg

+ 26 - 24
src/pages/gallery/components/UploadProgress.tsx

@@ -1,6 +1,8 @@
 import React from 'react';
-import { Alert, Button, Modal, ProgressBar } from 'react-bootstrap';
-import { UPLOAD_STAGES } from 'services/uploadService';
+import {
+    Alert, Button, Modal, ProgressBar,
+} from 'react-bootstrap';
+import {UPLOAD_STAGES} from 'services/uploadService';
 import constants from 'utils/strings/constants';
 
 interface Props {
@@ -12,10 +14,10 @@ interface Props {
     show;
 }
 export default function UploadProgress(props: Props) {
-    let fileProgressStatuses = [];
+    const fileProgressStatuses = [];
     if (props.fileProgress) {
-        for (let [fileName, progress] of props.fileProgress) {
-            fileProgressStatuses.push({ fileName, progress });
+        for (const [fileName, progress] of props.fileProgress) {
+            fileProgressStatuses.push({fileName, progress});
         }
         fileProgressStatuses.sort((a, b) => {
             if (b.progress !== -1 && a.progress === -1) return 1;
@@ -25,9 +27,9 @@ export default function UploadProgress(props: Props) {
         <Modal
             show={props.show}
             onHide={
-                props.uploadStage !== UPLOAD_STAGES.FINISH
-                    ? () => null
-                    : props.closeModal
+                props.uploadStage !== UPLOAD_STAGES.FINISH ?
+                    () => null :
+                    props.closeModal
             }
             aria-labelledby="contained-modal-title-vcenter"
             centered
@@ -44,12 +46,12 @@ export default function UploadProgress(props: Props) {
                     }}
                 >
                     <h4>
-                        {props.uploadStage == UPLOAD_STAGES.UPLOADING
-                            ? props.fileCounter.total > 1 &&
+                        {props.uploadStage === UPLOAD_STAGES.UPLOADING ?
+                            props.fileCounter.total > 1 &&
                               constants.UPLOAD[props.uploadStage](
-                                  props.fileCounter
-                              )
-                            : constants.UPLOAD[props.uploadStage]}
+                                  props.fileCounter,
+                              ) :
+                            constants.UPLOAD[props.uploadStage]}
                     </h4>
                 </div>
                 {props.now === 100 ? (
@@ -62,7 +64,7 @@ export default function UploadProgress(props: Props) {
                     <ProgressBar
                         now={props.now}
                         animated
-                        variant={'upload-progress-bar'}
+                        variant="upload-progress-bar"
                     />
                 )}
                 {fileProgressStatuses?.length > 0 && (
@@ -73,23 +75,23 @@ export default function UploadProgress(props: Props) {
                             maxHeight: '250px',
                         }}
                     >
-                        {fileProgressStatuses.map(({ fileName, progress }) => (
-                            <li style={{ marginTop: '12px' }}>
-                                {props.now === 100
-                                    ? fileName
-                                    : constants.FILE_UPLOAD_PROGRESS(
-                                          fileName,
-                                          progress
-                                      )}
+                        {fileProgressStatuses.map(({fileName, progress}) => (
+                            <li key={fileName} style={{marginTop: '12px'}}>
+                                {props.now === 100 ?
+                                    fileName :
+                                    constants.FILE_UPLOAD_PROGRESS(
+                                        fileName,
+                                        progress,
+                                    )}
                             </li>
                         ))}
                     </ul>
                 )}
                 {props.now === 100 && (
-                    <Modal.Footer style={{ border: 'none' }}>
+                    <Modal.Footer style={{border: 'none'}}>
                         <Button
                             variant="outline-secondary"
-                            style={{ width: '100%' }}
+                            style={{width: '100%'}}
                             onClick={props.closeModal}
                         >
                             {constants.CLOSE}

+ 75 - 88
src/pages/gallery/index.tsx

@@ -1,6 +1,6 @@
-import React, { useEffect, useRef, useState } from 'react';
-import { useRouter } from 'next/router';
-import { clearKeys, getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
+import React, {useEffect, useRef, useState} from 'react';
+import {useRouter} from 'next/router';
+import {clearKeys, getKey, SESSION_KEYS} from 'utils/storage/sessionStorage';
 import {
     File,
     getLocalFiles,
@@ -9,8 +9,6 @@ import {
 } from 'services/fileService';
 import styled from 'styled-components';
 import LoadingBar from 'react-top-loading-bar';
-import Collections from './components/Collections';
-import Upload from './components/Upload';
 import {
     Collection,
     syncCollections,
@@ -21,40 +19,41 @@ import {
     getNonEmptyCollections,
 } from 'services/collectionService';
 import constants from 'utils/strings/constants';
-import { Alert } from 'react-bootstrap';
 import billingService from 'services/billingService';
-import PlanSelector from './components/PlanSelector';
-import { checkSubscriptionPurchase } from 'utils/billingUtil';
+import {checkSubscriptionPurchase} from 'utils/billingUtil';
 
 import FullScreenDropZone from 'components/FullScreenDropZone';
 import Sidebar from 'components/Sidebar';
-import UploadButton from './components/UploadButton';
-import { checkConnectivity } from 'utils/common';
+import {checkConnectivity} from 'utils/common';
 import {
     isFirstLogin,
     justSignedUp,
     setIsFirstLogin,
     setJustSignedUp,
 } from 'utils/storage';
-import { isTokenValid, logoutUser } from 'services/userService';
-import AlertBanner from './components/AlertBanner';
-import MessageDialog, { MessageAttributes } from 'components/MessageDialog';
-import { useDropzone } from 'react-dropzone';
+import {isTokenValid, logoutUser} from 'services/userService';
+import MessageDialog, {MessageAttributes} from 'components/MessageDialog';
+import {useDropzone} from 'react-dropzone';
 import EnteSpinner from 'components/EnteSpinner';
-import CollectionNamer, {
-    CollectionNamerAttributes,
-} from './components/CollectionNamer';
+import {LoadingOverlay} from 'components/LoadingOverlay';
+import PhotoFrame from 'components/PhotoFrame';
+import {getSelectedFileIds} from 'utils/file';
+import {addFilesToCollection} from 'utils/collection';
+import {errorCodes} from 'utils/common/errorUtil';
+import SearchBar, {DateValue} from 'components/SearchBar';
+import {Bbox} from 'services/searchService';
+import SelectedFileOptions from './components/SelectedFileOptions';
 import CollectionSelector, {
     CollectionSelectorAttributes,
 } from './components/CollectionSelector';
-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';
-import { errorCodes } from 'utils/common/errorUtil';
-import SearchBar, { DateValue } from 'components/SearchBar';
-import { Bbox } from 'services/searchService';
+import CollectionNamer, {
+    CollectionNamerAttributes,
+} from './components/CollectionNamer';
+import AlertBanner from './components/AlertBanner';
+import UploadButton from './components/UploadButton';
+import PlanSelector from './components/PlanSelector';
+import Upload from './components/Upload';
+import Collections from './components/Collections';
 
 export enum FILE_TYPE {
     IMAGE,
@@ -100,25 +99,22 @@ export interface SearchStats {
 export default function Gallery() {
     const router = useRouter();
     const [collections, setCollections] = useState<Collection[]>([]);
-    const [collectionsAndTheirLatestFile, setCollectionsAndTheirLatestFile] =
-        useState<CollectionAndItsLatestFile[]>([]);
+    const [collectionsAndTheirLatestFile, setCollectionsAndTheirLatestFile] = useState<CollectionAndItsLatestFile[]>([]);
     const [files, setFiles] = useState<File[]>(null);
     const [favItemIds, setFavItemIds] = useState<Set<number>>();
     const [bannerMessage, setBannerMessage] = useState<string>(null);
     const [sinceTime, setSinceTime] = useState(0);
     const [isFirstLoad, setIsFirstLoad] = useState(false);
     const [isFirstFetch, setIsFirstFetch] = useState(false);
-    const [selected, setSelected] = useState<selectedState>({ count: 0 });
+    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);
-    const [collectionSelectorAttributes, setCollectionSelectorAttributes] =
-        useState<CollectionSelectorAttributes>(null);
+    const [collectionSelectorAttributes, setCollectionSelectorAttributes] = useState<CollectionSelectorAttributes>(null);
     const [collectionSelectorView, setCollectionSelectorView] = useState(false);
 
-    const [collectionNamerAttributes, setCollectionNamerAttributes] =
-        useState<CollectionNamerAttributes>(null);
+    const [collectionNamerAttributes, setCollectionNamerAttributes] = useState<CollectionNamerAttributes>(null);
     const [collectionNamerView, setCollectionNamerView] = useState(false);
     const [search, setSearch] = useState<Search>({
         date: null,
@@ -158,13 +154,12 @@ export default function Gallery() {
             const collections = await getLocalCollections();
             const nonEmptyCollections = getNonEmptyCollections(
                 collections,
-                files
+                files,
+            );
+            const collectionsAndTheirLatestFile = await getCollectionsAndTheirLatestFile(
+                nonEmptyCollections,
+                files,
             );
-            const collectionsAndTheirLatestFile =
-                await getCollectionsAndTheirLatestFile(
-                    nonEmptyCollections,
-                    files
-                );
             setFiles(files);
             setCollections(nonEmptyCollections);
             setCollectionsAndTheirLatestFile(collectionsAndTheirLatestFile);
@@ -182,7 +177,7 @@ export default function Gallery() {
     useEffect(() => setDialogView(true), [dialogMessage]);
     useEffect(
         () => setCollectionSelectorView(true),
-        [collectionSelectorAttributes]
+        [collectionSelectorAttributes],
     );
     useEffect(() => setCollectionNamerView(true), [collectionNamerAttributes]);
 
@@ -196,16 +191,15 @@ export default function Gallery() {
             await billingService.updatePlans();
             await billingService.syncSubscription();
             const collections = await syncCollections();
-            const { files, isUpdated } = await syncFiles(collections);
+            const {files, isUpdated} = await syncFiles(collections);
             const nonEmptyCollections = getNonEmptyCollections(
                 collections,
-                files
+                files,
+            );
+            const collectionAndItsLatestFile = await getCollectionsAndTheirLatestFile(
+                nonEmptyCollections,
+                files,
             );
-            const collectionAndItsLatestFile =
-                await getCollectionsAndTheirLatestFile(
-                    nonEmptyCollections,
-                    files
-                );
             const favItemIds = await getFavItemIds(files);
             setCollections(nonEmptyCollections);
             if (isUpdated) {
@@ -216,40 +210,40 @@ export default function Gallery() {
             setSinceTime(new Date().getTime());
         } catch (e) {
             switch (e.message) {
-                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: 'success',
-                        },
-                        nonClosable: true,
-                    });
-                    break;
-                case errorCodes.ERR_NO_INTERNET_CONNECTION:
-                    setBannerMessage(constants.NO_INTERNET_CONNECTION);
-                    break;
-                case errorCodes.ERR_KEY_MISSING:
-                    clearKeys();
-                    router.push('/credentials');
-                    break;
+            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: 'success',
+                    },
+                    nonClosable: true,
+                });
+                break;
+            case errorCodes.ERR_NO_INTERNET_CONNECTION:
+                setBannerMessage(constants.NO_INTERNET_CONNECTION);
+                break;
+            case errorCodes.ERR_KEY_MISSING:
+                clearKeys();
+                router.push('/credentials');
+                break;
             }
         } finally {
             loadingBar.current?.complete();
         }
     };
 
-    const clearSelection = function () {
-        setSelected({ count: 0 });
+    const clearSelection = function() {
+        setSelected({count: 0});
     };
 
     const selectCollection = (id?: number) => {
         const href = `/gallery?collection=${id || ''}`;
-        router.push(href, undefined, { shallow: true });
+        router.push(href, undefined, {shallow: true});
     };
 
     if (!files) {
@@ -257,7 +251,7 @@ export default function Gallery() {
     }
     const addToCollectionHelper = (
         collectionName: string,
-        collection: Collection
+        collection: Collection,
     ) => {
         loadingBar.current?.continuousStart();
         addFilesToCollection(
@@ -268,32 +262,25 @@ export default function Gallery() {
             syncWithRemote,
             selectCollection,
             collectionName,
-            collection
+            collection,
         );
     };
 
-    const showCreateCollectionModal = () =>
-        setCollectionNamerAttributes({
-            title: constants.CREATE_COLLECTION,
-            buttonText: constants.CREATE,
-            autoFilledName: '',
-            callback: (collectionName) =>
-                addToCollectionHelper(collectionName, null),
-        });
+    const showCreateCollectionModal = () => setCollectionNamerAttributes({
+        title: constants.CREATE_COLLECTION,
+        buttonText: constants.CREATE,
+        autoFilledName: '',
+        callback: (collectionName) => addToCollectionHelper(collectionName, null),
+    });
 
     const deleteFileHelper = () => {
         loadingBar.current?.continuousStart();
         deleteFiles(
             getSelectedFileIds(selected),
             clearSelection,
-            syncWithRemote
+            syncWithRemote,
         );
     };
-    const updateFiles = (files: File[]) => {
-        setFiles(files);
-        setSinceTime(new Date().getTime());
-        selectCollection(null);
-    };
 
     const updateSearch = (search: Search) => {
         setSearch(search);
@@ -325,7 +312,7 @@ export default function Gallery() {
             />
             <AlertBanner bannerMessage={bannerMessage} />
             <MessageDialog
-                size={'lg'}
+                size="lg"
                 show={dialogView}
                 onHide={() => setDialogView(false)}
                 attributes={dialogMessage}
@@ -374,7 +361,7 @@ export default function Gallery() {
                 }
                 closeCollectionSelector={setCollectionSelectorView.bind(
                     null,
-                    false
+                    false,
                 )}
                 setLoading={setLoading}
                 setCollectionNamerAttributes={setCollectionNamerAttributes}

+ 13 - 13
src/pages/generate/index.tsx

@@ -1,18 +1,18 @@
-import React, { useState, useEffect } from 'react';
+import React, {useState, useEffect} from 'react';
 import constants from 'utils/strings/constants';
-import { logoutUser, putAttributes } from 'services/userService';
-import { getData, LS_KEYS, setData } from 'utils/storage/localStorage';
-import { useRouter } from 'next/router';
-import { getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
+import {logoutUser, putAttributes} from 'services/userService';
+import {getData, LS_KEYS, setData} from 'utils/storage/localStorage';
+import {useRouter} from 'next/router';
+import {getKey, SESSION_KEYS} from 'utils/storage/sessionStorage';
 import {
     setSessionKeys,
     generateAndSaveIntermediateKeyAttributes,
     generateKeyAttributes,
 } from 'utils/crypto';
 import SetPasswordForm from 'components/SetPasswordForm';
-import { setJustSignedUp } from 'utils/storage';
+import {setJustSignedUp} from 'utils/storage';
 import RecoveryKeyModal from 'components/RecoveryKeyModal';
-import { KeyAttributes } from 'types';
+import {KeyAttributes} from 'types';
 import Container from 'components/Container';
 import EnteSpinner from 'components/EnteSpinner';
 
@@ -22,7 +22,7 @@ export interface KEK {
     memLimit: number;
 }
 
-export default function Generate(props) {
+export default function Generate() {
     const [token, setToken] = useState<string>();
     const router = useRouter();
     const [recoverModalView, setRecoveryModalView] = useState(false);
@@ -32,7 +32,7 @@ export default function Generate(props) {
             setLoading(true);
             const key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
             const keyAttributes: KeyAttributes = getData(
-                LS_KEYS.ORIGINAL_KEY_ATTRIBUTES
+                LS_KEYS.ORIGINAL_KEY_ATTRIBUTES,
             );
             router.prefetch('/gallery');
             const user = getData(LS_KEYS.USER);
@@ -45,7 +45,7 @@ export default function Generate(props) {
                 try {
                     await putAttributes(user.token, keyAttributes);
                 } catch (e) {
-                    //ignore
+                    // ignore
                 }
                 setData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES, null);
                 setRecoveryModalView(true);
@@ -59,15 +59,15 @@ export default function Generate(props) {
 
     const onSubmit = async (passphrase, setFieldError) => {
         try {
-            const { keyAttributes, masterKey } = await generateKeyAttributes(
-                passphrase
+            const {keyAttributes, masterKey} = await generateKeyAttributes(
+                passphrase,
             );
 
             await putAttributes(token, keyAttributes);
             await generateAndSaveIntermediateKeyAttributes(
                 passphrase,
                 keyAttributes,
-                masterKey
+                masterKey,
             );
             await setSessionKeys(masterKey);
             setJustSignedUp(true);

+ 15 - 14
src/pages/index.tsx

@@ -1,16 +1,17 @@
-import React, { useState, useEffect } from 'react';
-import { useRouter } from 'next/router';
+import React, {useState, useEffect} from 'react';
+import {useRouter} from 'next/router';
 import Card from 'react-bootstrap/Card';
 import Form from 'react-bootstrap/Form';
 import FormControl from 'react-bootstrap/FormControl';
 import Button from 'react-bootstrap/Button';
 import constants from 'utils/strings/constants';
-import { Formik, FormikHelpers } from 'formik';
+import {Formik, FormikHelpers} from 'formik';
 import * as Yup from 'yup';
-import { getOtt } from 'services/userService';
+import {getOtt} from 'services/userService';
 import Container from 'components/Container';
-import { setData, LS_KEYS, getData } from 'utils/storage/localStorage';
+import {setData, LS_KEYS, getData} from 'utils/storage/localStorage';
 import SubmitButton from 'components/SubmitButton';
+
 interface formValues {
     email: string;
 }
@@ -29,13 +30,13 @@ export default function Home() {
     }, []);
 
     const loginUser = async (
-        { email }: formValues,
-        { setFieldError }: FormikHelpers<formValues>
+        {email}: formValues,
+        {setFieldError}: FormikHelpers<formValues>,
     ) => {
         try {
             setLoading(true);
             await getOtt(email);
-            setData(LS_KEYS.USER, { email });
+            setData(LS_KEYS.USER, {email});
             router.push('/verify');
         } catch (e) {
             setFieldError('email', `${constants.UNKNOWN_ERROR} ${e.message}`);
@@ -49,13 +50,13 @@ export default function Home() {
 
     return (
         <Container>
-            <Card style={{ minWidth: '320px' }} className="text-center">
-                <Card.Body style={{ padding: '40px 30px' }}>
-                    <Card.Title style={{ marginBottom: '32px' }}>
+            <Card style={{minWidth: '320px'}} className="text-center">
+                <Card.Body style={{padding: '40px 30px'}}>
+                    <Card.Title style={{marginBottom: '32px'}}>
                         {constants.LOGIN}
                     </Card.Title>
                     <Formik<formValues>
-                        initialValues={{ email: '' }}
+                        initialValues={{email: ''}}
                         validationSchema={Yup.object().shape({
                             email: Yup.string()
                                 .email(constants.EMAIL_ERROR)
@@ -80,9 +81,9 @@ export default function Home() {
                                         value={values.email}
                                         onChange={handleChange('email')}
                                         isInvalid={Boolean(
-                                            touched.email && errors.email
+                                            touched.email && errors.email,
                                         )}
-                                        autoFocus={true}
+                                        autoFocus
                                         disabled={loading}
                                     />
                                     <FormControl.Feedback type="invalid">

+ 11 - 11
src/pages/recover/index.tsx

@@ -1,14 +1,14 @@
-import React, { useEffect, useState } from 'react';
+import React, {useEffect, useState} from 'react';
 
 import constants from 'utils/strings/constants';
-import { getData, LS_KEYS } from 'utils/storage/localStorage';
-import { useRouter } from 'next/router';
-import { KeyAttributes } from 'types';
-import CryptoWorker, { setSessionKeys } from 'utils/crypto';
+import {getData, LS_KEYS} from 'utils/storage/localStorage';
+import {useRouter} from 'next/router';
+import {KeyAttributes} from 'types';
+import CryptoWorker, {setSessionKeys} from 'utils/crypto';
 import SingleInputForm from 'components/SingleInputForm';
 import MessageDialog from 'components/MessageDialog';
 import Container from 'components/Container';
-import { Card, Button } from 'react-bootstrap';
+import {Card, Button} from 'react-bootstrap';
 
 export default function Recover() {
     const router = useRouter();
@@ -30,10 +30,10 @@ export default function Recover() {
     const recover = async (recoveryKey: string, setFieldError) => {
         try {
             const cryptoWorker = await new CryptoWorker();
-            let masterKey: string = await cryptoWorker.decryptB64(
+            const masterKey: string = await cryptoWorker.decryptB64(
                 keyAttributes.masterKeyEncryptedWithRecoveryKey,
                 keyAttributes.masterKeyDecryptionNonce,
-                await cryptoWorker.fromHex(recoveryKey)
+                await cryptoWorker.fromHex(recoveryKey),
             );
             setSessionKeys(masterKey);
             router.push('/changePassword');
@@ -47,11 +47,11 @@ export default function Recover() {
         <>
             <Container>
                 <Card
-                    style={{ minWidth: '320px', padding: '40px 30px' }}
+                    style={{minWidth: '320px', padding: '40px 30px'}}
                     className="text-center"
                 >
                     <Card.Body>
-                        <Card.Title style={{ marginBottom: '24px' }}>
+                        <Card.Title style={{marginBottom: '24px'}}>
                             {constants.RECOVER_ACCOUNT}
                         </Card.Title>
                         <SingleInputForm
@@ -81,7 +81,7 @@ export default function Recover() {
                 </Card>
             </Container>
             <MessageDialog
-                size={'lg'}
+                size="lg"
                 show={messageDialogView}
                 onHide={() => SetMessageDialogView(false)}
                 attributes={{

+ 21 - 25
src/pages/signup/index.tsx

@@ -1,22 +1,22 @@
-import React, { useState, useEffect } from 'react';
-import { useRouter } from 'next/router';
+import React, {useState, useEffect} from 'react';
+import {useRouter} from 'next/router';
 import Card from 'react-bootstrap/Card';
 import Form from 'react-bootstrap/Form';
 import FormControl from 'react-bootstrap/FormControl';
 import constants from 'utils/strings/constants';
-import { Formik, FormikHelpers } from 'formik';
+import {Formik, FormikHelpers} from 'formik';
 import * as Yup from 'yup';
-import { getOtt } from 'services/userService';
+import {getOtt} from 'services/userService';
 import Container from 'components/Container';
-import { setData, LS_KEYS, getData } from 'utils/storage/localStorage';
+import {setData, LS_KEYS, getData} from 'utils/storage/localStorage';
 import SubmitButton from 'components/SubmitButton';
-import { Button } from 'react-bootstrap';
+import {Button} from 'react-bootstrap';
 import {
     generateAndSaveIntermediateKeyAttributes,
     generateKeyAttributes,
     setSessionKeys,
 } from 'utils/crypto';
-import { setJustSignedUp } from 'utils/storage';
+import {setJustSignedUp} from 'utils/storage';
 
 interface FormValues {
     email: string;
@@ -28,7 +28,6 @@ export default function SignUp() {
     const [loading, setLoading] = useState(false);
     const router = useRouter();
     const [acceptTerms, setAcceptTerms] = useState(false);
-    const [understood, setUnderstood] = useState(false);
     useEffect(() => {
         router.prefetch('/verify');
         const user = getData(LS_KEYS.USER);
@@ -38,25 +37,24 @@ export default function SignUp() {
     }, []);
 
     const registerUser = async (
-        { email, passphrase, confirm }: FormValues,
-        { setFieldError }: FormikHelpers<FormValues>
+        {email, passphrase, confirm}: FormValues,
+        {setFieldError}: FormikHelpers<FormValues>,
     ) => {
         setLoading(true);
         try {
-            setData(LS_KEYS.USER, { email });
+            setData(LS_KEYS.USER, {email});
             await getOtt(email);
         } catch (e) {
             setFieldError('email', `${constants.UNKNOWN_ERROR} ${e.message}`);
         }
         try {
             if (passphrase === confirm) {
-                const { keyAttributes, masterKey } =
-                    await generateKeyAttributes(passphrase);
+                const {keyAttributes, masterKey} = await generateKeyAttributes(passphrase);
                 setData(LS_KEYS.ORIGINAL_KEY_ATTRIBUTES, keyAttributes);
                 await generateAndSaveIntermediateKeyAttributes(
                     passphrase,
                     keyAttributes,
-                    masterKey
+                    masterKey,
                 );
 
                 await setSessionKeys(masterKey);
@@ -74,9 +72,9 @@ export default function SignUp() {
 
     return (
         <Container>
-            <Card style={{ width: '400px' }} className="text-center">
-                <Card.Body style={{ padding: '40px 30px' }}>
-                    <Card.Title style={{ marginBottom: '20px' }}>
+            <Card style={{width: '400px'}} className="text-center">
+                <Card.Body style={{padding: '40px 30px'}}>
+                    <Card.Title style={{marginBottom: '20px'}}>
                         {constants.SIGN_UP}
                     </Card.Title>
                     <Formik<FormValues>
@@ -90,7 +88,7 @@ export default function SignUp() {
                                 .email(constants.EMAIL_ERROR)
                                 .required(constants.REQUIRED),
                             passphrase: Yup.string().required(
-                                constants.REQUIRED
+                                constants.REQUIRED,
                             ),
                             confirm: Yup.string().required(constants.REQUIRED),
                         })}
@@ -113,9 +111,9 @@ export default function SignUp() {
                                         value={values.email}
                                         onChange={handleChange('email')}
                                         isInvalid={Boolean(
-                                            touched.email && errors.email
+                                            touched.email && errors.email,
                                         )}
-                                        autoFocus={true}
+                                        autoFocus
                                         disabled={loading}
                                     />
                                     <FormControl.Feedback type="invalid">
@@ -130,7 +128,7 @@ export default function SignUp() {
                                         onChange={handleChange('passphrase')}
                                         isInvalid={Boolean(
                                             touched.passphrase &&
-                                                errors.passphrase
+                                                errors.passphrase,
                                         )}
                                         disabled={loading}
                                     />
@@ -147,7 +145,7 @@ export default function SignUp() {
                                         value={values.confirm}
                                         onChange={handleChange('confirm')}
                                         isInvalid={Boolean(
-                                            touched.confirm && errors.confirm
+                                            touched.confirm && errors.confirm,
                                         )}
                                         disabled={loading}
                                     />
@@ -164,9 +162,7 @@ export default function SignUp() {
                                 >
                                     <Form.Check
                                         checked={acceptTerms}
-                                        onChange={(e) =>
-                                            setAcceptTerms(e.target.checked)
-                                        }
+                                        onChange={(e) => setAcceptTerms(e.target.checked)}
                                         type="checkbox"
                                         label={constants.TERMS_AND_CONDITIONS()}
                                     />

+ 18 - 26
src/pages/verify/index.tsx

@@ -1,13 +1,11 @@
-import React, { useState, useEffect } from 'react';
+import React, {useState, useEffect} from 'react';
 import Container from 'components/Container';
 import Card from 'react-bootstrap/Card';
 import Form from 'react-bootstrap/Form';
-import Button from 'react-bootstrap/Button';
 import constants from 'utils/strings/constants';
-import styled from 'styled-components';
-import { LS_KEYS, getData, setData } from 'utils/storage/localStorage';
-import { useRouter } from 'next/router';
-import { Formik, FormikHelpers } from 'formik';
+import {LS_KEYS, getData, setData} from 'utils/storage/localStorage';
+import {useRouter} from 'next/router';
+import {Formik, FormikHelpers} from 'formik';
 import * as Yup from 'yup';
 import {
     verifyOtt,
@@ -16,15 +14,9 @@ import {
     clearFiles,
     isTokenValid,
 } from 'services/userService';
-import { setIsFirstLogin } from 'utils/storage';
+import {setIsFirstLogin} from 'utils/storage';
 import SubmitButton from 'components/SubmitButton';
-import { clearKeys } from 'utils/storage/sessionStorage';
-
-const Image = styled.img`
-    width: 350px;
-    margin-bottom: 20px;
-    max-width: 100%;
-`;
+import {clearKeys} from 'utils/storage/sessionStorage';
 
 interface formValues {
     ott: string;
@@ -57,8 +49,8 @@ export default function Verify() {
     }, []);
 
     const onSubmit = async (
-        { ott }: formValues,
-        { setFieldError }: FormikHelpers<formValues>
+        {ott}: formValues,
+        {setFieldError}: FormikHelpers<formValues>,
     ) => {
         try {
             setLoading(true);
@@ -69,7 +61,7 @@ export default function Verify() {
                 token: resp.data.token,
                 id: resp.data.id,
             });
-            const { subscription, keyAttributes } = resp.data;
+            const {subscription, keyAttributes} = resp.data;
             keyAttributes && setData(LS_KEYS.KEY_ATTRIBUTES, keyAttributes);
             subscription && setData(LS_KEYS.SUBSCRIPTION, subscription);
             clearFiles();
@@ -92,7 +84,7 @@ export default function Verify() {
 
     const resendEmail = async () => {
         setResend(1);
-        const resp = await getOtt(email);
+        await getOtt(email);
         setResend(2);
         setTimeout(() => setResend(0), 3000);
     };
@@ -103,19 +95,19 @@ export default function Verify() {
 
     return (
         <Container>
-            <Card style={{ minWidth: '300px' }} className="text-center">
+            <Card style={{minWidth: '300px'}} className="text-center">
                 <Card.Body>
                     <Card.Title
-                        style={{ fontWeight: 'bold', marginBottom: '24px' }}
+                        style={{fontWeight: 'bold', marginBottom: '24px'}}
                     >
                         {constants.VERIFY_EMAIL}
                     </Card.Title>
-                    {constants.EMAIL_SENT({ email })}
+                    {constants.EMAIL_SENT({email})}
                     {constants.CHECK_INBOX}
                     <br />
                     <br />
                     <Formik<formValues>
-                        initialValues={{ ott: '' }}
+                        initialValues={{ott: ''}}
                         validationSchema={Yup.object().shape({
                             ott: Yup.string().required(constants.REQUIRED),
                         })}
@@ -138,11 +130,11 @@ export default function Verify() {
                                         value={values.ott}
                                         onChange={handleChange('ott')}
                                         isInvalid={Boolean(
-                                            touched.ott && errors.ott
+                                            touched.ott && errors.ott,
                                         )}
                                         placeholder={constants.ENTER_OTT}
                                         disabled={loading}
-                                        autoFocus={true}
+                                        autoFocus
                                     />
                                     <Form.Control.Feedback type="invalid">
                                         {errors.ott}
@@ -152,7 +144,7 @@ export default function Verify() {
                                     buttonText={constants.VERIFY}
                                     loading={loading}
                                 />
-                                <div style={{ marginTop: '24px' }}>
+                                <div style={{marginTop: '24px'}}>
                                     {resend === 0 && (
                                         <a href="#" onClick={resendEmail}>
                                             {constants.RESEND_MAIL}
@@ -164,7 +156,7 @@ export default function Verify() {
                                     {resend === 2 && (
                                         <span>{constants.SENT}</span>
                                     )}
-                                    <div style={{ marginTop: '8px' }}>
+                                    <div style={{marginTop: '8px'}}>
                                         <a href="#" onClick={logoutUser}>
                                             {constants.CHANGE_EMAIL}
                                         </a>

+ 14 - 16
src/services/HTTPService.ts

@@ -1,5 +1,4 @@
-import axios, { AxiosRequestConfig } from 'axios';
-import { clearData } from 'utils/storage/localStorage';
+import axios, {AxiosRequestConfig} from 'axios';
 
 interface IHTTPHeaders {
     [headerKey: string]: any;
@@ -15,18 +14,17 @@ interface IQueryPrams {
 class HTTPService {
     constructor() {
         axios.interceptors.response.use(
-            (response) => {
-                return Promise.resolve(response);
-            },
+            (response) => Promise.resolve(response),
             (err) => {
                 if (!err.response) {
                     return Promise.reject(err);
                 }
-                const response = err.response;
+                const {response} = err;
                 return Promise.reject(response);
-            }
+            },
         );
     }
+
     /**
      * header object to be append to all api calls.
      */
@@ -78,7 +76,7 @@ class HTTPService {
             ...this.headers,
             ...config.headers,
         };
-        return await axios({ ...config, ...customConfig });
+        return await axios({...config, ...customConfig});
     }
 
     /**
@@ -88,7 +86,7 @@ class HTTPService {
         url: string,
         params?: IQueryPrams,
         headers?: IHTTPHeaders,
-        customConfig?: any
+        customConfig?: any,
     ) {
         return this.request(
             {
@@ -97,7 +95,7 @@ class HTTPService {
                 params,
                 url,
             },
-            customConfig
+            customConfig,
         );
     }
 
@@ -109,7 +107,7 @@ class HTTPService {
         data?: any,
         params?: IQueryPrams,
         headers?: IHTTPHeaders,
-        customConfig?: any
+        customConfig?: any,
     ) {
         return this.request(
             {
@@ -119,7 +117,7 @@ class HTTPService {
                 params,
                 url,
             },
-            customConfig
+            customConfig,
         );
     }
 
@@ -131,7 +129,7 @@ class HTTPService {
         data: any,
         params?: IQueryPrams,
         headers?: IHTTPHeaders,
-        customConfig?: any
+        customConfig?: any,
     ) {
         return this.request(
             {
@@ -141,7 +139,7 @@ class HTTPService {
                 params,
                 url,
             },
-            customConfig
+            customConfig,
         );
     }
 
@@ -153,7 +151,7 @@ class HTTPService {
         data: any,
         params?: IQueryPrams,
         headers?: IHTTPHeaders,
-        customConfig?: any
+        customConfig?: any,
     ) {
         return this.request(
             {
@@ -163,7 +161,7 @@ class HTTPService {
                 params,
                 url,
             },
-            customConfig
+            customConfig,
         );
     }
 }

+ 47 - 39
src/services/billingService.ts

@@ -1,12 +1,13 @@
-import { getEndpoint } from 'utils/common/apiUtil';
+import {getEndpoint} from 'utils/common/apiUtil';
+import {getStripePublishableKey, getToken} from 'utils/common/key';
+import {checkConnectivity, runningInBrowser} from 'utils/common/';
+import {setData, LS_KEYS} from 'utils/storage/localStorage';
+import {convertBytesToGBs} from 'utils/billingUtil';
+import {loadStripe, Stripe} from '@stripe/stripe-js';
+import {SUBSCRIPTION_VERIFICATION_ERROR} from 'utils/common/errorUtil';
 import HTTPService from './HTTPService';
+
 const ENDPOINT = getEndpoint();
-import { getStripePublishableKey, getToken } from 'utils/common/key';
-import { checkConnectivity, runningInBrowser } from 'utils/common/';
-import { setData, LS_KEYS } from 'utils/storage/localStorage';
-import { convertBytesToGBs } from 'utils/billingUtil';
-import { loadStripe, Stripe } from '@stripe/stripe-js';
-import { SUBSCRIPTION_VERIFICATION_ERROR } from 'utils/common/errorUtil';
 
 export enum PAYMENT_INTENT_STATUS {
     SUCCESS = 'success',
@@ -43,9 +44,10 @@ export interface SubscriptionUpdateResponse {
 export const FREE_PLAN = 'free';
 class billingService {
     private stripe: Stripe;
+
     constructor() {
         try {
-            let publishableKey = getStripePublishableKey();
+            const publishableKey = getStripePublishableKey();
             const main = async () => {
                 this.stripe = await loadStripe(publishableKey);
             };
@@ -54,15 +56,17 @@ class billingService {
             console.warn(e);
         }
     }
+
     public async updatePlans() {
         try {
             const response = await HTTPService.get(`${ENDPOINT}/billing/plans`);
-            const plans = response.data['plans'];
+            const {plans} = response.data;
             setData(LS_KEYS.PLANS, plans);
         } catch (e) {
             console.error('failed to get plans', e);
         }
     }
+
     public async syncSubscription() {
         try {
             const response = await HTTPService.get(
@@ -70,19 +74,20 @@ class billingService {
                 null,
                 {
                     'X-Auth-Token': getToken(),
-                }
+                },
             );
-            const subscription = response.data['subscription'];
+            const {subscription} = response.data;
             setData(LS_KEYS.SUBSCRIPTION, subscription);
         } catch (e) {
-            console.error(`failed to get user's subscription details`, e);
+            console.error('failed to get user\'s subscription details', e);
         }
     }
+
     public async buyPaidSubscription(productID) {
         try {
             const response = await this.createCheckoutSession(productID);
             await this.stripe.redirectToCheckout({
-                sessionId: response.data['sessionID'],
+                sessionId: response.data.sessionID,
             });
         } catch (e) {
             console.error('unable to buy subscription', e);
@@ -100,26 +105,28 @@ class billingService {
                 null,
                 {
                     'X-Auth-Token': getToken(),
-                }
+                },
             );
-            const result: SubscriptionUpdateResponse = response.data['result'];
+            const {result} = response.data;
             switch (result.status) {
-                case PAYMENT_INTENT_STATUS.SUCCESS:
-                    // subscription updated successfully
-                    // no-op required
-                    break;
-                case PAYMENT_INTENT_STATUS.REQUIRE_PAYMENT_METHOD:
-                    throw new Error(
-                        PAYMENT_INTENT_STATUS.REQUIRE_PAYMENT_METHOD
-                    );
-                case PAYMENT_INTENT_STATUS.REQUIRE_ACTION:
-                    const { error } = await this.stripe.confirmCardPayment(
-                        result.clientSecret
+            case PAYMENT_INTENT_STATUS.SUCCESS:
+                // subscription updated successfully
+                // no-op required
+                break;
+            case PAYMENT_INTENT_STATUS.REQUIRE_PAYMENT_METHOD:
+                throw new Error(
+                    PAYMENT_INTENT_STATUS.REQUIRE_PAYMENT_METHOD,
+                );
+            case PAYMENT_INTENT_STATUS.REQUIRE_ACTION:
+                {
+                    const {error} = await this.stripe.confirmCardPayment(
+                        result.clientSecret,
                     );
                     if (error) {
                         throw error;
                     }
-                    break;
+                }
+                break;
             }
         } catch (e) {
             console.error(e);
@@ -140,9 +147,9 @@ class billingService {
                 null,
                 {
                     'X-Auth-Token': getToken(),
-                }
+                },
             );
-            const subscription = response.data['subscription'];
+            const {subscription} = response.data;
             setData(LS_KEYS.SUBSCRIPTION, subscription);
         } catch (e) {
             console.error(e);
@@ -158,9 +165,9 @@ class billingService {
                 null,
                 {
                     'X-Auth-Token': getToken(),
-                }
+                },
             );
-            const subscription = response.data['subscription'];
+            const {subscription} = response.data;
             setData(LS_KEYS.SUBSCRIPTION, subscription);
         } catch (e) {
             console.error(e);
@@ -176,12 +183,12 @@ class billingService {
             },
             {
                 'X-Auth-Token': getToken(),
-            }
+            },
         );
     }
 
     public async verifySubscription(
-        sessionID: string = null
+        sessionID: string = null,
     ): Promise<Subscription> {
         try {
             const response = await HTTPService.post(
@@ -194,9 +201,9 @@ class billingService {
                 null,
                 {
                     'X-Auth-Token': getToken(),
-                }
+                },
             );
-            const subscription = response.data['subscription'];
+            const {subscription} = response.data;
             setData(LS_KEYS.SUBSCRIPTION, subscription);
             return subscription;
         } catch (err) {
@@ -212,22 +219,23 @@ class billingService {
                 null,
                 {
                     'X-Auth-Token': getToken(),
-                }
+                },
             );
-            window.location.href = response.data['url'];
+            window.location.href = response.data.url;
         } catch (e) {
             console.error('unable to get customer portal url');
             throw e;
         }
     }
+
     public async getUsage() {
         try {
             const response = await HTTPService.get(
                 `${ENDPOINT}/billing/usage`,
-                { startTime: 0, endTime: Date.now() * 1000 },
+                {startTime: 0, endTime: Date.now() * 1000},
                 {
                     'X-Auth-Token': getToken(),
-                }
+                },
             );
             return convertBytesToGBs(response.data.usage);
         } catch (e) {

+ 83 - 98
src/services/collectionService.ts

@@ -1,15 +1,15 @@
-import { getEndpoint } from 'utils/common/apiUtil';
-import { getData, LS_KEYS } from 'utils/storage/localStorage';
-import { File } from './fileService';
+import {getEndpoint} from 'utils/common/apiUtil';
+import {getData, LS_KEYS} from 'utils/storage/localStorage';
 import localForage from 'utils/storage/localForage';
 
-import HTTPService from './HTTPService';
-import { B64EncryptionResult } from './uploadService';
-import { getActualKey, getToken } from 'utils/common/key';
-import { getPublicKey, User } from './userService';
+import {getActualKey, getToken} from 'utils/common/key';
 import CryptoWorker from 'utils/crypto';
-import { SetDialogMessage } from 'components/MessageDialog';
+import {SetDialogMessage} from 'components/MessageDialog';
 import constants from 'utils/strings/constants';
+import {getPublicKey, User} from './userService';
+import {B64EncryptionResult} from './uploadService';
+import HTTPService from './HTTPService';
+import {File} from './fileService';
 
 const ENDPOINT = getEndpoint();
 
@@ -51,36 +51,35 @@ export interface CollectionAndItsLatestFile {
 
 const getCollectionWithSecrets = async (
     collection: Collection,
-    masterKey: string
+    masterKey: string,
 ) => {
     const worker = await new CryptoWorker();
     const userID = getData(LS_KEYS.USER).id;
     let decryptedKey: string;
-    if (collection.owner.id == userID) {
+    if (collection.owner.id === userID) {
         decryptedKey = await worker.decryptB64(
             collection.encryptedKey,
             collection.keyDecryptionNonce,
-            masterKey
+            masterKey,
         );
     } else {
         const keyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES);
         const secretKey = await worker.decryptB64(
             keyAttributes.encryptedSecretKey,
             keyAttributes.secretKeyDecryptionNonce,
-            masterKey
+            masterKey,
         );
         decryptedKey = await worker.boxSealOpen(
             collection.encryptedKey,
             keyAttributes.publicKey,
-            secretKey
+            secretKey,
         );
     }
-    collection.name =
-        collection.name ||
+    collection.name = collection.name ||
         (await worker.decryptToUTF8(
             collection.encryptedName,
             collection.nameDecryptionNonce,
-            decryptedKey
+            decryptedKey,
         ));
     return {
         ...collection,
@@ -91,15 +90,15 @@ const getCollectionWithSecrets = async (
 const getCollections = async (
     token: string,
     sinceTime: number,
-    key: string
+    key: string,
 ): Promise<Collection[]> => {
     try {
         const resp = await HTTPService.get(
             `${ENDPOINT}/collections`,
             {
-                sinceTime: sinceTime,
+                sinceTime,
             },
-            { 'X-Auth-Token': token }
+            {'X-Auth-Token': token},
         );
         const promises: Promise<Collection>[] = resp.data.collections.map(
             async (collection: Collection) => {
@@ -110,17 +109,16 @@ const getCollections = async (
                 try {
                     collectionWithSecrets = await getCollectionWithSecrets(
                         collection,
-                        key
+                        key,
                     );
+                    return collectionWithSecrets;
                 } catch (e) {
                     console.error(
                         `decryption failed for collection with id=${collection.id}`,
-                        e
+                        e,
                     );
-                } finally {
-                    return collectionWithSecrets;
                 }
-            }
+            },
         );
         return await Promise.all(promises);
     } catch (e) {
@@ -130,35 +128,26 @@ const getCollections = async (
 };
 
 export const getLocalCollections = async (): Promise<Collection[]> => {
-    const collections: Collection[] =
-        (await localForage.getItem(COLLECTIONS)) ?? [];
+    const collections: Collection[] = (await localForage.getItem(COLLECTIONS)) ?? [];
     return collections;
 };
 
-export const getCollectionUpdationTime = async (): Promise<number> => {
-    return (await localForage.getItem<number>(COLLECTION_UPDATION_TIME)) ?? 0;
-};
+export const getCollectionUpdationTime = async (): Promise<number> => (await localForage.getItem<number>(COLLECTION_UPDATION_TIME)) ?? 0;
 
 export const syncCollections = async () => {
     const localCollections = await getLocalCollections();
     const lastCollectionUpdationTime = await getCollectionUpdationTime();
     const token = getToken();
-    let key;
-    try {
-        key = await getActualKey();
-    } catch (e) {
-        throw e;
-    }
-    const updatedCollections =
-        (await getCollections(token, lastCollectionUpdationTime, key)) ?? [];
-    if (updatedCollections.length == 0) {
+    const key = await getActualKey();
+    const updatedCollections = (await getCollections(token, lastCollectionUpdationTime, key)) ?? [];
+    if (updatedCollections.length === 0) {
         return localCollections;
     }
     const allCollectionsInstances = [
         ...localCollections,
         ...updatedCollections,
     ];
-    var latestCollectionsInstances = new Map<number, Collection>();
+    const latestCollectionsInstances = new Map<number, Collection>();
     allCollectionsInstances.forEach((collection) => {
         if (
             !latestCollectionsInstances.has(collection.id) ||
@@ -169,10 +158,11 @@ export const syncCollections = async () => {
         }
     });
 
-    let collections: Collection[] = [],
-        updationTime = await localForage.getItem<number>(
-            COLLECTION_UPDATION_TIME
-        );
+    const collections: Collection[] = [];
+    let updationTime = await localForage.getItem<number>(
+        COLLECTION_UPDATION_TIME,
+    );
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
     for (const [_, collection] of latestCollectionsInstances) {
         if (!collection.isDeleted) {
             collections.push(collection);
@@ -188,7 +178,7 @@ export const syncCollections = async () => {
 
 export const getCollectionsAndTheirLatestFile = (
     collections: Collection[],
-    files: File[]
+    files: File[],
 ): CollectionAndItsLatestFile[] => {
     const latestFile = new Map<number, File>();
 
@@ -197,13 +187,13 @@ export const getCollectionsAndTheirLatestFile = (
             latestFile.set(file.collectionID, file);
         }
     });
-    let collectionsAndTheirLatestFile: CollectionAndItsLatestFile[] = [];
+    const collectionsAndTheirLatestFile: CollectionAndItsLatestFile[] = [];
     const userID = getData(LS_KEYS.USER)?.id;
 
     for (const collection of collections) {
         if (
-            collection.owner.id != userID ||
-            collection.type == CollectionType.favorites
+            collection.owner.id !== userID ||
+            collection.type === CollectionType.favorites
         ) {
             continue;
         }
@@ -216,27 +206,25 @@ export const getCollectionsAndTheirLatestFile = (
 };
 
 export const getFavItemIds = async (files: File[]): Promise<Set<number>> => {
-    let favCollection = await getFavCollection();
+    const favCollection = await getFavCollection();
     if (!favCollection) return new Set();
 
     return new Set(
         files
             .filter((file) => file.collectionID === favCollection.id)
-            .map((file): number => file.id)
+            .map((file): number => file.id),
     );
 };
 
-export const createAlbum = async (albumName: string) => {
-    return createCollection(albumName, CollectionType.album);
-};
+export const createAlbum = async (albumName: string) => createCollection(albumName, CollectionType.album);
 
 export const createCollection = async (
     collectionName: string,
-    type: CollectionType
+    type: CollectionType,
 ): Promise<Collection> => {
     try {
         const existingCollections = await getLocalCollections();
-        for (let collection of existingCollections) {
+        for (const collection of existingCollections) {
             if (collection.name === collectionName) {
                 return collection;
             }
@@ -250,14 +238,14 @@ export const createCollection = async (
             nonce: keyDecryptionNonce,
         }: B64EncryptionResult = await worker.encryptToB64(
             collectionKey,
-            encryptionKey
+            encryptionKey,
         );
         const {
             encryptedData: encryptedName,
             nonce: nameDecryptionNonce,
         }: B64EncryptionResult = await worker.encryptUTF8(
             collectionName,
-            collectionKey
+            collectionKey,
         );
         const newCollection: Collection = {
             id: null,
@@ -274,11 +262,11 @@ export const createCollection = async (
         };
         let createdCollection: Collection = await postCollection(
             newCollection,
-            token
+            token,
         );
         createdCollection = await getCollectionWithSecrets(
             createdCollection,
-            encryptionKey
+            encryptionKey,
         );
         return createdCollection;
     } catch (e) {
@@ -289,14 +277,14 @@ export const createCollection = async (
 
 const postCollection = async (
     collectionData: Collection,
-    token: string
+    token: string,
 ): Promise<Collection> => {
     try {
         const response = await HTTPService.post(
             `${ENDPOINT}/collections`,
             collectionData,
             null,
-            { 'X-Auth-Token': token }
+            {'X-Auth-Token': token},
         );
         return response.data.collection;
     } catch (e) {
@@ -309,7 +297,7 @@ export const addToFavorites = async (file: File) => {
     if (!favCollection) {
         favCollection = await createCollection(
             'Favorites',
-            CollectionType.favorites
+            CollectionType.favorites,
         );
         await localForage.setItem(FAV_COLLECTION, favCollection);
     }
@@ -317,42 +305,41 @@ export const addToFavorites = async (file: File) => {
 };
 
 export const removeFromFavorites = async (file: File) => {
-    let favCollection = await getFavCollection();
+    const favCollection = await getFavCollection();
     await removeFromCollection(favCollection, [file]);
 };
 
 export const addToCollection = async (
     collection: Collection,
-    files: File[]
+    files: File[],
 ) => {
     try {
-        const params = new Object();
+        const params = {};
         const worker = await new CryptoWorker();
         const token = getToken();
-        params['collectionID'] = collection.id;
+        params.collectionID = collection.id;
         await Promise.all(
             files.map(async (file) => {
                 file.collectionID = collection.id;
-                const newEncryptedKey: B64EncryptionResult =
-                    await worker.encryptToB64(file.key, collection.key);
+                const newEncryptedKey: B64EncryptionResult = await worker.encryptToB64(file.key, collection.key);
                 file.encryptedKey = newEncryptedKey.encryptedData;
                 file.keyDecryptionNonce = newEncryptedKey.nonce;
-                if (params['files'] == undefined) {
-                    params['files'] = [];
+                if (params.files === undefined) {
+                    params.files = [];
                 }
-                params['files'].push({
+                params.files.push({
                     id: file.id,
                     encryptedKey: file.encryptedKey,
                     keyDecryptionNonce: file.keyDecryptionNonce,
                 });
                 return file;
-            })
+            }),
         );
         await HTTPService.post(
             `${ENDPOINT}/collections/add-files`,
             params,
             null,
-            { 'X-Auth-Token': token }
+            {'X-Auth-Token': token},
         );
     } catch (e) {
         console.error('Add to collection Failed ', e);
@@ -360,22 +347,22 @@ export const addToCollection = async (
 };
 const removeFromCollection = async (collection: Collection, files: File[]) => {
     try {
-        const params = new Object();
+        const params = {};
         const token = getToken();
-        params['collectionID'] = collection.id;
+        params.collectionID = collection.id;
         await Promise.all(
             files.map(async (file) => {
-                if (params['fileIDs'] == undefined) {
-                    params['fileIDs'] = [];
+                if (params.fileIDs === undefined) {
+                    params.fileIDs = [];
                 }
-                params['fileIDs'].push(file.id);
-            })
+                params.fileIDs.push(file.id);
+            }),
         );
         await HTTPService.post(
             `${ENDPOINT}/collections/remove-files`,
             params,
             null,
-            { 'X-Auth-Token': token }
+            {'X-Auth-Token': token},
         );
     } catch (e) {
         console.error('remove from collection failed ', e);
@@ -386,7 +373,7 @@ export const deleteCollection = async (
     collectionID: number,
     syncWithRemote: () => Promise<void>,
     redirectToAll: () => void,
-    setDialogMessage: SetDialogMessage
+    setDialogMessage: SetDialogMessage,
 ) => {
     try {
         const token = getToken();
@@ -395,7 +382,7 @@ export const deleteCollection = async (
             `${ENDPOINT}/collections/${collectionID}`,
             null,
             null,
-            { 'X-Auth-Token': token }
+            {'X-Auth-Token': token},
         );
         await syncWithRemote();
         redirectToAll();
@@ -404,14 +391,14 @@ export const deleteCollection = async (
         setDialogMessage({
             title: constants.ERROR,
             content: constants.DELETE_COLLECTION_FAILED,
-            close: { variant: 'danger' },
+            close: {variant: 'danger'},
         });
     }
 };
 
 export const renameCollection = async (
     collection: Collection,
-    newCollectionName: string
+    newCollectionName: string,
 ) => {
     const token = getToken();
     const worker = await new CryptoWorker();
@@ -420,7 +407,7 @@ export const renameCollection = async (
         nonce: nameDecryptionNonce,
     }: B64EncryptionResult = await worker.encryptUTF8(
         newCollectionName,
-        collection.key
+        collection.key,
     );
     const collectionRenameRequest = {
         collectionID: collection.id,
@@ -433,12 +420,12 @@ export const renameCollection = async (
         null,
         {
             'X-Auth-Token': token,
-        }
+        },
     );
 };
 export const shareCollection = async (
     collection: Collection,
-    withUserEmail: string
+    withUserEmail: string,
 ) => {
     try {
         const worker = await new CryptoWorker();
@@ -447,12 +434,12 @@ export const shareCollection = async (
         const publicKey: string = await getPublicKey(withUserEmail);
         const encryptedKey: string = await worker.boxSeal(
             collection.key,
-            publicKey
+            publicKey,
         );
         const shareCollectionRequest = {
             collectionID: collection.id,
             email: withUserEmail,
-            encryptedKey: encryptedKey,
+            encryptedKey,
         };
         await HTTPService.post(
             `${ENDPOINT}/collections/share`,
@@ -460,7 +447,7 @@ export const shareCollection = async (
             null,
             {
                 'X-Auth-Token': token,
-            }
+            },
         );
     } catch (e) {
         console.error('share collection failed ', e);
@@ -470,7 +457,7 @@ export const shareCollection = async (
 
 export const unshareCollection = async (
     collection: Collection,
-    withUserEmail: string
+    withUserEmail: string,
 ) => {
     try {
         const token = getToken();
@@ -484,7 +471,7 @@ export const unshareCollection = async (
             null,
             {
                 'X-Auth-Token': token,
-            }
+            },
         );
     } catch (e) {
         console.error('unshare collection failed ', e);
@@ -494,8 +481,8 @@ export const unshareCollection = async (
 
 export const getFavCollection = async () => {
     const collections = await getLocalCollections();
-    for (let collection of collections) {
-        if (collection.type == CollectionType.favorites) {
+    for (const collection of collections) {
+        if (collection.type === CollectionType.favorites) {
             return collection;
         }
     }
@@ -504,13 +491,11 @@ export const getFavCollection = async () => {
 
 export const getNonEmptyCollections = (
     collections: Collection[],
-    files: File[]
+    files: File[],
 ) => {
     const nonEmptyCollectionsIds = new Set<number>();
-    for (let file of files) {
+    for (const file of files) {
         nonEmptyCollectionsIds.add(file.collectionID);
     }
-    return collections.filter((collection) =>
-        nonEmptyCollectionsIds.has(collection.id)
-    );
+    return collections.filter((collection) => nonEmptyCollectionsIds.has(collection.id));
 };

+ 79 - 82
src/services/downloadManager.ts

@@ -1,12 +1,13 @@
-import { getToken } from 'utils/common/key';
-import { File } from './fileService';
-import HTTPService from './HTTPService';
-import { getFileUrl, getThumbnailUrl } from 'utils/common/apiUtil';
+import {getToken} from 'utils/common/key';
+import {getFileUrl, getThumbnailUrl} from 'utils/common/apiUtil';
 import CryptoWorker from 'utils/crypto';
-import { fileIsHEIC, convertHEIC2JPEG } from 'utils/file';
+import {fileIsHEIC, convertHEIC2JPEG} from 'utils/file';
+import HTTPService from './HTTPService';
+import {File} from './fileService';
 
 class DownloadManager {
     private fileDownloads = new Map<number, Promise<string>>();
+
     private thumbnailDownloads = new Map<number, Promise<string>>();
 
     public async getPreview(file: File) {
@@ -25,19 +26,19 @@ class DownloadManager {
                     const resp = await HTTPService.get(
                         getThumbnailUrl(file.id),
                         null,
-                        { 'X-Auth-Token': token },
-                        { responseType: 'arraybuffer' }
+                        {'X-Auth-Token': token},
+                        {responseType: 'arraybuffer'},
                     );
                     const worker = await new CryptoWorker();
                     const decrypted: any = await worker.decryptThumbnail(
                         new Uint8Array(resp.data),
                         await worker.fromB64(file.thumbnail.decryptionHeader),
-                        file.key
+                        file.key,
                     );
                     try {
                         await cache.put(
                             file.id.toString(),
-                            new Response(new Blob([decrypted]))
+                            new Response(new Blob([decrypted])),
                         );
                     } catch (e) {
                         // TODO: handle storage full exception.
@@ -59,7 +60,7 @@ class DownloadManager {
                 const download = (async () => {
                     const fileStream = await this.downloadFile(file);
                     return URL.createObjectURL(
-                        await new Response(fileStream).blob()
+                        await new Response(fileStream).blob(),
                     );
                 })();
                 this.fileDownloads.set(file.id, download);
@@ -80,13 +81,13 @@ class DownloadManager {
             const resp = await HTTPService.get(
                 getFileUrl(file.id),
                 null,
-                { 'X-Auth-Token': token },
-                { responseType: 'arraybuffer' }
+                {'X-Auth-Token': token},
+                {responseType: 'arraybuffer'},
             );
             const decrypted: any = await worker.decryptFile(
                 new Uint8Array(resp.data),
                 await worker.fromB64(file.file.decryptionHeader),
-                file.key
+                file.key,
             );
             let decryptedBlob = new Blob([decrypted]);
 
@@ -96,84 +97,80 @@ class DownloadManager {
             return new ReadableStream({
                 async start(controller: ReadableStreamDefaultController) {
                     controller.enqueue(
-                        new Uint8Array(await decryptedBlob.arrayBuffer())
+                        new Uint8Array(await decryptedBlob.arrayBuffer()),
                     );
                     controller.close();
                 },
             });
-        } else {
-            const resp = await fetch(getFileUrl(file.id), {
-                headers: {
-                    'X-Auth-Token': token,
-                },
-            });
-            const reader = resp.body.getReader();
-            const stream = new ReadableStream({
-                async start(controller) {
-                    const decryptionHeader = await worker.fromB64(
-                        file.file.decryptionHeader
-                    );
-                    const fileKey = await worker.fromB64(file.key);
-                    let {
-                        pullState,
-                        decryptionChunkSize,
-                        tag,
-                    } = await worker.initDecryption(decryptionHeader, fileKey);
-                    let data = new Uint8Array();
-                    // The following function handles each data chunk
-                    function push() {
-                        // "done" is a Boolean and value a "Uint8Array"
-                        reader.read().then(async ({ done, value }) => {
-                            // Is there more data to read?
-                            if (!done) {
-                                const buffer = new Uint8Array(
-                                    data.byteLength + value.byteLength
+        }
+        const resp = await fetch(getFileUrl(file.id), {
+            headers: {
+                'X-Auth-Token': token,
+            },
+        });
+        const reader = resp.body.getReader();
+        const stream = new ReadableStream({
+            async start(controller) {
+                const decryptionHeader = await worker.fromB64(
+                    file.file.decryptionHeader,
+                );
+                const fileKey = await worker.fromB64(file.key);
+                const {
+                    pullState,
+                    decryptionChunkSize,
+                } = await worker.initDecryption(decryptionHeader, fileKey);
+                let data = new Uint8Array();
+                // The following function handles each data chunk
+                function push() {
+                    // "done" is a Boolean and value a "Uint8Array"
+                    reader.read().then(async ({done, value}) => {
+                        // Is there more data to read?
+                        if (!done) {
+                            const buffer = new Uint8Array(
+                                data.byteLength + value.byteLength,
+                            );
+                            buffer.set(new Uint8Array(data), 0);
+                            buffer.set(
+                                new Uint8Array(value),
+                                data.byteLength,
+                            );
+                            if (buffer.length > decryptionChunkSize) {
+                                const fileData = buffer.slice(
+                                    0,
+                                    decryptionChunkSize,
                                 );
-                                buffer.set(new Uint8Array(data), 0);
-                                buffer.set(
-                                    new Uint8Array(value),
-                                    data.byteLength
+                                const {
+                                    decryptedData,
+                                } = await worker.decryptChunk(
+                                    fileData,
+                                    pullState,
                                 );
-                                if (buffer.length > decryptionChunkSize) {
-                                    const fileData = buffer.slice(
-                                        0,
-                                        decryptionChunkSize
-                                    );
-                                    const {
-                                        decryptedData,
-                                        newTag,
-                                    } = await worker.decryptChunk(
-                                        fileData,
-                                        pullState
-                                    );
-                                    controller.enqueue(decryptedData);
-                                    tag = newTag;
-                                    data = buffer.slice(decryptionChunkSize);
-                                } else {
-                                    data = buffer;
-                                }
-                                push();
+                                controller.enqueue(decryptedData);
+                                data = buffer.slice(decryptionChunkSize);
                             } else {
-                                if (data) {
-                                    const {
-                                        decryptedData,
-                                    } = await worker.decryptChunk(
-                                        data,
-                                        pullState
-                                    );
-                                    controller.enqueue(decryptedData);
-                                    data = null;
-                                }
-                                controller.close();
+                                data = buffer;
                             }
-                        });
-                    }
+                            push();
+                        } else {
+                            if (data) {
+                                const {
+                                    decryptedData,
+                                } = await worker.decryptChunk(
+                                    data,
+                                    pullState,
+                                );
+                                controller.enqueue(decryptedData);
+                                data = null;
+                            }
+                            controller.close();
+                        }
+                    });
+                }
 
-                    push();
-                },
-            });
-            return stream;
-        }
+                push();
+            },
+        });
+        return stream;
     }
 }
 

+ 22 - 19
src/services/exportService.ts

@@ -1,7 +1,7 @@
-import { runningInBrowser } from 'utils/common';
-import { Collection } from './collectionService';
+import {runningInBrowser} from 'utils/common';
+import {Collection} from './collectionService';
 import downloadManager from './downloadManager';
-import { File } from './fileService';
+import {File} from './fileService';
 
 enum ExportNotification {
     START = 'export started',
@@ -10,8 +10,10 @@ enum ExportNotification {
     ABORT = 'export aborted',
 }
 class ExportService {
-    ElectronAPIs: any = runningInBrowser() && window['ElectronAPIs'];
+    ElectronAPIs: any = runningInBrowser() && window.ElectronAPIs;
+
     exportInProgress: Promise<void> = null;
+
     abortExport: boolean = false;
 
     async exportFiles(files: File[], collections: Collection[]) {
@@ -22,6 +24,7 @@ class ExportService {
         this.exportInProgress = this.fileExporter(files, collections);
         return this.exportInProgress;
     }
+
     async fileExporter(files: File[], collections: Collection[]) {
         try {
             const dir = await this.ElectronAPIs.selectRootDirectory();
@@ -30,44 +33,43 @@ class ExportService {
                 return;
             }
             const exportedFiles: Set<string> = await this.ElectronAPIs.getExportedFiles(
-                dir
+                dir,
             );
-            this.ElectronAPIs.showOnTray(`starting export`);
+            this.ElectronAPIs.showOnTray('starting export');
             this.ElectronAPIs.registerStopExportListener(
-                () => (this.abortExport = true)
+                () => (this.abortExport = true),
             );
             const collectionIDMap = new Map<number, string>();
-            for (let collection of collections) {
-                let collectionFolderPath = `${dir}/${
+            for (const collection of collections) {
+                const collectionFolderPath = `${dir}/${
                     collection.id
                 }_${this.sanitizeName(collection.name)}`;
                 await this.ElectronAPIs.checkExistsAndCreateCollectionDir(
-                    collectionFolderPath
+                    collectionFolderPath,
                 );
                 collectionIDMap.set(collection.id, collectionFolderPath);
             }
             this.ElectronAPIs.sendNotification(ExportNotification.START);
-            for (let [index, file] of files.entries()) {
+            for (const [index, file] of files.entries()) {
                 if (this.abortExport) {
                     break;
                 }
                 const uid = `${file.id}_${this.sanitizeName(
-                    file.metadata.title
+                    file.metadata.title,
                 )}`;
-                const filePath =
-                    collectionIDMap.get(file.collectionID) + '/' + uid;
+                const filePath = `${collectionIDMap.get(file.collectionID)}/${uid}`;
                 if (!exportedFiles.has(filePath)) {
                     await this.downloadAndSave(file, filePath);
                     this.ElectronAPIs.updateExportRecord(dir, filePath);
                 }
                 this.ElectronAPIs.showOnTray(
-                    `exporting file ${index + 1} / ${files.length}`
+                    `exporting file ${index + 1} / ${files.length}`,
                 );
             }
             this.ElectronAPIs.sendNotification(
-                this.abortExport
-                    ? ExportNotification.ABORT
-                    : ExportNotification.FINISH
+                this.abortExport ?
+                    ExportNotification.ABORT :
+                    ExportNotification.FINISH,
             );
         } catch (e) {
             console.error(e);
@@ -83,9 +85,10 @@ class ExportService {
         this.ElectronAPIs.saveStreamToDisk(path, fileStream);
         this.ElectronAPIs.saveFileToDisk(
             `${path}.json`,
-            JSON.stringify(file.metadata, null, 2)
+            JSON.stringify(file.metadata, null, 2),
         );
     }
+
     private sanitizeName(name) {
         return name.replaceAll('/', '_').replaceAll(' ', '_');
     }

+ 27 - 30
src/services/fileService.ts

@@ -1,13 +1,12 @@
-import { getEndpoint } from 'utils/common/apiUtil';
-import HTTPService from './HTTPService';
+import {getEndpoint} from 'utils/common/apiUtil';
 import localForage from 'utils/storage/localForage';
 
-import { Collection } from './collectionService';
-import { DataStream, MetadataObject } from './uploadService';
 import CryptoWorker from 'utils/crypto';
-import { getToken } from 'utils/common/key';
-import { selectedState } from 'pages/gallery';
-import { ErrorHandler } from 'utils/common/errorUtil';
+import {getToken} from 'utils/common/key';
+import {ErrorHandler} from 'utils/common/errorUtil';
+import {DataStream, MetadataObject} from './uploadService';
+import {Collection} from './collectionService';
+import HTTPService from './HTTPService';
 
 const ENDPOINT = getEndpoint();
 const DIFF_LIMIT: number = 2500;
@@ -40,7 +39,7 @@ export interface File {
 }
 
 export const getLocalFiles = async () => {
-    let files: Array<File> = (await localForage.getItem<File[]>(FILES)) || [];
+    const files: Array<File> = (await localForage.getItem<File[]>(FILES)) || [];
     return files;
 };
 
@@ -48,24 +47,22 @@ export const syncFiles = async (collections: Collection[]) => {
     const localFiles = await getLocalFiles();
     let isUpdated = false;
     let files = await removeDeletedCollectionFiles(collections, localFiles);
-    if (files.length != localFiles.length) {
+    if (files.length !== localFiles.length) {
         isUpdated = true;
         await localForage.setItem('files', files);
     }
-    for (let collection of collections) {
+    for (const collection of collections) {
         if (!getToken()) {
             continue;
         }
-        const lastSyncTime =
-            (await localForage.getItem<number>(`${collection.id}-time`)) ?? 0;
+        const lastSyncTime = (await localForage.getItem<number>(`${collection.id}-time`)) ?? 0;
         if (collection.updationTime === lastSyncTime) {
             continue;
         }
         isUpdated = true;
-        let fetchedFiles =
-            (await getFiles(collection, lastSyncTime, DIFF_LIMIT)) ?? [];
+        const fetchedFiles = (await getFiles(collection, lastSyncTime, DIFF_LIMIT)) ?? [];
         files.push(...fetchedFiles);
-        var latestVersionFiles = new Map<string, File>();
+        const latestVersionFiles = new Map<string, File>();
         files.forEach((file) => {
             const uid = `${file.collectionID}-${file.id}`;
             if (
@@ -76,6 +73,7 @@ export const syncFiles = async (collections: Collection[]) => {
             }
         });
         files = [];
+        // eslint-disable-next-line @typescript-eslint/no-unused-vars
         for (const [_, file] of latestVersionFiles) {
             if (file.isDeleted) {
                 continue;
@@ -83,12 +81,12 @@ export const syncFiles = async (collections: Collection[]) => {
             files.push(file);
         }
         files = files.sort(
-            (a, b) => b.metadata.creationTime - a.metadata.creationTime
+            (a, b) => b.metadata.creationTime - a.metadata.creationTime,
         );
         await localForage.setItem('files', files);
         await localForage.setItem(
             `${collection.id}-time`,
-            collection.updationTime
+            collection.updationTime,
         );
     }
     return {
@@ -104,13 +102,12 @@ export const syncFiles = async (collections: Collection[]) => {
 export const getFiles = async (
     collection: Collection,
     sinceTime: number,
-    limit: number
+    limit: number,
 ): Promise<File[]> => {
     try {
         const worker = await new CryptoWorker();
         const decryptedFiles: File[] = [];
-        let time =
-            sinceTime ||
+        let time = sinceTime ||
             (await localForage.getItem<number>(`${collection.id}-time`)) ||
             0;
         let resp;
@@ -124,11 +121,11 @@ export const getFiles = async (
                 {
                     collectionID: collection.id,
                     sinceTime: time,
-                    limit: limit,
+                    limit,
                 },
                 {
                     'X-Auth-Token': token,
-                }
+                },
             );
 
             decryptedFiles.push(
@@ -138,13 +135,13 @@ export const getFiles = async (
                             file.key = await worker.decryptB64(
                                 file.encryptedKey,
                                 file.keyDecryptionNonce,
-                                collection.key
+                                collection.key,
                             );
                             file.metadata = await worker.decryptMetadata(file);
                         }
                         return file;
-                    }) as Promise<File>[]
-                ))
+                    }) as Promise<File>[],
+                )),
             );
 
             if (resp.data.diff.length) {
@@ -160,10 +157,10 @@ export const getFiles = async (
 
 const removeDeletedCollectionFiles = async (
     collections: Collection[],
-    files: File[]
+    files: File[],
 ) => {
     const syncedCollectionIds = new Set<number>();
-    for (let collection of collections) {
+    for (const collection of collections) {
         syncedCollectionIds.add(collection.id);
     }
     files = files.filter((file) => syncedCollectionIds.has(file.collectionID));
@@ -173,7 +170,7 @@ const removeDeletedCollectionFiles = async (
 export const deleteFiles = async (
     filesToDelete: number[],
     clearSelection: Function,
-    syncWithRemote: Function
+    syncWithRemote: Function,
 ) => {
     try {
         const token = getToken();
@@ -182,11 +179,11 @@ export const deleteFiles = async (
         }
         await HTTPService.post(
             `${ENDPOINT}/files/delete`,
-            { fileIDs: filesToDelete },
+            {fileIDs: filesToDelete},
             null,
             {
                 'X-Auth-Token': token,
-            }
+            },
         );
         clearSelection();
         syncWithRemote();

+ 23 - 29
src/services/searchService.ts

@@ -1,8 +1,8 @@
-import HTTPService from './HTTPService';
 import * as chrono from 'chrono-node';
-import { getEndpoint } from 'utils/common/apiUtil';
-import { getToken } from 'utils/common/key';
-import { DateValue, Suggestion, SuggestionType } from 'components/SearchBar';
+import {getEndpoint} from 'utils/common/apiUtil';
+import {getToken} from 'utils/common/key';
+import {DateValue, Suggestion, SuggestionType} from 'components/SearchBar';
+import HTTPService from './HTTPService';
 
 const ENDPOINT = getEndpoint();
 const DIGITS = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']);
@@ -11,17 +11,15 @@ export interface LocationSearchResponse {
     place: string;
     bbox: Bbox;
 }
-export const getMapboxToken = () => {
-    return process.env.NEXT_PUBLIC_MAPBOX_TOKEN;
-};
+export const getMapboxToken = () => process.env.NEXT_PUBLIC_MAPBOX_TOKEN;
 
 export function parseHumanDate(humanDate: string): DateValue[] {
     const date = chrono.parseDate(humanDate);
-    const date1 = chrono.parseDate(humanDate + ' 1');
-    if (date != null) {
+    const date1 = chrono.parseDate(`${humanDate} 1`);
+    if (date !== null) {
         const dates = [
-            { month: date.getMonth() },
-            { date: date.getDate(), month: date.getMonth() },
+            {month: date.getMonth()},
+            {date: date.getDate(), month: date.getMonth()},
         ];
         let reverse = false;
         humanDate.split('').forEach((c) => {
@@ -31,18 +29,16 @@ export function parseHumanDate(humanDate: string): DateValue[] {
         });
         if (reverse) {
             return dates.reverse();
-        } else {
-            return dates;
         }
-    } else if (date1) {
-        return [{ month: date1.getMonth() }];
-    } else {
-        return [];
+        return dates;
+    } if (date1) {
+        return [{month: date1.getMonth()}];
     }
+    return [];
 }
 
 export async function searchLocation(
-    searchPhrase: string
+    searchPhrase: string,
 ): Promise<LocationSearchResponse[]> {
     const resp = await HTTPService.get(
         `${ENDPOINT}/search/location`,
@@ -52,7 +48,7 @@ export async function searchLocation(
         },
         {
             'X-Auth-Token': getToken(),
-        }
+        },
     );
     return resp.data.results;
 }
@@ -61,44 +57,42 @@ export function getHolidaySuggestion(searchPhrase: string): Suggestion[] {
     return [
         {
             label: 'Christmas',
-            value: { month: 11, date: 25 },
+            value: {month: 11, date: 25},
             type: SuggestionType.DATE,
         },
         {
             label: 'Christmas Eve',
-            value: { month: 11, date: 24 },
+            value: {month: 11, date: 24},
             type: SuggestionType.DATE,
         },
         {
             label: 'New Year',
-            value: { month: 0, date: 1 },
+            value: {month: 0, date: 1},
             type: SuggestionType.DATE,
         },
         {
             label: 'New Year Eve',
-            value: { month: 11, date: 31 },
+            value: {month: 11, date: 31},
             type: SuggestionType.DATE,
         },
-    ].filter((suggestion) =>
-        suggestion.label.toLowerCase().includes(searchPhrase.toLowerCase())
-    );
+    ].filter((suggestion) => suggestion.label.toLowerCase().includes(searchPhrase.toLowerCase()));
 }
 
 export function getYearSuggestion(searchPhrase: string): Suggestion[] {
-    if (searchPhrase.length == 4) {
+    if (searchPhrase.length === 4) {
         try {
             const year = parseInt(searchPhrase);
             if (year >= 1970 && year <= new Date().getFullYear()) {
                 return [
                     {
                         label: searchPhrase,
-                        value: { year },
+                        value: {year},
                         type: SuggestionType.DATE,
                     },
                 ];
             }
         } catch (e) {
-            //ignore
+            // ignore
         }
     }
     return [];

+ 220 - 225
src/services/uploadService.ts

@@ -1,23 +1,24 @@
-import { getEndpoint } from 'utils/common/apiUtil';
-import HTTPService from './HTTPService';
+import {getEndpoint} from 'utils/common/apiUtil';
 import EXIF from 'exif-js';
-import { File, fileAttribute } from './fileService';
-import { Collection } from './collectionService';
-import { FILE_TYPE } from 'pages/gallery';
-import { checkConnectivity, WaitFor2Seconds } from 'utils/common';
+import {FILE_TYPE} from 'pages/gallery';
+import {checkConnectivity, WaitFor2Seconds} from 'utils/common';
 import {
     ErrorHandler,
     THUMBNAIL_GENERATION_FAILED,
 } from 'utils/common/errorUtil';
-import { ComlinkWorker, getDedicatedCryptoWorker } from 'utils/crypto';
+import {ComlinkWorker, getDedicatedCryptoWorker} from 'utils/crypto';
 import * as convert from 'xml-js';
-import { ENCRYPTION_CHUNK_SIZE } from 'types';
-import { getToken } from 'utils/common/key';
+import {ENCRYPTION_CHUNK_SIZE} from 'types';
+import {getToken} from 'utils/common/key';
 import {
     fileIsHEIC,
     convertHEIC2JPEG,
     sortFilesIntoCollections,
 } from 'utils/file';
+import {Collection} from './collectionService';
+import {File, fileAttribute} from './fileService';
+import HTTPService from './HTTPService';
+
 const ENDPOINT = getEndpoint();
 
 const THUMBNAIL_HEIGHT = 720;
@@ -34,7 +35,7 @@ const WEST_DIRECTION = 'W';
 const MIN_STREAM_FILE_SIZE = 20 * 1024 * 1024;
 const CHUNKS_COMBINED_FOR_UPLOAD = 5;
 const RANDOM_PERCENTAGE_PROGRESS_FOR_PUT = () => 90 + 10 * Math.random();
-const NULL_LOCATION: Location = { latitude: null, longitude: null };
+const NULL_LOCATION: Location = {latitude: null, longitude: null};
 const WAIT_TIME_THUMBNAIL_GENERATION = 30 * 1000;
 const FILE_UPLOAD_FAILED = -1;
 const FILE_UPLOAD_SKIPPED = -2;
@@ -59,7 +60,7 @@ export interface DataStream {
 }
 
 function isDataStream(object: any): object is DataStream {
-    return object.hasOwnProperty('stream');
+    return 'stream' in object;
 }
 interface EncryptionResult {
     file: fileAttribute;
@@ -124,21 +125,33 @@ export enum UPLOAD_STAGES {
 
 class UploadService {
     private cryptoWorkers = new Array<ComlinkWorker>(MAX_CONCURRENT_UPLOADS);
+
     private uploadURLs: UploadURL[] = [];
+
     private uploadURLFetchInProgress: Promise<any> = null;
+
     private perFileProgress: number;
+
     private filesCompleted: number;
+
     private totalFileCount: number;
+
     private fileProgress: Map<string, number>;
+
     private metadataMap: Map<string, Object>;
+
     private filesToBeUploaded: FileWithCollection[];
+
     private progressBarProps;
+
     private uploadErrors: Error[];
+
     private existingFilesCollectionWise: Map<number, File[]>;
+
     public async uploadFiles(
         filesWithCollectionToUpload: FileWithCollection[],
         existingFiles: File[],
-        progressBarProps
+        progressBarProps,
     ) {
         try {
             checkConnectivity();
@@ -149,16 +162,15 @@ class UploadService {
             this.uploadErrors = [];
             this.metadataMap = new Map<string, object>();
             this.progressBarProps = progressBarProps;
-            this.existingFilesCollectionWise =
-                sortFilesIntoCollections(existingFiles);
+            this.existingFilesCollectionWise = sortFilesIntoCollections(existingFiles);
             this.updateProgressBarUI();
 
-            let metadataFiles: globalThis.File[] = [];
-            let actualFiles: FileWithCollection[] = [];
+            const metadataFiles: globalThis.File[] = [];
+            const actualFiles: FileWithCollection[] = [];
             filesWithCollectionToUpload.forEach((fileWithCollection) => {
-                let file = fileWithCollection.file;
-                if (file?.name.substr(0, 1) == '.') {
-                    //ignore files with name starting with . (hidden files)
+                const {file} = fileWithCollection;
+                if (file?.name.substr(0, 1) === '.') {
+                    // ignore files with name starting with . (hidden files)
                     return;
                 }
                 if (
@@ -168,14 +180,14 @@ class UploadService {
                 ) {
                     actualFiles.push(fileWithCollection);
                 }
-                if (file.name.slice(-4) == TYPE_JSON) {
+                if (file.name.slice(-4) === TYPE_JSON) {
                     metadataFiles.push(fileWithCollection.file);
                 }
             });
             this.filesToBeUploaded = actualFiles;
 
             progressBarProps.setUploadStage(
-                UPLOAD_STAGES.READING_GOOGLE_METADATA_FILES
+                UPLOAD_STAGES.READING_GOOGLE_METADATA_FILES,
             );
             this.totalFileCount = metadataFiles.length;
             this.perFileProgress = 100 / metadataFiles.length;
@@ -209,8 +221,8 @@ class UploadService {
                     this.uploader(
                         await new this.cryptoWorkers[i].comlink(),
                         new FileReader(),
-                        this.filesToBeUploaded.pop()
-                    )
+                        this.filesToBeUploaded.pop(),
+                    ),
                 );
             }
             progressBarProps.setUploadStage(UPLOAD_STAGES.UPLOADING);
@@ -232,9 +244,9 @@ class UploadService {
     private async uploader(
         worker: any,
         reader: FileReader,
-        fileWithCollection: FileWithCollection
+        fileWithCollection: FileWithCollection,
     ) {
-        let { file: rawFile, collection } = fileWithCollection;
+        const {file: rawFile, collection} = fileWithCollection;
         this.fileProgress.set(rawFile.name, 0);
         this.updateProgressBarUI();
         try {
@@ -248,17 +260,16 @@ class UploadService {
                 this.fileProgress.delete(rawFile.name);
                 return;
             }
-            let { file: encryptedFile, fileKey: encryptedKey }: EncryptedFile =
-                await this.encryptFile(worker, file, collection.key);
+            let {file: encryptedFile, fileKey: encryptedKey}: EncryptedFile = await this.encryptFile(worker, file, collection.key);
             let backupedFile: BackupedFile = await this.uploadToBucket(
-                encryptedFile
+                encryptedFile,
             );
             file = null;
             encryptedFile = null;
             let uploadFile: uploadFile = this.getUploadFile(
                 collection,
                 backupedFile,
-                encryptedKey
+                encryptedKey,
             );
             encryptedKey = null;
             backupedFile = null;
@@ -268,7 +279,7 @@ class UploadService {
         } catch (e) {
             console.error('file upload failed with error', e);
             const error = new Error(
-                `Uploading Failed for File - ${rawFile.name}`
+                `Uploading Failed for File - ${rawFile.name}`,
             );
             this.uploadErrors.push(error);
             // set progress to -1 indicating that file upload failed but keep it to show in the file-upload list progress
@@ -281,23 +292,23 @@ class UploadService {
                 await this.uploader(
                     worker,
                     reader,
-                    this.filesToBeUploaded.pop()
+                    this.filesToBeUploaded.pop(),
                 );
             }
         }
     }
 
     private updateProgressBarUI() {
-        const { setPercentComplete, setFileCounter, setFileProgress } =
-            this.progressBarProps;
+        const {setPercentComplete, setFileCounter, setFileProgress} = this.progressBarProps;
         setFileCounter({
             finished: this.filesCompleted,
             total: this.totalFileCount,
         });
         let percentComplete = this.perFileProgress * this.filesCompleted;
         if (this.fileProgress) {
-            for (let [_, progress] of this.fileProgress) {
-                //filter  negative indicator values during percentComplete calculation
+            // eslint-disable-next-line @typescript-eslint/no-unused-vars
+            for (const [_, progress] of this.fileProgress) {
+                // filter  negative indicator values during percentComplete calculation
                 if (progress < 0) {
                     continue;
                 }
@@ -310,20 +321,20 @@ class UploadService {
 
     private fileAlreadyInCollection(
         newFile: FileInMemory,
-        collection: Collection
+        collection: Collection,
     ): boolean {
-        const collectionFiles =
-            this.existingFilesCollectionWise.get(collection.id) ?? [];
-        for (let existingFile of collectionFiles) {
+        const collectionFiles = this.existingFilesCollectionWise.get(collection.id) ?? [];
+        for (const existingFile of collectionFiles) {
             if (this.areFilesSame(existingFile.metadata, newFile.metadata)) {
                 return true;
             }
         }
         return false;
     }
+
     private areFilesSame(
         existingFile: MetadataObject,
-        newFile: MetadataObject
+        newFile: MetadataObject,
     ): boolean {
         if (
             existingFile.fileType === newFile.fileType &&
@@ -332,28 +343,27 @@ class UploadService {
             existingFile.title === newFile.title
         ) {
             return true;
-        } else {
-            return false;
         }
+        return false;
     }
 
     private async readFile(reader: FileReader, receivedFile: globalThis.File) {
         try {
             const thumbnail = await this.generateThumbnail(
                 reader,
-                receivedFile
+                receivedFile,
             );
 
             let fileType: FILE_TYPE;
             switch (receivedFile.type.split('/')[0]) {
-                case TYPE_IMAGE:
-                    fileType = FILE_TYPE.IMAGE;
-                    break;
-                case TYPE_VIDEO:
-                    fileType = FILE_TYPE.VIDEO;
-                    break;
-                default:
-                    fileType = FILE_TYPE.OTHERS;
+            case TYPE_IMAGE:
+                fileType = FILE_TYPE.IMAGE;
+                break;
+            case TYPE_VIDEO:
+                fileType = FILE_TYPE.VIDEO;
+                break;
+            default:
+                fileType = FILE_TYPE.OTHERS;
             }
             if (
                 fileType === FILE_TYPE.OTHERS &&
@@ -363,34 +373,31 @@ class UploadService {
                 fileType = FILE_TYPE.IMAGE;
             }
 
-            const { location, creationTime } = await this.getExifData(
+            const {location, creationTime} = await this.getExifData(
                 reader,
                 receivedFile,
-                fileType
+                fileType,
             );
             let receivedFileOriginalName = receivedFile.name;
             if (receivedFile.name.endsWith(EDITED_FILE_SUFFIX)) {
                 receivedFileOriginalName = receivedFile.name.slice(
                     0,
-                    -1 * EDITED_FILE_SUFFIX.length
+                    -1 * EDITED_FILE_SUFFIX.length,
                 );
             }
-            const metadata = Object.assign(
-                {
-                    title: receivedFile.name,
-                    creationTime:
+            const metadata = {
+                title: receivedFile.name,
+                creationTime:
                         creationTime || receivedFile.lastModified * 1000,
-                    modificationTime: receivedFile.lastModified * 1000,
-                    latitude: location?.latitude,
-                    longitude: location?.latitude,
-                    fileType,
-                },
-                this.metadataMap.get(receivedFileOriginalName)
-            );
-            const filedata =
-                receivedFile.size > MIN_STREAM_FILE_SIZE
-                    ? this.getFileStream(reader, receivedFile)
-                    : await this.getUint8ArrayView(reader, receivedFile);
+                modificationTime: receivedFile.lastModified * 1000,
+                latitude: location?.latitude,
+                longitude: location?.latitude,
+                fileType,
+                ...this.metadataMap.get(receivedFileOriginalName),
+            };
+            const filedata = receivedFile.size > MIN_STREAM_FILE_SIZE ?
+                this.getFileStream(reader, receivedFile) :
+                await this.getUint8ArrayView(reader, receivedFile);
 
             return {
                 filedata,
@@ -406,22 +413,19 @@ class UploadService {
     private async encryptFile(
         worker: any,
         file: FileInMemory,
-        encryptionKey: string
+        encryptionKey: string,
     ): Promise<EncryptedFile> {
         try {
-            const { key: fileKey, file: encryptedFiledata }: EncryptionResult =
-                isDataStream(file.filedata)
-                    ? await this.encryptFileStream(worker, file.filedata)
-                    : await worker.encryptFile(file.filedata);
+            const {key: fileKey, file: encryptedFiledata}: EncryptionResult = isDataStream(file.filedata) ?
+                await this.encryptFileStream(worker, file.filedata) :
+                await worker.encryptFile(file.filedata);
 
-            const { file: encryptedThumbnail }: EncryptionResult =
-                await worker.encryptThumbnail(file.thumbnail, fileKey);
-            const { file: encryptedMetadata }: EncryptionResult =
-                await worker.encryptMetadata(file.metadata, fileKey);
+            const {file: encryptedThumbnail}: EncryptionResult = await worker.encryptThumbnail(file.thumbnail, fileKey);
+            const {file: encryptedMetadata}: EncryptionResult = await worker.encryptMetadata(file.metadata, fileKey);
 
             const encryptedKey: B64EncryptionResult = await worker.encryptToB64(
                 fileKey,
-                encryptionKey
+                encryptionKey,
             );
 
             const result: EncryptedFile = {
@@ -441,21 +445,20 @@ class UploadService {
     }
 
     private async encryptFileStream(worker, fileData: DataStream) {
-        const { stream, chunkCount } = fileData;
+        const {stream, chunkCount} = fileData;
         const fileStreamReader = stream.getReader();
-        const { key, decryptionHeader, pushState } =
-            await worker.initChunkEncryption();
-        let ref = { pullCount: 1 };
+        const {key, decryptionHeader, pushState} = await worker.initChunkEncryption();
+        const ref = {pullCount: 1};
         const encryptedFileStream = new ReadableStream({
             async pull(controller) {
-                let { value } = await fileStreamReader.read();
+                const {value} = await fileStreamReader.read();
                 const encryptedFileChunk = await worker.encryptFileChunk(
                     value,
                     pushState,
-                    ref.pullCount === chunkCount
+                    ref.pullCount === chunkCount,
                 );
                 controller.enqueue(encryptedFileChunk);
-                if (ref.pullCount == chunkCount) {
+                if (ref.pullCount === chunkCount) {
                     controller.close();
                 }
                 ref.pullCount++;
@@ -465,41 +468,41 @@ class UploadService {
             key,
             file: {
                 decryptionHeader,
-                encryptedData: { stream: encryptedFileStream, chunkCount },
+                encryptedData: {stream: encryptedFileStream, chunkCount},
             },
         };
     }
 
     private async uploadToBucket(file: ProcessedFile): Promise<BackupedFile> {
         try {
-            let fileObjectKey, thumbnailObjectKey;
+            let fileObjectKey;
             if (isDataStream(file.file.encryptedData)) {
-                const { chunkCount, stream } = file.file.encryptedData;
+                const {chunkCount, stream} = file.file.encryptedData;
                 const uploadPartCount = Math.ceil(
-                    chunkCount / CHUNKS_COMBINED_FOR_UPLOAD
+                    chunkCount / CHUNKS_COMBINED_FOR_UPLOAD,
                 );
                 const filePartUploadURLs = await this.fetchMultipartUploadURLs(
-                    uploadPartCount
+                    uploadPartCount,
                 );
                 fileObjectKey = await this.putFileInParts(
                     filePartUploadURLs,
                     stream,
                     file.filename,
-                    uploadPartCount
+                    uploadPartCount,
                 );
             } else {
                 const fileUploadURL = await this.getUploadURL();
                 fileObjectKey = await this.putFile(
                     fileUploadURL,
                     file.file.encryptedData,
-                    file.filename
+                    file.filename,
                 );
             }
             const thumbnailUploadURL = await this.getUploadURL();
-            thumbnailObjectKey = await this.putFile(
+            const thumbnailObjectKey = await this.putFile(
                 thumbnailUploadURL,
                 file.thumbnail.encryptedData as Uint8Array,
-                null
+                null,
             );
 
             const backupedFile: BackupedFile = {
@@ -523,7 +526,7 @@ class UploadService {
     private getUploadFile(
         collection: Collection,
         backupedFile: BackupedFile,
-        fileKey: B64EncryptionResult
+        fileKey: B64EncryptionResult,
     ): uploadFile {
         const uploadFile: uploadFile = {
             collectionID: collection.id,
@@ -547,7 +550,7 @@ class UploadService {
                 null,
                 {
                     'X-Auth-Token': token,
-                }
+                },
             );
             return response.data;
         } catch (e) {
@@ -561,17 +564,16 @@ class UploadService {
             const metadataJSON: object = await new Promise(
                 (resolve, reject) => {
                     const reader = new FileReader();
-                    reader.onabort = () => reject('file reading was aborted');
-                    reader.onerror = () => reject('file reading has failed');
+                    reader.onabort = () => reject(new Error('file reading was aborted'));
+                    reader.onerror = () => reject(new Error('file reading has failed'));
                     reader.onload = () => {
-                        let result =
-                            typeof reader.result !== 'string'
-                                ? new TextDecoder().decode(reader.result)
-                                : reader.result;
+                        const result = typeof reader.result !== 'string' ?
+                            new TextDecoder().decode(reader.result) :
+                            reader.result;
                         resolve(JSON.parse(result));
                     };
                     reader.readAsText(receivedFile);
-                }
+                },
             );
 
             const metaDataObject = {};
@@ -579,57 +581,57 @@ class UploadService {
                 return;
             }
             if (
-                metadataJSON['photoTakenTime'] &&
-                metadataJSON['photoTakenTime']['timestamp']
+                metadataJSON.photoTakenTime &&
+                metadataJSON.photoTakenTime.timestamp
             ) {
-                metaDataObject['creationTime'] =
-                    metadataJSON['photoTakenTime']['timestamp'] * 1000000;
+                metaDataObject.creationTime = metadataJSON.photoTakenTime.timestamp * 1000000;
             }
             if (
-                metadataJSON['modificationTime'] &&
-                metadataJSON['modificationTime']['timestamp']
+                metadataJSON.modificationTime &&
+                metadataJSON.modificationTime.timestamp
             ) {
-                metaDataObject['modificationTime'] =
-                    metadataJSON['modificationTime']['timestamp'] * 1000000;
+                metaDataObject.modificationTime = metadataJSON.modificationTime.timestamp * 1000000;
             }
             let locationData = null;
             if (
-                metadataJSON['geoData'] &&
-                (metadataJSON['geoData']['latitude'] != 0.0 ||
-                    metadataJSON['geoData']['longitude'] != 0.0)
+                metadataJSON.geoData &&
+                (metadataJSON.geoData.latitude !== 0.0 ||
+                    metadataJSON.geoData.longitude !== 0.0)
             ) {
-                locationData = metadataJSON['geoData'];
+                locationData = metadataJSON.geoData;
             } else if (
-                metadataJSON['geoDataExif'] &&
-                (metadataJSON['geoDataExif']['latitude'] != 0.0 ||
-                    metadataJSON['geoDataExif']['longitude'] != 0.0)
+                metadataJSON.geoDataExif &&
+                (metadataJSON.geoDataExif.latitude !== 0.0 ||
+                    metadataJSON.geoDataExif.longitude !== 0.0)
             ) {
-                locationData = metadataJSON['geoDataExif'];
+                locationData = metadataJSON.geoDataExif;
             }
-            if (locationData != null) {
-                metaDataObject['latitude'] = locationData['latitude'];
-                metaDataObject['longitude'] = locationData['longitude'];
+            if (locationData !== null) {
+                metaDataObject.latitude = locationData.latitude;
+                metaDataObject.longitude = locationData.longitude;
             }
-            this.metadataMap.set(metadataJSON['title'], metaDataObject);
+            this.metadataMap.set(metadataJSON.title, metaDataObject);
         } catch (e) {
             console.error(e);
-            //ignore
+            // ignore
         }
     }
+
     private async generateThumbnail(
         reader: FileReader,
-        file: globalThis.File
+        file: globalThis.File,
     ): Promise<Uint8Array> {
         try {
-            let canvas = document.createElement('canvas');
-            let canvas_CTX = canvas.getContext('2d');
+            const canvas = document.createElement('canvas');
+            // eslint-disable-next-line camelcase
+            const canvas_CTX = canvas.getContext('2d');
             let imageURL = null;
             if (file.type.match(TYPE_IMAGE) || fileIsHEIC(file.name)) {
                 if (fileIsHEIC(file.name)) {
                     file = new globalThis.File(
                         [await convertHEIC2JPEG(file)],
                         null,
-                        null
+                        null,
                     );
                 }
                 let image = new Image();
@@ -638,8 +640,7 @@ class UploadService {
                 await new Promise((resolve, reject) => {
                     image.onload = () => {
                         try {
-                            const thumbnailWidth =
-                                (image.width * THUMBNAIL_HEIGHT) / image.height;
+                            const thumbnailWidth = (image.width * THUMBNAIL_HEIGHT) / image.height;
                             canvas.width = thumbnailWidth;
                             canvas.height = THUMBNAIL_HEIGHT;
                             canvas_CTX.drawImage(
@@ -647,32 +648,29 @@ class UploadService {
                                 0,
                                 0,
                                 thumbnailWidth,
-                                THUMBNAIL_HEIGHT
+                                THUMBNAIL_HEIGHT,
                             );
                             image = undefined;
                             resolve(null);
                         } catch (e) {
                             console.error(e);
-                            reject(`${THUMBNAIL_GENERATION_FAILED} err: ${e}`);
+                            reject(new Error(`${THUMBNAIL_GENERATION_FAILED} err: ${e}`));
                         }
                     };
                     setTimeout(
-                        () =>
-                            reject(
-                                `${THUMBNAIL_GENERATION_FAILED} err:
-                                    wait time exceeded`
-                            ),
-                        WAIT_TIME_THUMBNAIL_GENERATION
+                        () => reject(
+                            new Error(`${THUMBNAIL_GENERATION_FAILED} err:wait time exceeded`),
+                        ),
+                        WAIT_TIME_THUMBNAIL_GENERATION,
                     );
                 });
             } else {
-                await new Promise(async (resolve, reject) => {
+                await new Promise((resolve, reject) => {
                     let video = document.createElement('video');
                     imageURL = URL.createObjectURL(file);
-                    video.addEventListener('timeupdate', function () {
+                    video.addEventListener('timeupdate', () => {
                         try {
-                            const thumbnailWidth =
-                                (video.videoWidth * THUMBNAIL_HEIGHT) /
+                            const thumbnailWidth = (video.videoWidth * THUMBNAIL_HEIGHT) /
                                 video.videoHeight;
                             canvas.width = thumbnailWidth;
                             canvas.height = THUMBNAIL_HEIGHT;
@@ -681,43 +679,42 @@ class UploadService {
                                 0,
                                 0,
                                 thumbnailWidth,
-                                THUMBNAIL_HEIGHT
+                                THUMBNAIL_HEIGHT,
                             );
                             video = null;
                             resolve(null);
                         } catch (e) {
                             console.error(e);
-                            reject(`${THUMBNAIL_GENERATION_FAILED} err: ${e}`);
+                            reject(new Error(`${THUMBNAIL_GENERATION_FAILED} err: ${e}`));
                         }
                     });
                     video.preload = 'metadata';
                     video.src = imageURL;
                     video.currentTime = 3;
                     setTimeout(
-                        () =>
-                            reject(
-                                `${THUMBNAIL_GENERATION_FAILED} err:
-                                wait time exceeded`
-                            ),
-                        WAIT_TIME_THUMBNAIL_GENERATION
+                        () => reject(
+                            new Error(`${THUMBNAIL_GENERATION_FAILED} err:
+                                wait time exceeded`),
+                        ),
+                        WAIT_TIME_THUMBNAIL_GENERATION,
                     );
                 });
             }
             URL.revokeObjectURL(imageURL);
-            let thumbnailBlob = null,
-                attempts = 0,
-                quality = 1;
+            let thumbnailBlob = null;
+            let attempts = 0;
+            let quality = 1;
 
             do {
                 attempts++;
                 quality /= 2;
                 thumbnailBlob = await new Promise((resolve) => {
                     canvas.toBlob(
-                        function (blob) {
+                        (blob) => {
                             resolve(blob);
                         },
                         'image/jpeg',
-                        quality
+                        quality,
                     );
                 });
                 thumbnailBlob = thumbnailBlob ?? new Blob([]);
@@ -727,7 +724,7 @@ class UploadService {
             );
             const thumbnail = await this.getUint8ArrayView(
                 reader,
-                thumbnailBlob
+                thumbnailBlob,
             );
             return thumbnail;
         } catch (e) {
@@ -737,24 +734,24 @@ class UploadService {
     }
 
     private getFileStream(reader: FileReader, file: globalThis.File) {
-        let self = this;
-        let fileChunkReader = (async function* fileChunkReaderMaker(
+        const self = this;
+        const fileChunkReader = (async function* fileChunkReaderMaker(
             fileSize,
-            self
+            self,
         ) {
             let offset = 0;
             while (offset < fileSize) {
-                let blob = file.slice(offset, ENCRYPTION_CHUNK_SIZE + offset);
-                let fileChunk = await self.getUint8ArrayView(reader, blob);
+                const blob = file.slice(offset, ENCRYPTION_CHUNK_SIZE + offset);
+                const fileChunk = await self.getUint8ArrayView(reader, blob);
                 yield fileChunk;
                 offset += ENCRYPTION_CHUNK_SIZE;
             }
             return null;
-        })(file.size, self);
+        }(file.size, self));
         return {
             stream: new ReadableStream<Uint8Array>({
                 async pull(controller: ReadableStreamDefaultController) {
-                    let chunk = await fileChunkReader.next();
+                    const chunk = await fileChunkReader.next();
                     if (chunk.done) {
                         controller.close();
                     } else {
@@ -768,18 +765,17 @@ class UploadService {
 
     private async getUint8ArrayView(
         reader: FileReader,
-        file: Blob
+        file: Blob,
     ): Promise<Uint8Array> {
         try {
             return await new Promise((resolve, reject) => {
-                reader.onabort = () => reject('file reading was aborted');
-                reader.onerror = () => reject('file reading has failed');
+                reader.onabort = () => reject(new Error('file reading was aborted'));
+                reader.onerror = () => reject(new Error('file reading has failed'));
                 reader.onload = () => {
                     // Do whatever you want with the file contents
-                    const result =
-                        typeof reader.result === 'string'
-                            ? new TextEncoder().encode(reader.result)
-                            : new Uint8Array(reader.result);
+                    const result = typeof reader.result === 'string' ?
+                        new TextEncoder().encode(reader.result) :
+                        new Uint8Array(reader.result);
                     resolve(result);
                 };
                 reader.readAsArrayBuffer(file);
@@ -791,7 +787,7 @@ class UploadService {
     }
 
     private async getUploadURL() {
-        if (this.uploadURLs.length == 0) {
+        if (this.uploadURLs.length === 0) {
             await this.fetchUploadURLs();
         }
         return this.uploadURLs.pop();
@@ -809,15 +805,15 @@ class UploadService {
                     {
                         count: Math.min(
                             MAX_URL_REQUESTS,
-                            (this.totalFileCount - this.filesCompleted) * 2
+                            (this.totalFileCount - this.filesCompleted) * 2,
                         ),
                     },
-                    { 'X-Auth-Token': token }
+                    {'X-Auth-Token': token},
                 );
                 const response = await this.uploadURLFetchInProgress;
 
                 this.uploadURLFetchInProgress = null;
-                this.uploadURLs.push(...response.data['urls']);
+                this.uploadURLs.push(...response.data.urls);
             }
             return this.uploadURLFetchInProgress;
         } catch (e) {
@@ -827,7 +823,7 @@ class UploadService {
     }
 
     private async fetchMultipartUploadURLs(
-        count: number
+        count: number,
     ): Promise<MultipartUploadURLs> {
         try {
             const token = getToken();
@@ -839,10 +835,10 @@ class UploadService {
                 {
                     count,
                 },
-                { 'X-Auth-Token': token }
+                {'X-Auth-Token': token},
             );
 
-            return response.data['urls'];
+            return response.data.urls;
         } catch (e) {
             console.error('fetch multipart-upload-url failed ', e);
             throw e;
@@ -852,7 +848,7 @@ class UploadService {
     private async putFile(
         fileUploadURL: UploadURL,
         file: Uint8Array,
-        filename: string
+        filename: string,
     ): Promise<string> {
         try {
             await this.retryPromise(
@@ -861,8 +857,8 @@ class UploadService {
                     file,
                     null,
                     null,
-                    this.trackUploadProgress(filename)
-                )
+                    this.trackUploadProgress(filename),
+                ),
             );
             return fileUploadURL.objectKey;
         } catch (e) {
@@ -875,21 +871,20 @@ class UploadService {
         multipartUploadURLs: MultipartUploadURLs,
         file: ReadableStream<Uint8Array>,
         filename: string,
-        uploadPartCount: number
+        uploadPartCount: number,
     ) {
-        let streamEncryptedFileReader = file.getReader();
-        let percentPerPart = Math.round(
-            RANDOM_PERCENTAGE_PROGRESS_FOR_PUT() / uploadPartCount
+        const streamEncryptedFileReader = file.getReader();
+        const percentPerPart = Math.round(
+            RANDOM_PERCENTAGE_PROGRESS_FOR_PUT() / uploadPartCount,
         );
         const resParts = [];
         for (const [
             index,
             fileUploadURL,
         ] of multipartUploadURLs.partURLs.entries()) {
-            let combinedChunks = [];
+            const combinedChunks = [];
             for (let i = 0; i < CHUNKS_COMBINED_FOR_UPLOAD; i++) {
-                let { done, value: chunk } =
-                    await streamEncryptedFileReader.read();
+                const {done, value: chunk} = await streamEncryptedFileReader.read();
                 if (done) {
                     break;
                 }
@@ -897,30 +892,30 @@ class UploadService {
                     combinedChunks.push(chunk[index]);
                 }
             }
-            let uploadChunk = Uint8Array.from(combinedChunks);
+            const uploadChunk = Uint8Array.from(combinedChunks);
             const response = await this.retryPromise(
                 HTTPService.put(
                     fileUploadURL,
                     uploadChunk,
                     null,
                     null,
-                    this.trackUploadProgress(filename, percentPerPart, index)
-                )
+                    this.trackUploadProgress(filename, percentPerPart, index),
+                ),
             );
             resParts.push({
                 PartNumber: index + 1,
                 ETag: response.headers.etag,
             });
         }
-        var options = { compact: true, ignoreComment: true, spaces: 4 };
+        const options = {compact: true, ignoreComment: true, spaces: 4};
         const body = convert.js2xml(
-            { CompleteMultipartUpload: { Part: resParts } },
-            options
+            {CompleteMultipartUpload: {Part: resParts}},
+            options,
         );
         await this.retryPromise(
             HTTPService.post(multipartUploadURLs.completeURL, body, null, {
                 'content-type': 'text/xml',
-            })
+            }),
         );
         return multipartUploadURLs.objectKey;
     }
@@ -928,7 +923,7 @@ class UploadService {
     private trackUploadProgress(
         filename,
         percentPerPart = RANDOM_PERCENTAGE_PROGRESS_FOR_PUT(),
-        index = 0
+        index = 0,
     ) {
         return {
             onUploadProgress: (event) => {
@@ -939,33 +934,34 @@ class UploadService {
                             Math.round(
                                 percentPerPart * index +
                                     (percentPerPart * event.loaded) /
-                                        event.total
+                                        event.total,
                             ),
-                            98
-                        )
+                            98,
+                        ),
                     );
                 this.updateProgressBarUI();
             },
         };
     }
+
     private async getExifData(
         reader: FileReader,
         receivedFile: globalThis.File,
-        fileType: FILE_TYPE
+        fileType: FILE_TYPE,
     ): Promise<ParsedEXIFData> {
         try {
             if (fileType === FILE_TYPE.VIDEO) {
                 // Todo  extract exif data from videos
-                return { location: NULL_LOCATION, creationTime: null };
+                return {location: NULL_LOCATION, creationTime: null};
             }
-            const exifData: any = await new Promise((resolve, reject) => {
+            const exifData: any = await new Promise((resolve) => {
                 reader.onload = () => {
                     resolve(EXIF.readFromBinaryFile(reader.result));
                 };
                 reader.readAsArrayBuffer(receivedFile);
             });
             if (!exifData) {
-                return { location: NULL_LOCATION, creationTime: null };
+                return {location: NULL_LOCATION, creationTime: null};
             }
             return {
                 location: this.getEXIFLocation(exifData),
@@ -976,16 +972,17 @@ class UploadService {
             throw e;
         }
     }
+
     private getUNIXTime(exifData: any) {
-        let dateString: string = exifData.DateTimeOriginal || exifData.DateTime;
+        const dateString: string = exifData.DateTimeOriginal || exifData.DateTime;
         if (!dateString) {
             return null;
         }
-        let parts = dateString.split(' ')[0].split(':');
-        let date = new Date(
+        const parts = dateString.split(' ')[0].split(':');
+        const date = new Date(
             Number(parts[0]),
             Number(parts[1]) - 1,
-            Number(parts[2])
+            Number(parts[2]),
         );
         return date.getTime() * 1000;
     }
@@ -995,45 +992,43 @@ class UploadService {
             return NULL_LOCATION;
         }
 
-        let latDegree: number, latMinute: number, latSecond: number;
-        let lonDegree: number, lonMinute: number, lonSecond: number;
+        const latDegree = exifData.GPSLatitude[0];
+        const latMinute = exifData.GPSLatitude[1];
+        const latSecond = exifData.GPSLatitude[2];
 
-        latDegree = exifData.GPSLatitude[0];
-        latMinute = exifData.GPSLatitude[1];
-        latSecond = exifData.GPSLatitude[2];
+        const lonDegree = exifData.GPSLongitude[0];
+        const lonMinute = exifData.GPSLongitude[1];
+        const lonSecond = exifData.GPSLongitude[2];
 
-        lonDegree = exifData.GPSLongitude[0];
-        lonMinute = exifData.GPSLongitude[1];
-        lonSecond = exifData.GPSLongitude[2];
+        const latDirection = exifData.GPSLatitudeRef;
+        const lonDirection = exifData.GPSLongitudeRef;
 
-        let latDirection = exifData.GPSLatitudeRef;
-        let lonDirection = exifData.GPSLongitudeRef;
-
-        let latFinal = this.convertDMSToDD(
+        const latFinal = this.convertDMSToDD(
             latDegree,
             latMinute,
             latSecond,
-            latDirection
+            latDirection,
         );
 
-        let lonFinal = this.convertDMSToDD(
+        const lonFinal = this.convertDMSToDD(
             lonDegree,
             lonMinute,
             lonSecond,
-            lonDirection
+            lonDirection,
         );
-        return { latitude: latFinal * 1.0, longitude: lonFinal * 1.0 };
+        return {latitude: latFinal * 1.0, longitude: lonFinal * 1.0};
     }
 
     private convertDMSToDD(degrees, minutes, seconds, direction) {
         let dd = degrees + minutes / 60 + seconds / 3600;
 
-        if (direction == SOUTH_DIRECTION || direction == WEST_DIRECTION) {
-            dd = dd * -1;
+        if (direction === SOUTH_DIRECTION || direction === WEST_DIRECTION) {
+            dd *= -1;
         }
 
         return dd;
     }
+
     private async retryPromise(promise: Promise<any>, retryCount: number = 2) {
         try {
             const resp = await promise;

+ 34 - 44
src/services/userService.ts

@@ -1,11 +1,11 @@
-import HTTPService from './HTTPService';
-import { KeyAttributes } from 'types';
-import { getEndpoint } from 'utils/common/apiUtil';
-import { clearKeys } from 'utils/storage/sessionStorage';
+import {KeyAttributes} from 'types';
+import {getEndpoint} from 'utils/common/apiUtil';
+import {clearKeys} from 'utils/storage/sessionStorage';
 import router from 'next/router';
-import { clearData } from 'utils/storage/localStorage';
+import {clearData} from 'utils/storage/localStorage';
 import localForage from 'utils/storage/localForage';
-import { getToken } from 'utils/common/key';
+import {getToken} from 'utils/common/key';
+import HTTPService from './HTTPService';
 
 export interface UpdatedKey {
     kekSalt: string;
@@ -29,61 +29,51 @@ export interface User {
     email: string;
 }
 
-export const getOtt = (email: string) => {
-    return HTTPService.get(`${ENDPOINT}/users/ott`, {
-        email: email,
-        client: 'web',
-    });
-};
+export const getOtt = (email: string) => HTTPService.get(`${ENDPOINT}/users/ott`, {
+    email,
+    client: 'web',
+});
 export const getPublicKey = async (email: string) => {
     const token = getToken();
 
     const resp = await HTTPService.get(
         `${ENDPOINT}/users/public-key`,
-        { email },
+        {email},
         {
             'X-Auth-Token': token,
-        }
+        },
     );
-    return resp.data['publicKey'];
-};
-
-export const verifyOtt = (email: string, ott: string) => {
-    return HTTPService.get(`${ENDPOINT}/users/credentials`, { email, ott });
+    return resp.data.publicKey;
 };
 
-export const putAttributes = (token: string, keyAttributes: KeyAttributes) => {
-    return HTTPService.put(
-        `${ENDPOINT}/users/attributes`,
-        { keyAttributes: keyAttributes },
-        null,
-        {
-            'X-Auth-Token': token,
-        }
-    );
-};
+export const verifyOtt = (email: string, ott: string) => HTTPService.get(`${ENDPOINT}/users/credentials`, {email, ott});
 
-export const setKeys = (token: string, updatedKey: UpdatedKey) => {
-    return HTTPService.put(`${ENDPOINT}/users/keys`, updatedKey, null, {
+export const putAttributes = (token: string, keyAttributes: KeyAttributes) => HTTPService.put(
+    `${ENDPOINT}/users/attributes`,
+    {keyAttributes},
+    null,
+    {
         'X-Auth-Token': token,
-    });
-};
+    },
+);
 
-export const SetRecoveryKey = (token: string, recoveryKey: RecoveryKey) => {
-    return HTTPService.put(
-        `${ENDPOINT}/users/recovery-key`,
-        recoveryKey,
-        null,
-        {
-            'X-Auth-Token': token,
-        }
-    );
-};
+export const setKeys = (token: string, updatedKey: UpdatedKey) => HTTPService.put(`${ENDPOINT}/users/keys`, updatedKey, null, {
+    'X-Auth-Token': token,
+});
+
+export const setRecoveryKey = (token: string, recoveryKey: RecoveryKey) => HTTPService.put(
+    `${ENDPOINT}/users/recovery-key`,
+    recoveryKey,
+    null,
+    {
+        'X-Auth-Token': token,
+    },
+);
 
 export const logoutUser = async () => {
     clearKeys();
     clearData();
-    const cache = await caches.delete('thumbs');
+    await caches.delete('thumbs');
     await clearFiles();
     router.push('/');
 };

+ 54 - 54
src/utils/billingUtil.ts

@@ -5,11 +5,11 @@ import billingService, {
     Plan,
     Subscription,
 } from 'services/billingService';
-import { SUBSCRIPTION_VERIFICATION_ERROR } from './common/errorUtil';
-import { getData, LS_KEYS } from './storage/localStorage';
-import { NextRouter } from 'next/router';
-import { SetDialogMessage } from 'components/MessageDialog';
-import { SetLoading } from 'pages/gallery';
+import {NextRouter} from 'next/router';
+import {SetDialogMessage} from 'components/MessageDialog';
+import {SetLoading} from 'pages/gallery';
+import {getData, LS_KEYS} from './storage/localStorage';
+import {SUBSCRIPTION_VERIFICATION_ERROR} from './common/errorUtil';
 
 const STRIPE = 'stripe';
 
@@ -70,7 +70,7 @@ export function hasStripeSubscription(subscription: Subscription) {
     return (
         hasPaidSubscription(subscription) &&
         subscription.paymentProvider.length > 0 &&
-        subscription.paymentProvider == STRIPE
+        subscription.paymentProvider === STRIPE
     );
 }
 
@@ -78,7 +78,7 @@ export async function updateSubscription(
     plan: Plan,
     setDialogMessage: SetDialogMessage,
     setLoading: SetLoading,
-    closePlanSelectorModal: () => null
+    closePlanSelectorModal: () => null,
 ) {
     try {
         setLoading(true);
@@ -88,43 +88,43 @@ export async function updateSubscription(
         setDialogMessage({
             title: constants.SUCCESS,
             content: constants.SUBSCRIPTION_PURCHASE_SUCCESS(
-                getUserSubscription().expiryTime
+                getUserSubscription().expiryTime,
             ),
-            close: { variant: 'success' },
+            close: {variant: 'success'},
         });
     } catch (err) {
         switch (err?.message) {
-            case PAYMENT_INTENT_STATUS.REQUIRE_PAYMENT_METHOD:
-                setDialogMessage({
-                    title: constants.UPDATE_PAYMENT_METHOD,
-                    content: constants.UPDATE_PAYMENT_METHOD_MESSAGE,
-                    staticBackdrop: true,
-                    proceed: {
-                        text: constants.UPDATE_PAYMENT_METHOD,
-                        variant: 'success',
-                        action: updatePaymentMethod.bind(
-                            null,
+        case PAYMENT_INTENT_STATUS.REQUIRE_PAYMENT_METHOD:
+            setDialogMessage({
+                title: constants.UPDATE_PAYMENT_METHOD,
+                content: constants.UPDATE_PAYMENT_METHOD_MESSAGE,
+                staticBackdrop: true,
+                proceed: {
+                    text: constants.UPDATE_PAYMENT_METHOD,
+                    variant: 'success',
+                    action: updatePaymentMethod.bind(
+                        null,
 
-                            setDialogMessage,
-                            setLoading
-                        ),
-                    },
-                    close: { text: constants.CANCEL },
-                });
-                break;
-            case SUBSCRIPTION_VERIFICATION_ERROR:
-                setDialogMessage({
-                    title: constants.ERROR,
-                    content: constants.SUBSCRIPTION_VERIFICATION_FAILED,
-                    close: { variant: 'danger' },
-                });
-                break;
-            default:
-                setDialogMessage({
-                    title: constants.ERROR,
-                    content: constants.SUBSCRIPTION_PURCHASE_FAILED,
-                    close: { variant: 'danger' },
-                });
+                        setDialogMessage,
+                        setLoading,
+                    ),
+                },
+                close: {text: constants.CANCEL},
+            });
+            break;
+        case SUBSCRIPTION_VERIFICATION_ERROR:
+            setDialogMessage({
+                title: constants.ERROR,
+                content: constants.SUBSCRIPTION_VERIFICATION_FAILED,
+                close: {variant: 'danger'},
+            });
+            break;
+        default:
+            setDialogMessage({
+                title: constants.ERROR,
+                content: constants.SUBSCRIPTION_PURCHASE_FAILED,
+                close: {variant: 'danger'},
+            });
         }
     } finally {
         setLoading(false);
@@ -135,7 +135,7 @@ export async function updateSubscription(
 export async function cancelSubscription(
     setDialogMessage: SetDialogMessage,
     closePlanSelectorModal: () => null,
-    setLoading: SetLoading
+    setLoading: SetLoading,
 ) {
     try {
         setLoading(true);
@@ -143,13 +143,13 @@ export async function cancelSubscription(
         setDialogMessage({
             title: constants.SUCCESS,
             content: constants.SUBSCRIPTION_CANCEL_SUCCESS,
-            close: { variant: 'success' },
+            close: {variant: 'success'},
         });
     } catch (e) {
         setDialogMessage({
             title: constants.ERROR,
             content: constants.SUBSCRIPTION_CANCEL_FAILED,
-            close: { variant: 'danger' },
+            close: {variant: 'danger'},
         });
     } finally {
         closePlanSelectorModal();
@@ -160,7 +160,7 @@ export async function cancelSubscription(
 export async function activateSubscription(
     setDialogMessage: SetDialogMessage,
     closePlanSelectorModal: () => null,
-    setLoading: SetLoading
+    setLoading: SetLoading,
 ) {
     try {
         setLoading(true);
@@ -168,13 +168,13 @@ export async function activateSubscription(
         setDialogMessage({
             title: constants.SUCCESS,
             content: constants.SUBSCRIPTION_ACTIVATE_SUCCESS,
-            close: { variant: 'success' },
+            close: {variant: 'success'},
         });
     } catch (e) {
         setDialogMessage({
             title: constants.ERROR,
             content: constants.SUBSCRIPTION_ACTIVATE_FAILED,
-            close: { variant: 'danger' },
+            close: {variant: 'danger'},
         });
     } finally {
         closePlanSelectorModal();
@@ -184,7 +184,7 @@ export async function activateSubscription(
 
 export async function updatePaymentMethod(
     setDialogMessage: SetDialogMessage,
-    setLoading: SetLoading
+    setLoading: SetLoading,
 ) {
     try {
         setLoading(true);
@@ -193,7 +193,7 @@ export async function updatePaymentMethod(
         setDialogMessage({
             title: constants.ERROR,
             content: constants.UNKNOWN_ERROR,
-            close: { variant: 'danger' },
+            close: {variant: 'danger'},
         });
     } finally {
         setLoading(true);
@@ -202,7 +202,7 @@ export async function updatePaymentMethod(
 
 export async function checkSubscriptionPurchase(
     setDialogMessage: SetDialogMessage,
-    router: NextRouter
+    router: NextRouter,
 ) {
     try {
         const urlParams = new URLSearchParams(window.location.search);
@@ -211,18 +211,18 @@ export async function checkSubscriptionPurchase(
             setDialogMessage({
                 title: constants.MESSAGE,
                 content: constants.SUBSCRIPTION_PURCHASE_CANCELLED,
-                close: { variant: 'danger' },
+                close: {variant: 'danger'},
             });
         } else if (sessionId) {
             try {
                 const subscription = await billingService.verifySubscription(
-                    sessionId
+                    sessionId,
                 );
                 setDialogMessage({
                     title: constants.SUBSCRIPTION_PURCHASE_SUCCESS_TITLE,
-                    close: { variant: 'success' },
+                    close: {variant: 'success'},
                     content: constants.SUBSCRIPTION_PURCHASE_SUCCESS(
-                        subscription?.expiryTime
+                        subscription?.expiryTime,
                     ),
                 });
             } catch (e) {
@@ -234,8 +234,8 @@ export async function checkSubscriptionPurchase(
             }
         }
     } catch (e) {
-        //ignore
+        // ignore
     } finally {
-        router.push('gallery', undefined, { shallow: true });
+        router.push('gallery', undefined, {shallow: true});
     }
 }

+ 5 - 5
src/utils/collection/index.ts

@@ -4,8 +4,8 @@ import {
     CollectionType,
     createCollection,
 } from 'services/collectionService';
-import { getSelectedFiles } from 'utils/file';
-import { File } from 'services/fileService';
+import {getSelectedFiles} from 'utils/file';
+import {File} from 'services/fileService';
 
 export async function addFilesToCollection(
     setCollectionSelectorView: (value: boolean) => void,
@@ -15,14 +15,14 @@ export async function addFilesToCollection(
     syncWithRemote: () => Promise<void>,
     selectCollection: (id: number) => void,
     collectionName: string,
-    existingCollection: Collection
+    existingCollection: Collection,
 ) {
     setCollectionSelectorView(false);
     let collection;
     if (!existingCollection) {
         collection = await createCollection(
             collectionName,
-            CollectionType.album
+            CollectionType.album,
         );
     } else {
         collection = existingCollection;
@@ -35,5 +35,5 @@ export async function addFilesToCollection(
 }
 
 export function getSelectedCollection(collectionID: number, collections) {
-    return collections.find((collection) => collection.id == collectionID);
+    return collections.find((collection) => collection.id === collectionID);
 }

+ 9 - 10
src/utils/common/apiUtil.ts

@@ -1,19 +1,18 @@
 export const getEndpoint = () => {
-    const endPoint =
-        process.env.NEXT_PUBLIC_ENTE_ENDPOINT ?? 'https://api.ente.io';
+    const endPoint = process.env.NEXT_PUBLIC_ENTE_ENDPOINT ?? 'https://api.ente.io';
     return endPoint;
 };
 
 export const getFileUrl = (id: number) => {
-    if (process.env.NEXT_PUBLIC_ENTE_ENDPOINT != undefined) {
-        return process.env.NEXT_PUBLIC_ENTE_ENDPOINT + `/files/download/${id}` ?? 'https://api.ente.io';
+    if (process.env.NEXT_PUBLIC_ENTE_ENDPOINT !== undefined) {
+        return `${process.env.NEXT_PUBLIC_ENTE_ENDPOINT}/files/download/${id}` ?? 'https://api.ente.io';
     }
-    return `https://files.ente.workers.dev/?fileID=${id}`
-}
+    return `https://files.ente.workers.dev/?fileID=${id}`;
+};
 
 export const getThumbnailUrl = (id: number) => {
-    if (process.env.NEXT_PUBLIC_ENTE_ENDPOINT != undefined) {
-        return process.env.NEXT_PUBLIC_ENTE_ENDPOINT + `/files/preview/${id}` ?? 'https://api.ente.io';
+    if (process.env.NEXT_PUBLIC_ENTE_ENDPOINT !== undefined) {
+        return `${process.env.NEXT_PUBLIC_ENTE_ENDPOINT}/files/preview/${id}` ?? 'https://api.ente.io';
     }
-    return `https://thumbnails.ente.workers.dev/?fileID=${id}`
-}
+    return `https://thumbnails.ente.workers.dev/?fileID=${id}`;
+};

+ 15 - 18
src/utils/common/errorUtil.ts

@@ -10,8 +10,7 @@ export const errorCodes = {
 
 const AXIOS_NETWORK_ERROR = 'Network Error';
 
-export const SUBSCRIPTION_VERIFICATION_ERROR =
-    'Subscription verification failed';
+export const SUBSCRIPTION_VERIFICATION_ERROR = 'Subscription verification failed';
 
 export const THUMBNAIL_GENERATION_FAILED = 'thumbnail generation failed';
 
@@ -20,23 +19,21 @@ export function ErrorHandler(error) {
     if (error?.status) {
         const errorCode = error.status.toString();
         switch (errorCode) {
-            case errorCodes.ERR_NO_ACTIVE_SUBSCRIPTION:
-                errorMessage = constants.SUBSCRIPTION_EXPIRED;
-                break;
-            case errorCodes.ERR_STORAGE_LIMIT_EXCEEDED:
-                errorMessage = constants.STORAGE_QUOTA_EXCEEDED;
-                break;
-            case errorCodes.ERR_NO_INTERNET_CONNECTION:
-                errorMessage = constants.NO_INTERNET_CONNECTION;
-                break;
-            case errorCodes.ERR_SESSION_EXPIRED:
-                errorMessage = constants.SESSION_EXPIRED_MESSAGE;
-                break;
-        }
-    } else {
-        if (error.message === AXIOS_NETWORK_ERROR) {
-            errorMessage = constants.SYNC_FAILED;
+        case errorCodes.ERR_NO_ACTIVE_SUBSCRIPTION:
+            errorMessage = constants.SUBSCRIPTION_EXPIRED;
+            break;
+        case errorCodes.ERR_STORAGE_LIMIT_EXCEEDED:
+            errorMessage = constants.STORAGE_QUOTA_EXCEEDED;
+            break;
+        case errorCodes.ERR_NO_INTERNET_CONNECTION:
+            errorMessage = constants.NO_INTERNET_CONNECTION;
+            break;
+        case errorCodes.ERR_SESSION_EXPIRED:
+            errorMessage = constants.SESSION_EXPIRED_MESSAGE;
+            break;
         }
+    } else if (error.message === AXIOS_NETWORK_ERROR) {
+        errorMessage = constants.SYNC_FAILED;
     }
     if (errorMessage) {
         throw new Error(errorMessage);

+ 4 - 6
src/utils/common/index.ts

@@ -1,15 +1,13 @@
-import { errorCodes } from './errorUtil';
+import {errorCodes} from './errorUtil';
 
 const TwoSecondInMillSeconds = 2000;
-const DESKTOP_APP_DOWNLOAD_URL =
-    'https://github.com/ente-io/bhari-frame/releases/';
+const DESKTOP_APP_DOWNLOAD_URL = 'https://github.com/ente-io/bhari-frame/releases/';
 
 export function checkConnectivity() {
     if (navigator.onLine) {
         return true;
-    } else {
-        throw new Error(errorCodes.ERR_NO_INTERNET_CONNECTION);
     }
+    throw new Error(errorCodes.ERR_NO_INTERNET_CONNECTION);
 }
 
 export function runningInBrowser() {
@@ -22,7 +20,7 @@ export async function WaitFor2Seconds() {
     });
 }
 export function downloadApp() {
-    var win = window.open(DESKTOP_APP_DOWNLOAD_URL, '_blank');
+    const win = window.open(DESKTOP_APP_DOWNLOAD_URL, '_blank');
     win.focus();
 }
 export function reverseString(title: string) {

+ 8 - 11
src/utils/common/key.ts

@@ -1,20 +1,20 @@
-import { B64EncryptionResult } from 'services/uploadService';
+import {B64EncryptionResult} from 'services/uploadService';
 import CryptoWorker from 'utils/crypto';
-import { getData, LS_KEYS } from 'utils/storage/localStorage';
-import { getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
-import { errorCodes } from './errorUtil';
+import {getData, LS_KEYS} from 'utils/storage/localStorage';
+import {getKey, SESSION_KEYS} from 'utils/storage/sessionStorage';
+import {errorCodes} from './errorUtil';
 
 export const getActualKey = async () => {
     try {
         const encryptionKeyAttributes: B64EncryptionResult = getKey(
-            SESSION_KEYS.ENCRYPTION_KEY
+            SESSION_KEYS.ENCRYPTION_KEY,
         );
 
         const cryptoWorker = await new CryptoWorker();
         const key: string = await cryptoWorker.decryptB64(
             encryptionKeyAttributes.encryptedData,
             encryptionKeyAttributes.nonce,
-            encryptionKeyAttributes.key
+            encryptionKeyAttributes.key,
         );
         return key;
     } catch (e) {
@@ -22,10 +22,7 @@ export const getActualKey = async () => {
     }
 };
 
-export const getStripePublishableKey = () =>
-    process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ??
+export const getStripePublishableKey = () => process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ??
     'pk_live_51HAhqDK59oeucIMOiTI6MDDM2UWUbCAJXJCGsvjJhiO8nYJz38rQq5T4iyQLDMKxqEDUfU5Hopuj4U5U4dff23oT00fHvZeodC';
 
-export const getToken = () => {
-    return getData(LS_KEYS.USER)?.token;
-};
+export const getToken = () => getData(LS_KEYS.USER)?.token;

+ 5 - 5
src/utils/common/useLongPress.ts

@@ -1,5 +1,5 @@
 // https://stackoverflow.com/a/54749871/2760968
-import { useState, useEffect } from 'react';
+import {useState, useEffect} from 'react';
 
 export default function useLongPress(callback: () => void, ms = 300) {
     const [startLongPress, setStartLongPress] = useState(false);
@@ -7,13 +7,13 @@ export default function useLongPress(callback: () => void, ms = 300) {
     useEffect(() => {
         let timerId: NodeJS.Timeout;
         if (startLongPress) {
-        timerId = setTimeout(callback, ms);
+            timerId = setTimeout(callback, ms);
         } else {
-        clearTimeout(timerId);
+            clearTimeout(timerId);
         }
 
         return () => {
-        clearTimeout(timerId);
+            clearTimeout(timerId);
         };
     }, [callback, ms, startLongPress]);
 
@@ -24,4 +24,4 @@ export default function useLongPress(callback: () => void, ms = 300) {
         onTouchStart: () => setStartLongPress(true),
         onTouchEnd: () => setStartLongPress(false),
     };
-}
+}

+ 26 - 34
src/utils/crypto/index.ts

@@ -1,12 +1,13 @@
-import { KEK } from 'pages/generate';
-import { B64EncryptionResult } from 'services/uploadService';
-import { KeyAttributes } from 'types';
+import {KEK} from 'pages/generate';
+import {B64EncryptionResult} from 'services/uploadService';
+import {KeyAttributes} from 'types';
 import * as Comlink from 'comlink';
-import { runningInBrowser } from 'utils/common';
-import { SESSION_KEYS, setKey } from 'utils/storage/sessionStorage';
-import { getData, LS_KEYS, setData } from 'utils/storage/localStorage';
-import { getActualKey, getToken } from 'utils/common/key';
-import { SetRecoveryKey } from 'services/userService';
+import {runningInBrowser} from 'utils/common';
+import {SESSION_KEYS, setKey} from 'utils/storage/sessionStorage';
+import {getData, LS_KEYS, setData} from 'utils/storage/localStorage';
+import {getActualKey, getToken} from 'utils/common/key';
+import {setRecoveryKey} from 'services/userService';
+
 export interface ComlinkWorker {
     comlink: any;
     worker: Worker;
@@ -18,13 +19,13 @@ export const getDedicatedCryptoWorker = (): ComlinkWorker => {
             type: 'module',
         });
         const comlink = Comlink.wrap(worker);
-        return { comlink, worker };
+        return {comlink, worker};
     }
 };
 const CryptoWorker: any = getDedicatedCryptoWorker()?.comlink;
 
 export async function generateKeyAttributes(
-    passphrase: string
+    passphrase: string,
 ): Promise<{ keyAttributes: KeyAttributes; masterKey: string }> {
     const cryptoWorker = await new CryptoWorker();
     const masterKey: string = await cryptoWorker.generateEncryptionKey();
@@ -32,16 +33,12 @@ export async function generateKeyAttributes(
     const kekSalt: string = await cryptoWorker.generateSaltToDeriveKey();
     const kek = await cryptoWorker.deriveSensitiveKey(passphrase, kekSalt);
 
-    const masterKeyEncryptedWithKek: B64EncryptionResult =
-        await cryptoWorker.encryptToB64(masterKey, kek.key);
-    const masterKeyEncryptedWithRecoveryKey: B64EncryptionResult =
-        await cryptoWorker.encryptToB64(masterKey, recoveryKey);
-    const recoveryKeyEncryptedWithMasterKey: B64EncryptionResult =
-        await cryptoWorker.encryptToB64(recoveryKey, masterKey);
+    const masterKeyEncryptedWithKek: B64EncryptionResult = await cryptoWorker.encryptToB64(masterKey, kek.key);
+    const masterKeyEncryptedWithRecoveryKey: B64EncryptionResult = await cryptoWorker.encryptToB64(masterKey, recoveryKey);
+    const recoveryKeyEncryptedWithMasterKey: B64EncryptionResult = await cryptoWorker.encryptToB64(recoveryKey, masterKey);
 
     const keyPair = await cryptoWorker.generateKeyPair();
-    const encryptedKeyPairAttributes: B64EncryptionResult =
-        await cryptoWorker.encryptToB64(keyPair.privateKey, masterKey);
+    const encryptedKeyPairAttributes: B64EncryptionResult = await cryptoWorker.encryptToB64(keyPair.privateKey, masterKey);
 
     const keyAttributes: KeyAttributes = {
         kekSalt,
@@ -60,23 +57,21 @@ export async function generateKeyAttributes(
         recoveryKeyDecryptionNonce: recoveryKeyEncryptedWithMasterKey.nonce,
     };
 
-    return { keyAttributes, masterKey };
+    return {keyAttributes, masterKey};
 }
 
 export async function generateAndSaveIntermediateKeyAttributes(
     passphrase,
     existingKeyAttributes,
-    key
+    key,
 ): Promise<KeyAttributes> {
     const cryptoWorker = await new CryptoWorker();
-    const intermediateKekSalt: string =
-        await cryptoWorker.generateSaltToDeriveKey();
+    const intermediateKekSalt: string = await cryptoWorker.generateSaltToDeriveKey();
     const intermediateKek: KEK = await cryptoWorker.deriveIntermediateKey(
         passphrase,
-        intermediateKekSalt
+        intermediateKekSalt,
     );
-    const encryptedKeyAttributes: B64EncryptionResult =
-        await cryptoWorker.encryptToB64(key, intermediateKek.key);
+    const encryptedKeyAttributes: B64EncryptionResult = await cryptoWorker.encryptToB64(key, intermediateKek.key);
 
     const intermediateKeyAttributes = Object.assign(existingKeyAttributes, {
         kekSalt: intermediateKekSalt,
@@ -110,16 +105,15 @@ export const getRecoveryKey = async () => {
             recoveryKey = await cryptoWorker.decryptB64(
                 recoveryKeyEncryptedWithMasterKey,
                 recoveryKeyDecryptionNonce,
-                masterKey
+                masterKey,
             );
         } else {
             recoveryKey = await createNewRecoveryKey();
         }
         recoveryKey = await cryptoWorker.toHex(recoveryKey);
+        return recoveryKey;
     } catch (e) {
         console.error('getRecoveryKey failed', e);
-    } finally {
-        return recoveryKey;
     }
 };
 
@@ -130,21 +124,19 @@ async function createNewRecoveryKey() {
     const cryptoWorker = await new CryptoWorker();
 
     const recoveryKey = await cryptoWorker.generateEncryptionKey();
-    const encryptedMasterKey: B64EncryptionResult =
-        await cryptoWorker.encryptToB64(masterKey, recoveryKey);
-    const encryptedRecoveryKey: B64EncryptionResult =
-        await cryptoWorker.encryptToB64(recoveryKey, masterKey);
+    const encryptedMasterKey: B64EncryptionResult = await cryptoWorker.encryptToB64(masterKey, recoveryKey);
+    const encryptedRecoveryKey: B64EncryptionResult = await cryptoWorker.encryptToB64(recoveryKey, masterKey);
     const recoveryKeyAttributes = {
         masterKeyEncryptedWithRecoveryKey: encryptedMasterKey.encryptedData,
         masterKeyDecryptionNonce: encryptedMasterKey.nonce,
         recoveryKeyEncryptedWithMasterKey: encryptedRecoveryKey.encryptedData,
         recoveryKeyDecryptionNonce: encryptedRecoveryKey.nonce,
     };
-    await SetRecoveryKey(getToken(), recoveryKeyAttributes);
+    await setRecoveryKey(getToken(), recoveryKeyAttributes);
 
     const updatedKeyAttributes = Object.assign(
         existingAttributes,
-        recoveryKeyAttributes
+        recoveryKeyAttributes,
     );
     setData(LS_KEYS.KEY_ATTRIBUTES, updatedKeyAttributes);
 

+ 65 - 68
src/utils/crypto/libsodium.ts

@@ -1,20 +1,20 @@
-import sodium, { StateAddress } from 'libsodium-wrappers';
-import { ENCRYPTION_CHUNK_SIZE } from 'types';
+import sodium, {StateAddress} from 'libsodium-wrappers';
+import {ENCRYPTION_CHUNK_SIZE} from 'types';
 
 export async function decryptChaChaOneShot(
     data: Uint8Array,
     header: Uint8Array,
-    key: string
+    key: string,
 ) {
     await sodium.ready;
     const pullState = sodium.crypto_secretstream_xchacha20poly1305_init_pull(
         header,
-        await fromB64(key)
+        await fromB64(key),
     );
     const pullResult = sodium.crypto_secretstream_xchacha20poly1305_pull(
         pullState,
         data,
-        null
+        null,
     );
     return pullResult.message;
 }
@@ -22,30 +22,29 @@ export async function decryptChaChaOneShot(
 export async function decryptChaCha(
     data: Uint8Array,
     header: Uint8Array,
-    key: string
+    key: string,
 ) {
     await sodium.ready;
     const pullState = sodium.crypto_secretstream_xchacha20poly1305_init_pull(
         header,
-        await fromB64(key)
+        await fromB64(key),
     );
-    const decryptionChunkSize =
-        ENCRYPTION_CHUNK_SIZE +
+    const decryptionChunkSize = ENCRYPTION_CHUNK_SIZE +
         sodium.crypto_secretstream_xchacha20poly1305_ABYTES;
-    var bytesRead = 0;
-    var decryptedData = [];
-    var tag = sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
-    while (tag != sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
-        var chunkSize = decryptionChunkSize;
+    let bytesRead = 0;
+    const decryptedData = [];
+    let tag = sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
+    while (tag !== sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
+        let chunkSize = decryptionChunkSize;
         if (bytesRead + chunkSize > data.length) {
             chunkSize = data.length - bytesRead;
         }
         const buffer = data.slice(bytesRead, bytesRead + chunkSize);
         const pullResult = sodium.crypto_secretstream_xchacha20poly1305_pull(
             pullState,
-            buffer
+            buffer,
         );
-        for (var index = 0; index < pullResult.message.length; index++) {
+        for (let index = 0; index < pullResult.message.length; index++) {
             decryptedData.push(pullResult.message[index]);
         }
         tag = pullResult.tag;
@@ -58,41 +57,40 @@ export async function initChunkDecryption(header: Uint8Array, key: Uint8Array) {
     await sodium.ready;
     const pullState = sodium.crypto_secretstream_xchacha20poly1305_init_pull(
         header,
-        key
+        key,
     );
-    const decryptionChunkSize =
-        ENCRYPTION_CHUNK_SIZE +
+    const decryptionChunkSize = ENCRYPTION_CHUNK_SIZE +
         sodium.crypto_secretstream_xchacha20poly1305_ABYTES;
     const tag = sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
-    return { pullState, decryptionChunkSize, tag };
+    return {pullState, decryptionChunkSize, tag};
 }
 
 export async function decryptChunk(data: Uint8Array, pullState: StateAddress) {
     await sodium.ready;
     const pullResult = sodium.crypto_secretstream_xchacha20poly1305_pull(
         pullState,
-        data
+        data,
     );
     const newTag = pullResult.tag;
-    return { decryptedData: pullResult.message, newTag };
+    return {decryptedData: pullResult.message, newTag};
 }
 
 export async function encryptChaChaOneShot(data: Uint8Array, key?: string) {
     await sodium.ready;
 
-    const uintkey: Uint8Array = key
-        ? await fromB64(key)
-        : sodium.crypto_secretstream_xchacha20poly1305_keygen();
-    let initPushResult = sodium.crypto_secretstream_xchacha20poly1305_init_push(
-        uintkey
+    const uintkey: Uint8Array = key ?
+        await fromB64(key) :
+        sodium.crypto_secretstream_xchacha20poly1305_keygen();
+    const initPushResult = sodium.crypto_secretstream_xchacha20poly1305_init_push(
+        uintkey,
     );
-    let [pushState, header] = [initPushResult.state, initPushResult.header];
+    const [pushState, header] = [initPushResult.state, initPushResult.header];
 
     const pushResult = sodium.crypto_secretstream_xchacha20poly1305_push(
         pushState,
         data,
         null,
-        sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
+        sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL,
     );
     return {
         key: await toB64(uintkey),
@@ -106,18 +104,18 @@ export async function encryptChaChaOneShot(data: Uint8Array, key?: string) {
 export async function encryptChaCha(data: Uint8Array, key?: string) {
     await sodium.ready;
 
-    const uintkey: Uint8Array = key
-        ? await fromB64(key)
-        : sodium.crypto_secretstream_xchacha20poly1305_keygen();
+    const uintkey: Uint8Array = key ?
+        await fromB64(key) :
+        sodium.crypto_secretstream_xchacha20poly1305_keygen();
 
-    let initPushResult = sodium.crypto_secretstream_xchacha20poly1305_init_push(
-        uintkey
+    const initPushResult = sodium.crypto_secretstream_xchacha20poly1305_init_push(
+        uintkey,
     );
-    let [pushState, header] = [initPushResult.state, initPushResult.header];
+    const [pushState, header] = [initPushResult.state, initPushResult.header];
     let bytesRead = 0;
     let tag = sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
 
-    let encryptedData = [];
+    const encryptedData = [];
 
     while (tag !== sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
         let chunkSize = ENCRYPTION_CHUNK_SIZE;
@@ -132,9 +130,9 @@ export async function encryptChaCha(data: Uint8Array, key?: string) {
             pushState,
             buffer,
             null,
-            tag
+            tag,
         );
-        for (var index = 0; index < pushResult.length; index++) {
+        for (let index = 0; index < pushResult.length; index++) {
             encryptedData.push(pushResult[index]);
         }
     }
@@ -149,11 +147,11 @@ export async function encryptChaCha(data: Uint8Array, key?: string) {
 
 export async function initChunkEncryption() {
     await sodium.ready;
-    let key = sodium.crypto_secretstream_xchacha20poly1305_keygen();
-    let initPushResult = sodium.crypto_secretstream_xchacha20poly1305_init_push(
-        key
+    const key = sodium.crypto_secretstream_xchacha20poly1305_keygen();
+    const initPushResult = sodium.crypto_secretstream_xchacha20poly1305_init_push(
+        key,
     );
-    let [pushState, header] = [initPushResult.state, initPushResult.header];
+    const [pushState, header] = [initPushResult.state, initPushResult.header];
     return {
         key: await toB64(key),
         decryptionHeader: await toB64(header),
@@ -163,18 +161,18 @@ export async function initChunkEncryption() {
 export async function encryptFileChunk(
     data: Uint8Array,
     pushState: sodium.StateAddress,
-    finalChunk?: boolean
+    finalChunk?: boolean,
 ) {
     await sodium.ready;
 
-    let tag = finalChunk
-        ? sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
-        : sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
+    const tag = finalChunk ?
+        sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL :
+        sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
     const pushResult = sodium.crypto_secretstream_xchacha20poly1305_push(
         pushState,
         data,
         null,
-        tag
+        tag,
     );
 
     return pushResult;
@@ -183,7 +181,7 @@ export async function encryptToB64(data: string, key?: string) {
     await sodium.ready;
     const encrypted = await encrypt(
         await fromB64(data),
-        key ? await fromB64(key) : null
+        key ? await fromB64(key) : null,
     );
 
     return {
@@ -202,7 +200,7 @@ export async function decryptB64(data: string, nonce: string, key: string) {
     const decrypted = await decrypt(
         await fromB64(data),
         await fromB64(nonce),
-        await fromB64(key)
+        await fromB64(key),
     );
 
     return await toB64(decrypted);
@@ -213,7 +211,7 @@ export async function decryptToUTF8(data: string, nonce: string, key: string) {
     const decrypted = await decrypt(
         await fromB64(data),
         await fromB64(nonce),
-        await fromB64(key)
+        await fromB64(key),
     );
 
     return sodium.to_string(decrypted);
@@ -221,20 +219,20 @@ export async function decryptToUTF8(data: string, nonce: string, key: string) {
 
 export async function encrypt(data: Uint8Array, key?: Uint8Array) {
     await sodium.ready;
-    const uintkey: Uint8Array = key ? key : sodium.crypto_secretbox_keygen();
+    const uintkey: Uint8Array = key || sodium.crypto_secretbox_keygen();
     const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
     const encryptedData = sodium.crypto_secretbox_easy(data, nonce, uintkey);
     return {
-        encryptedData: encryptedData,
+        encryptedData,
         key: uintkey,
-        nonce: nonce,
+        nonce,
     };
 }
 
 export async function decrypt(
     data: Uint8Array,
     nonce: Uint8Array,
-    key: Uint8Array
+    key: Uint8Array,
 ) {
     await sodium.ready;
     return sodium.crypto_secretbox_open_easy(data, nonce, key);
@@ -250,7 +248,7 @@ export async function hash(input: string) {
     return sodium.crypto_pwhash_str(
         await fromB64(input),
         sodium.crypto_pwhash_OPSLIMIT_SENSITIVE,
-        sodium.crypto_pwhash_MEMLIMIT_MODERATE
+        sodium.crypto_pwhash_MEMLIMIT_MODERATE,
     );
 }
 
@@ -258,7 +256,7 @@ export async function deriveKey(
     passphrase: string,
     salt: string,
     opsLimit: number,
-    memLimit: number
+    memLimit: number,
 ) {
     await sodium.ready;
     return await toB64(
@@ -268,8 +266,8 @@ export async function deriveKey(
             await fromB64(salt),
             opsLimit,
             memLimit,
-            sodium.crypto_pwhash_ALG_DEFAULT
-        )
+            sodium.crypto_pwhash_ALG_DEFAULT,
+        ),
     );
 }
 
@@ -287,11 +285,10 @@ export async function deriveSensitiveKey(passphrase: string, salt: string) {
                 memLimit,
             };
         } catch (e) {
-            opsLimit = opsLimit * 2;
-            memLimit = memLimit / 2;
+            opsLimit *= 2;
+            memLimit /= 2;
         }
     }
-    throw null;
 }
 
 export async function deriveIntermediateKey(passphrase: string, salt: string) {
@@ -303,11 +300,11 @@ export async function deriveIntermediateKey(passphrase: string, salt: string) {
             await fromB64(salt),
             sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
             sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
-            sodium.crypto_pwhash_ALG_DEFAULT
-        )
+            sodium.crypto_pwhash_ALG_DEFAULT,
+        ),
     );
     return {
-        key: key,
+        key,
         opsLimit: sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
         memLimit: sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
     };
@@ -335,22 +332,22 @@ export async function generateKeyPair() {
 export async function boxSealOpen(
     input: string,
     publicKey: string,
-    secretKey: string
+    secretKey: string,
 ) {
     await sodium.ready;
     return await toB64(
         sodium.crypto_box_seal_open(
             await fromB64(input),
             await fromB64(publicKey),
-            await fromB64(secretKey)
-        )
+            await fromB64(secretKey),
+        ),
     );
 }
 
 export async function boxSeal(input: string, publicKey: string) {
     await sodium.ready;
     return await toB64(
-        sodium.crypto_box_seal(await fromB64(input), await fromB64(publicKey))
+        sodium.crypto_box_seal(await fromB64(input), await fromB64(publicKey)),
     );
 }
 

+ 10 - 10
src/utils/file/index.ts

@@ -1,5 +1,5 @@
-import { deleteFiles, File } from 'services/fileService';
-import { runningInBrowser } from 'utils/common';
+import {File} from 'services/fileService';
+import {runningInBrowser} from 'utils/common';
 
 const TYPE_HEIC = 'heic';
 
@@ -7,7 +7,7 @@ export function downloadAsFile(filename: string, content: string) {
     const file = new Blob([content], {
         type: 'text/plain',
     });
-    var a = document.createElement('a');
+    const a = document.createElement('a');
     a.href = URL.createObjectURL(file);
     a.download = filename;
 
@@ -34,9 +34,9 @@ export function fileIsHEIC(name: string) {
 
 export function sortFilesIntoCollections(files: File[]) {
     const collectionWiseFiles = new Map<number, File[]>();
-    for (let file of files) {
+    for (const file of files) {
         if (!collectionWiseFiles.has(file.collectionID)) {
-            collectionWiseFiles.set(file.collectionID, new Array<File>());
+            collectionWiseFiles.set(file.collectionID, []);
         }
         collectionWiseFiles.get(file.collectionID).push(file);
     }
@@ -44,8 +44,8 @@ export function sortFilesIntoCollections(files: File[]) {
 }
 
 export function getSelectedFileIds(selectedFiles) {
-    let filesIDs: number[] = [];
-    for (let [key, val] of Object.entries(selectedFiles)) {
+    const filesIDs: number[] = [];
+    for (const [key, val] of Object.entries(selectedFiles)) {
         if (typeof val === 'boolean' && val) {
             filesIDs.push(Number(key));
         }
@@ -53,9 +53,9 @@ export function getSelectedFileIds(selectedFiles) {
     return filesIDs;
 }
 export function getSelectedFiles(selectedFiles, files: File[]): File[] {
-    let filesIDs = new Set(getSelectedFileIds(selectedFiles));
-    let filesToDelete: File[] = [];
-    for (let file of files) {
+    const filesIDs = new Set(getSelectedFileIds(selectedFiles));
+    const filesToDelete: File[] = [];
+    for (const file of files) {
         if (filesIDs.has(file.id)) {
             filesToDelete.push(file);
         }

+ 12 - 14
src/utils/search/index.ts

@@ -1,12 +1,12 @@
-import { DateValue, Suggestion, SuggestionType } from 'components/SearchBar';
-import { File } from 'services/fileService';
-import { Bbox } from 'services/searchService';
+import {DateValue} from 'components/SearchBar';
+import {File} from 'services/fileService';
+import {Bbox} from 'services/searchService';
 
 export function isInsideBox(
     file: { longitude: number; latitude: number },
-    bbox: Bbox
+    bbox: Bbox,
 ) {
-    if (file.latitude == null && file.longitude == null) {
+    if (file.latitude === null && file.longitude === null) {
         return false;
     }
     if (
@@ -37,19 +37,17 @@ export const isSameDay = (baseDate: DateValue) => (compareDate: Date) => {
 
 export function getFilesWithCreationDay(
     files: File[],
-    searchedDate: DateValue
+    searchedDate: DateValue,
 ) {
     const isSearchedDate = isSameDay(searchedDate);
-    return files.filter((file) =>
-        isSearchedDate(new Date(file.metadata.creationTime / 1000))
-    );
+    return files.filter((file) => isSearchedDate(new Date(file.metadata.creationTime / 1000)));
 }
 export function getFormattedDate(date: DateValue) {
-    var options = {};
-    date.date && (options['day'] = 'numeric');
-    (date.month || date.month === 0) && (options['month'] = 'long');
-    date.year && (options['year'] = 'numeric');
+    const options = {};
+    date.date && (options.day = 'numeric');
+    (date.month || date.month === 0) && (options.month = 'long');
+    date.year && (options.year = 'numeric');
     return new Intl.DateTimeFormat('en-IN', options).format(
-        new Date(date.year ?? 1, date.month ?? 1, date.date ?? 1)
+        new Date(date.year ?? 1, date.month ?? 1, date.date ?? 1),
     );
 }

+ 5 - 5
src/utils/sentry/index.ts

@@ -1,5 +1,5 @@
 import * as Sentry from '@sentry/node';
-import { RewriteFrames, CaptureConsole } from '@sentry/integrations';
+import {RewriteFrames, CaptureConsole} from '@sentry/integrations';
 
 export const sentryInit = () => {
     if (process.env.NEXT_PUBLIC_SENTRY_DSN) {
@@ -16,21 +16,21 @@ export const sentryInit = () => {
                     iteratee: (frame) => {
                         frame.filename = frame.filename.replace(
                             process.env.NEXT_PUBLIC_SENTRY_SERVER_ROOT_DIR,
-                            'app:///'
+                            'app:///',
                         );
                         frame.filename = frame.filename.replace(
                             '.next',
-                            '_next'
+                            '_next',
                         );
                         return frame;
                     },
-                })
+                }),
             );
         }
         integrations.push(
             new CaptureConsole({
                 levels: ['error'],
-            })
+            }),
         );
 
         Sentry.init({

+ 5 - 7
src/utils/storage/index.ts

@@ -1,15 +1,13 @@
-import { getData, LS_KEYS, setData } from './localStorage';
+import {getData, LS_KEYS, setData} from './localStorage';
 
-export const isFirstLogin = () =>
-    getData(LS_KEYS.IS_FIRST_LOGIN)?.status ?? false;
+export const isFirstLogin = () => getData(LS_KEYS.IS_FIRST_LOGIN)?.status ?? false;
 
 export function setIsFirstLogin(status) {
-    setData(LS_KEYS.IS_FIRST_LOGIN, { status });
+    setData(LS_KEYS.IS_FIRST_LOGIN, {status});
 }
 
-export const justSignedUp = () =>
-    getData(LS_KEYS.JUST_SIGNED_UP)?.status ?? false;
+export const justSignedUp = () => getData(LS_KEYS.JUST_SIGNED_UP)?.status ?? false;
 
 export function setJustSignedUp(status) {
-    setData(LS_KEYS.JUST_SIGNED_UP, { status });
+    setData(LS_KEYS.JUST_SIGNED_UP, {status});
 }

+ 3 - 2
src/utils/storage/localForage.ts

@@ -1,5 +1,6 @@
-import { runningInBrowser } from 'utils/common';
-const localForage: LocalForage = runningInBrowser() && require('localforage');
+import {runningInBrowser} from 'utils/common';
+
+const localForage = runningInBrowser() && require('localforage');
 
 if (runningInBrowser()) {
     localForage.config({

+ 1 - 1
src/utils/strings/constants.ts

@@ -1,4 +1,4 @@
-import { getConstantValue } from './vernacularStrings';
+import {getConstantValue} from './vernacularStrings';
 
 const constants = getConstantValue();
 export default constants;

+ 89 - 68
src/utils/strings/englishConstants.tsx

@@ -1,10 +1,10 @@
-import constants from './constants';
+import React from 'react';
 
 /**
  * Global English constants.
  */
 
-const dateString = function (date) {
+const dateString = function(date) {
     return new Date(date / 1000).toLocaleDateString('en-US', {
         year: 'numeric',
         month: 'long',
@@ -19,14 +19,14 @@ const englishConstants = {
     ENTER_NAME: 'your name',
     EMAIL: 'email',
     ENTER_EMAIL: 'email',
-    DATA_DISCLAIMER: `we'll never share your data with anyone else.`,
+    DATA_DISCLAIMER: 'we\'ll never share your data with anyone else.',
     SUBMIT: 'submit',
     EMAIL_ERROR: 'enter a valid email',
     REQUIRED: 'required',
     VERIFY_EMAIL: 'verify email',
-    EMAIL_SENT: ({ email }) => (
+    EMAIL_SENT: ({email}) => (
         <p>
-            we have sent a mail to <b>{email}</b>
+        we have sent a mail to <b>{email}</b>
         </p>
     ),
     CHECK_INBOX: 'please check your inbox (and spam) to complete verification',
@@ -46,43 +46,44 @@ const englishConstants = {
         'please enter a password that we can use to encrypt your data',
     PASSPHRASE_DISCLAIMER: () => (
         <p>
-            we don't store your password, so if you forget,
-            <strong> we will not be able to help you</strong> recover your data.
+        we don't store your password, so if you forget,
+            <strong> we will not be able to help you</strong>
+            {' '}
+        recover your data.
         </p>
     ),
     PASSPHRASE_HINT: 'password',
     RE_ENTER_PASSPHRASE: 'password again',
     CONFIRM_PASSPHRASE: 'confirm your password',
-    PASSPHRASE_MATCH_ERROR: `passwords don't match`,
+    PASSPHRASE_MATCH_ERROR: 'passwords don\'t match',
     CONSOLE_WARNING_STOP: 'STOP!',
-    CONSOLE_WARNING_DESC: `This is a browser feature intended for developers. Please don't copy-paste unverified code here.`,
-    SELECT_COLLECTION: `select an album to upload to`,
-    CREATE_COLLECTION: `create album`,
+    CONSOLE_WARNING_DESC: 'This is a browser feature intended for developers. Please don\'t copy-paste unverified code here.',
+    SELECT_COLLECTION: 'select an album to upload to',
+    CREATE_COLLECTION: 'create album',
     ENTER_ALBUM_NAME: 'album name',
     CLOSE: 'close',
     NO: 'no',
-    NOTHING_HERE: `nothing to see here, yet`,
+    NOTHING_HERE: 'nothing to see here, yet',
     UPLOAD: {
         0: 'preparing to upload',
         1: 'reading google metadata files',
-        2: (fileCounter) =>
-            `${fileCounter.finished} / ${fileCounter.total} files backed up`,
+        2: (fileCounter) => `${fileCounter.finished} / ${fileCounter.total} files backed up`,
         3: 'backup complete!',
     },
-    UPLOADING_FILES: `file upload`,
+    UPLOADING_FILES: 'file upload',
     FAILED_UPLOAD_FILE_LIST: 'upload failed for following files',
     FILE_UPLOAD_PROGRESS: (name, progress) => (
         <div id={name}>
             <strong>{name}</strong>
-            {` - `}
+            {' - '}
             {(() => {
                 switch (progress) {
-                    case -1:
-                        return 'failed';
-                    case -2:
-                        return 'already uploaded, skipping...';
-                    default:
-                        return `${progress}%`;
+                case -1:
+                    return 'failed';
+                case -2:
+                    return 'already uploaded, skipping...';
+                default:
+                    return `${progress}%`;
                 }
             })()}
         </div>
@@ -94,7 +95,7 @@ const englishConstants = {
     INITIAL_LOAD_DELAY_WARNING: 'the first load may take some time',
     USER_DOES_NOT_EXIST: 'sorry, could not find a user with that email',
     UPLOAD_BUTTON_TEXT: 'upload',
-    NO_ACCOUNT: "don't have an account?",
+    NO_ACCOUNT: 'don\'t have an account?',
     ALBUM_NAME: 'album name',
     CREATE: 'create',
     DOWNLOAD: 'download',
@@ -122,7 +123,7 @@ const englishConstants = {
     SESSION_EXPIRED: 'session expired',
     SYNC_FAILED:
         'failed to sync with remote server, please refresh page to try again',
-    PASSWORD_GENERATION_FAILED: `your browser was unable to generate a strong enough password  that meets ente's encryption standards, please try using the mobile app or another browser`,
+    PASSWORD_GENERATION_FAILED: 'your browser was unable to generate a strong enough password  that meets ente\'s encryption standards, please try using the mobile app or another browser',
     CHANGE_PASSWORD: 'change password',
     GO_BACK: 'go back',
     DOWNLOAD_RECOVERY_KEY: 'recovery key',
@@ -133,7 +134,7 @@ const englishConstants = {
     RECOVER_KEY_GENERATION_FAILED:
         'recovery code could be generated, please try again',
     KEY_NOT_STORED_DISCLAIMER:
-        "we don't store this key, so please save this in a safe place",
+        'we don\'t store this key, so please save this in a safe place',
     RECOVERY_KEY_FILENAME: 'ente-recovery-key.txt',
     FORGOT_PASSWORD: 'forgot password?',
     RECOVER_ACCOUNT: 'recover account',
@@ -159,23 +160,26 @@ const englishConstants = {
     MESSAGE: 'message',
     INSTALL_MOBILE_APP: () => (
         <div>
-            install our{' '}
+        install our{' '}
             <a
                 href="https://play.google.com/store/apps/details?id=io.ente.photos"
                 target="_blank"
-                style={{ color: '#2dc262' }}
+                style={{color: '#2dc262'}} rel="noreferrer"
             >
-                android
-            </a>{' '}
-            or{' '}
+              android
+            </a>
+            {' '}
+        or
+            {' '}
             <a
                 href="https://apps.apple.com/in/app/ente-photos/id1542026904"
-                style={{ color: '#2dc262' }}
-                target="_blank"
+                style={{color: '#2dc262'}}
+                target="_blank" rel="noreferrer"
             >
-                ios app{' '}
+              ios app
+                {' '}
             </a>
-            to automatically backup all your photos
+        to automatically backup all your photos
         </div>
     ),
     DOWNLOAD_APP_MESSAGE: () => (
@@ -204,39 +208,47 @@ const englishConstants = {
     FREE_SUBSCRIPTION_INFO: (expiryTime) => (
         <>
             <p>
-                you are on the <strong>free</strong> plan that expires on{' '}
+            you are on the <strong>free</strong>
+                {' '}
+            plan that expires on{' '}
                 {dateString(expiryTime)}
             </p>
         </>
     ),
     RENEWAL_ACTIVE_SUBSCRIPTION_INFO: (expiryTime) => (
-        <p>your subscription will renew on {dateString(expiryTime)}</p>
+        <p>
+        your subscription will renew on{dateString(expiryTime)}
+        </p>
     ),
 
     RENEWAL_CANCELLED_SUBSCRIPTION_INFO: (expiryTime) => (
         <>
             <p>
-                your subscription will be cancelled on {dateString(expiryTime)}
+            your subscription will be cancelled on {dateString(expiryTime)}
             </p>
         </>
     ),
 
     USAGE_INFO: (usage, quota) => (
         <p>
-            you have used {usage} GB out of your {quota} GB quota
+        you have used {usage}
+            {' '}
+        GB out of your{quota}
+            {' '}
+        GB quota
         </p>
     ),
 
     SUBSCRIPTION_PURCHASE_SUCCESS: (expiryTime) => (
         <>
             <p>we've received your payment</p>
-            your subscription is valid till{' '}
+        your subscription is valid till{' '}
             <strong>{dateString(expiryTime)}</strong>
         </>
     ),
     SUBSCRIPTION_PURCHASE_CANCELLED:
         'your purchase was canceled, please try again if you want to subscribe',
-    SUBSCRIPTION_VERIFICATION_FAILED: `we were not able to verify your purchase, verification can take few hours`,
+    SUBSCRIPTION_VERIFICATION_FAILED: 'we were not able to verify your purchase, verification can take few hours',
     SUBSCRIPTION_PURCHASE_FAILED:
         'subscription purchase failed , please try again later',
 
@@ -253,8 +265,8 @@ const englishConstants = {
     CANCEL_SUBSCRIPTION_MESSAGE: () => (
         <>
             <p>
-                all of your data will be deleted from our servers at the end of
-                this billing period.
+            all of your data will be deleted from our servers at the end of
+            this billing period.
             </p>
             <p>are you sure that you want to unsubscribe?</p>
         </>
@@ -264,13 +276,12 @@ const englishConstants = {
 
     ACTIVATE_SUBSCRIPTION: 'reactivate subscription',
     CONFIRM_ACTIVATE_SUBSCRIPTION: 'confirm subscription activation',
-    ACTIVATE_SUBSCRIPTION_MESSAGE: (expiryTime) =>
-        `once reactivated, you will be billed on ${dateString(expiryTime)}`,
+    ACTIVATE_SUBSCRIPTION_MESSAGE: (expiryTime) => `once reactivated, you will be billed on ${dateString(expiryTime)}`,
     SUBSCRIPTION_ACTIVATE_SUCCESS: 'subscription successfully activated',
     SUBSCRIPTION_ACTIVATE_FAILED: 'failed to reactivate subscription renewals',
 
     SUBSCRIPTION_PURCHASE_SUCCESS_TITLE: 'thank you',
-    CANCEL_SUBSCRIPTION_ON_MOBILE: `please cancel your subscription from the mobile app to activate a subscription here`,
+    CANCEL_SUBSCRIPTION_ON_MOBILE: 'please cancel your subscription from the mobile app to activate a subscription here',
     RENAME: 'rename',
     RENAME_COLLECTION: 'rename album',
     CONFIRM_DELETE_COLLECTION: 'confirm album deletion',
@@ -280,8 +291,8 @@ const englishConstants = {
         <>
             <p>are you sure you want to delete this album?</p>
             <p>
-                all files that are present only in this album will be
-                permanently deleted
+            all files that are present only in this album will be
+            permanently deleted
             </p>
         </>
     ),
@@ -292,43 +303,53 @@ const englishConstants = {
     ZERO_SHAREES: () => (
         <>
             <p>currently shared with no one 😔</p>
-            <em style={{ color: '#777' }}>"memories are fonder when shared"</em>
+            <em style={{color: '#777'}}>"memories are fonder when shared"</em>
         </>
     ),
     SHARE_WITH_SELF: 'oops, you cannot share with yourself',
-    ALREADY_SHARED: (email) =>
-        `oops, you're already sharing this with ${email}`,
+    ALREADY_SHARED: (email) => `oops, you're already sharing this with ${email}`,
     SHARING_BAD_REQUEST_ERROR: 'sharing album not allowed',
     SHARING_DISABLED_FOR_FREE_ACCOUNTS: 'sharing is disabled for free accounts',
     CREATE_ALBUM_FAILED: 'failed to create album , please try again',
     SEARCH_HINT: () => <span>New York, April 14, Christmas...</span>,
     TERMS_AND_CONDITIONS: () => (
         <p>
-            I agree to the{' '}
-            <a href="https://ente.io/terms" target="_blank">
-                terms
-            </a>{' '}
-            and{' '}
-            <a href="https://ente.io/privacy" target="_blank">
-                privacy policy
-            </a>{' '}
+        I agree to the{' '}
+            <a href="https://ente.io/terms" target="_blank" rel="noreferrer">
+            terms
+            </a>
+            {' '}
+        and
+            {' '}
+            <a href="https://ente.io/privacy" target="_blank" rel="noreferrer">
+            privacy policy
+            </a>
+            {' '}
         </p>
     ),
     CONFIRM_PASSWORD_NOT_SAVED: () => (
         <p>
-            i understand that if i lose my password , i may lose my data since
-            my data is{' '}
-            <a href="https://ente.io/encryption" target="_blank">
-                end-to-end encrypted
-            </a>{' '}
-            with ente
+        i understand that if i lose my password , i may lose my data since
+        my data is{' '}
+            <a href="https://ente.io/encryption" target="_blank" rel="noreferrer">
+            end-to-end encrypted
+            </a>
+            {' '}
+        with ente
         </p>
     ),
-    SEARCH_STATS: ({ resultCount, timeTaken }) => (
+    SEARCH_STATS: ({resultCount, timeTaken}) => (
         <span>
-            found <span style={{ color: '#2dc262' }}>{resultCount}</span>{' '}
-            memories ( <span style={{ color: '#2dc262' }}> {timeTaken}</span>{' '}
-            seconds )
+        found <span style={{color: '#2dc262'}}>{resultCount}</span>
+            {' '}
+        memories (
+            {' '}
+            <span style={{color: '#2dc262'}}>
+                {' '}
+                {timeTaken}
+            </span>
+            {' '}
+        seconds )
         </span>
     ),
 };

+ 6 - 5
src/utils/strings/vernacularStrings.ts

@@ -1,4 +1,4 @@
-import { runningInBrowser } from 'utils/common';
+import {runningInBrowser} from 'utils/common';
 import englishConstants from './englishConstants';
 
 /** Enums of supported locale */
@@ -15,6 +15,7 @@ export enum locale {
  *
  * @param strings
  * @param keys
+ * @returns string
  */
 export function template(strings: TemplateStringsArray, ...keys: string[]) {
     return (...values: any[]) => {
@@ -44,10 +45,10 @@ export type VernacularConstants<T> = {
  */
 export const getLocale = (lang: string) => {
     switch (lang) {
-        case locale.hi:
-            return locale.hi;
-        default:
-            return locale.en;
+    case locale.hi:
+        return locale.hi;
+    default:
+        return locale.en;
     }
 };
 

+ 6 - 3
src/worker/crypto.worker.js

@@ -6,7 +6,7 @@ export class Crypto {
         const encodedMetadata = await libsodium.decryptChaChaOneShot(
             await libsodium.fromB64(file.metadata.encryptedData),
             await libsodium.fromB64(file.metadata.decryptionHeader),
-            file.key
+            file.key,
         );
         return JSON.parse(new TextDecoder().decode(encodedMetadata));
     }
@@ -21,13 +21,13 @@ export class Crypto {
 
     async encryptMetadata(metadata, key) {
         const encodedMetadata = new TextEncoder().encode(
-            JSON.stringify(metadata)
+            JSON.stringify(metadata),
         );
 
         const {
             file: encryptedMetadata,
         } = await libsodium.encryptChaChaOneShot(encodedMetadata, key);
-        const { encryptedData, ...other } = encryptedMetadata;
+        const {encryptedData, ...other} = encryptedMetadata;
         return {
             file: {
                 encryptedData: await libsodium.toB64(encryptedData),
@@ -44,6 +44,7 @@ export class Crypto {
     async encryptFile(fileData, key) {
         return libsodium.encryptChaCha(fileData, key);
     }
+
     async encryptFileChunk(data, pushState, finalChunk) {
         return libsodium.encryptFileChunk(data, pushState, finalChunk);
     }
@@ -135,9 +136,11 @@ export class Crypto {
     async fromB64(string) {
         return libsodium.fromB64(string);
     }
+
     async toHex(string) {
         return libsodium.toHex(string);
     }
+
     async fromHex(string) {
         return libsodium.fromHex(string);
     }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 642 - 13
yarn.lock


Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů