From 824899760a59eb956c66461ada44a0360b4b07fa Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Thu, 12 Jan 2023 14:00:46 +0800 Subject: [PATCH] Update some style, add Matter archive importer tool --- .../importers/uploadImportFileResolver.ts | 4 +- .../templates/ConfirmProfileModal.tsx | 17 +- .../components/templates/ProfileLayout.tsx | 7 +- .../templates/auth/EmailForgotPassword.tsx | 8 +- .../components/templates/auth/EmailLogin.tsx | 8 +- .../templates/auth/EmailResetPassword.tsx | 8 +- .../components/templates/auth/EmailSignup.tsx | 13 +- packages/web/pages/invite/[inviteCode].tsx | 8 +- packages/web/pages/tools/import/file.tsx | 3 +- .../web/pages/tools/import/matter-archive.tsx | 218 ++++++++++++++++++ 10 files changed, 262 insertions(+), 32 deletions(-) create mode 100644 packages/web/pages/tools/import/matter-archive.tsx diff --git a/packages/api/src/resolvers/importers/uploadImportFileResolver.ts b/packages/api/src/resolvers/importers/uploadImportFileResolver.ts index 544f97dc6..4b37cfb2f 100644 --- a/packages/api/src/resolvers/importers/uploadImportFileResolver.ts +++ b/packages/api/src/resolvers/importers/uploadImportFileResolver.ts @@ -18,7 +18,7 @@ import { v4 as uuidv4 } from 'uuid' import { buildLogger } from '../../utils/logger' const MAX_DAILY_UPLOADS = 4 -const VALID_CONTENT_TYPES = ['text/csv'] +const VALID_CONTENT_TYPES = ['text/csv', 'application/zip'] const logger = buildLogger('app.dispatch') @@ -26,6 +26,8 @@ const extensionForContentType = (contentType: string) => { switch (contentType) { case 'text/csv': return 'csv' + case 'application/zip': + return 'zip' } return '.unknown' } diff --git a/packages/web/components/templates/ConfirmProfileModal.tsx b/packages/web/components/templates/ConfirmProfileModal.tsx index 72a939947..a61766932 100644 --- a/packages/web/components/templates/ConfirmProfileModal.tsx +++ b/packages/web/components/templates/ConfirmProfileModal.tsx @@ -15,9 +15,8 @@ export function ConfirmProfileModal(): JSX.Element { const [username, setUsername] = useState('') const [debouncedUsername, setDebouncedUsername] = useState('') const [bio, setBio] = useState('') - const [errorMessage, setErrorMessage] = useState( - undefined - ) + const [errorMessage, setErrorMessage] = + useState(undefined) const { isUsernameValid, usernameErrorMessage } = useValidateUsernameQuery({ username: debouncedUsername, @@ -110,8 +109,9 @@ export function ConfirmProfileModal(): JSX.Element { @@ -139,7 +139,12 @@ export function ConfirmProfileModal(): JSX.Element { {isUsernameValid && ( Username is available. diff --git a/packages/web/components/templates/ProfileLayout.tsx b/packages/web/components/templates/ProfileLayout.tsx index 874b30c89..e2d3d6b1a 100644 --- a/packages/web/components/templates/ProfileLayout.tsx +++ b/packages/web/components/templates/ProfileLayout.tsx @@ -12,7 +12,12 @@ export function ProfileLayout(props: ProfileLayoutProps): JSX.Element { {props.children} diff --git a/packages/web/components/templates/auth/EmailForgotPassword.tsx b/packages/web/components/templates/auth/EmailForgotPassword.tsx index b2fca77da..c97a222fc 100644 --- a/packages/web/components/templates/auth/EmailForgotPassword.tsx +++ b/packages/web/components/templates/auth/EmailForgotPassword.tsx @@ -12,9 +12,8 @@ import { parseErrorCodes } from '../../../lib/queryParamParser' export function EmailForgotPassword(): JSX.Element { const router = useRouter() const [email, setEmail] = useState('') - const [errorMessage, setErrorMessage] = useState( - undefined - ) + const [errorMessage, setErrorMessage] = + useState(undefined) useEffect(() => { if (!router.isReady) return @@ -36,7 +35,8 @@ export function EmailForgotPassword(): JSX.Element { width: '70vw', maxWidth: '576px', borderRadius: '8px', - boxShadow: 'rgb(224 224 224) 9px 9px 9px -9px', + border: '1px solid #3D3D3D', + boxShadow: '#B1B1B1 9px 9px 9px -9px', }} > diff --git a/packages/web/components/templates/auth/EmailLogin.tsx b/packages/web/components/templates/auth/EmailLogin.tsx index 6d3533cb9..8175f329f 100644 --- a/packages/web/components/templates/auth/EmailLogin.tsx +++ b/packages/web/components/templates/auth/EmailLogin.tsx @@ -15,9 +15,8 @@ export function EmailLogin(): JSX.Element { const router = useRouter() const [email, setEmail] = useState(undefined) const [password, setPassword] = useState(undefined) - const [errorMessage, setErrorMessage] = useState( - undefined - ) + const [errorMessage, setErrorMessage] = + useState(undefined) useEffect(() => { if (!router.isReady) return @@ -39,7 +38,8 @@ export function EmailLogin(): JSX.Element { width: '70vw', maxWidth: '576px', borderRadius: '8px', - boxShadow: 'rgb(224 224 224) 9px 9px 9px -9px', + border: '1px solid #3D3D3D', + boxShadow: '#B1B1B1 9px 9px 9px -9px', }} > diff --git a/packages/web/components/templates/auth/EmailResetPassword.tsx b/packages/web/components/templates/auth/EmailResetPassword.tsx index eafc284b2..10f378c8b 100644 --- a/packages/web/components/templates/auth/EmailResetPassword.tsx +++ b/packages/web/components/templates/auth/EmailResetPassword.tsx @@ -13,9 +13,8 @@ export function EmailResetPassword(): JSX.Element { const router = useRouter() const [token, setToken] = useState(undefined) const [password, setPassword] = useState('') - const [errorMessage, setErrorMessage] = useState( - undefined - ) + const [errorMessage, setErrorMessage] = + useState(undefined) useEffect(() => { if (!router.isReady) return @@ -45,7 +44,8 @@ export function EmailResetPassword(): JSX.Element { width: '70vw', maxWidth: '576px', borderRadius: '8px', - boxShadow: 'rgb(224 224 224) 9px 9px 9px -9px', + border: '1px solid #3D3D3D', + boxShadow: '#B1B1B1 9px 9px 9px -9px', }} > (undefined) const [fullname, setFullname] = useState(undefined) const [username, setUsername] = useState(undefined) - const [debouncedUsername, setDebouncedUsername] = useState< - string | undefined - >(undefined) - const [errorMessage, setErrorMessage] = useState( - undefined - ) + const [debouncedUsername, setDebouncedUsername] = + useState(undefined) + const [errorMessage, setErrorMessage] = + useState(undefined) useEffect(() => { if (!router.isReady) return @@ -60,7 +58,8 @@ export function EmailSignup(): JSX.Element { width: '70vw', maxWidth: '576px', borderRadius: '8px', - boxShadow: 'rgb(224 224 224) 9px 9px 9px -9px', + border: '1px solid #3D3D3D', + boxShadow: '#B1B1B1 9px 9px 9px -9px', }} > diff --git a/packages/web/pages/invite/[inviteCode].tsx b/packages/web/pages/invite/[inviteCode].tsx index 45e23276f..c95a7365d 100644 --- a/packages/web/pages/invite/[inviteCode].tsx +++ b/packages/web/pages/invite/[inviteCode].tsx @@ -17,9 +17,8 @@ export default function InvitePage(): JSX.Element { const router = useRouter() const { viewerData, viewerDataError, isLoading } = useGetViewerQuery() const { inviteCode } = router.query - const [errorMessage, setErrorMessage] = useState( - undefined - ) + const [errorMessage, setErrorMessage] = + useState(undefined) // Check if the user is logged in and display an error message if they are not useEffect(() => { @@ -77,7 +76,8 @@ export default function InvitePage(): JSX.Element { width: '70vw', maxWidth: '576px', borderRadius: '8px', - boxShadow: 'rgb(224 224 224) 9px 9px 9px -9px', + border: '1px solid #3D3D3D', + boxShadow: '#B1B1B1 9px 9px 9px -9px', }} > diff --git a/packages/web/pages/tools/import/file.tsx b/packages/web/pages/tools/import/file.tsx index d49b551b7..44096d324 100644 --- a/packages/web/pages/tools/import/file.tsx +++ b/packages/web/pages/tools/import/file.tsx @@ -96,7 +96,8 @@ export default function ImportUploader(): JSX.Element { width: '70vw', maxWidth: '576px', borderRadius: '8px', - boxShadow: 'rgb(224 224 224) 9px 9px 9px -9px', + border: '1px solid #3D3D3D', + boxShadow: '#B1B1B1 9px 9px 9px -9px', }} > () + const [file, setFile] = useState() + const [type, setType] = useState() + const [uploadState, setUploadState] = useState('none') + const { acceptedFiles, getRootProps, getInputProps } = useDropzone() + + const onDropAccepted = async (acceptedFiles: File[]) => { + const contentType = 'application/zip' + const file = acceptedFiles.find(() => true) + if (!file) { + setErrorMessage('No file selected.') + return + } + + setUploadState('uploading') + + try { + const result = await uploadImportFileRequestMutation( + UploadImportFileType.MATTER, + contentType + ) + + if (result && result.uploadSignedUrl) { + const uploadRes = await fetch(result.uploadSignedUrl, { + method: 'PUT', + body: file, + headers: { + 'content-type': contentType, + 'content-length': `${file.size}`, + }, + }) + setUploadState('completed') + } else { + setErrorMessage( + 'Unable to create file upload. Please ensure you are logged in.' + ) + setUploadState('none') + } + } catch (error) { + console.log('caught error', error) + if (error == 'UPLOAD_DAILY_LIMIT_EXCEEDED') { + setErrorMessage('You have exceeded your maximum daily upload limit.') + } + setUploadState('none') + } + } + + return ( + + + + Import Matter Archive + + + Omnivore supports uploading the Archive.zip file generated by + exporting your data from the Matter app. + + + To export your data from Matter, go to My Account, and choose Export + data, this will send you an email with your data in a file + Archive.zip. Upload that file using the uploader on this page. + + + More info + + + Note: Please note you are limited to three import uploads per a + day, and the maximum file size is 10MB. + + + {uploadState == 'completed' ? ( + + Your upload has completed. Please note that it can take some time + for your library to be updated. You will be sent an email when the + process completes. + + ) : ( + <> + + + {({ getRootProps, getInputProps }) => ( +
+ + + {uploadState == 'uploading' ? ( + + ) : ( + <> + + + Click or Drag Archive.zip file here to upload + + + )} + +
+ )} +
+
+ + )} + + {uploadState == 'completed' && ( + + + + )} + + {errorMessage && ( + {errorMessage} + )} +
+
+
+ ) +}