diff options
| author | jackyzha0 <[email protected]> | 2021-04-11 10:27:27 -0700 |
|---|---|---|
| committer | jackyzha0 <[email protected]> | 2021-04-11 10:27:27 -0700 |
| commit | 0144bfc9cc6c616a00a8171f3950a75ec948427e (patch) | |
| tree | 101d6c12471d411e9266cffa8e90176aff2e6fdb /frontend/src/components | |
| parent | base next bump (diff) | |
| download | ctrl-v-0144bfc9cc6c616a00a8171f3950a75ec948427e.tar.xz ctrl-v-0144bfc9cc6c616a00a8171f3950a75ec948427e.zip | |
base next refactor
Diffstat (limited to 'frontend/src/components')
| -rw-r--r-- | frontend/src/components/PasteInfo.js | 6 | ||||
| -rw-r--r-- | frontend/src/components/hooks/shared.js | 74 | ||||
| -rw-r--r-- | frontend/src/components/hooks/useFetchPaste.js | 67 | ||||
| -rw-r--r-- | frontend/src/components/modals/PasteModal.js | 8 | ||||
| -rw-r--r-- | frontend/src/components/pages/NewPaste.js | 150 | ||||
| -rw-r--r-- | frontend/src/components/pages/Raw.js | 16 | ||||
| -rw-r--r-- | frontend/src/components/pages/ViewPaste.js | 65 | ||||
| -rw-r--r-- | frontend/src/components/renderers/Code.js | 2 | ||||
| -rw-r--r-- | frontend/src/components/renderers/InlineCode.js | 2 |
9 files changed, 9 insertions, 381 deletions
diff --git a/frontend/src/components/PasteInfo.js b/frontend/src/components/PasteInfo.js index 6ab5b19..2f912fb 100644 --- a/frontend/src/components/PasteInfo.js +++ b/frontend/src/components/PasteInfo.js @@ -1,8 +1,8 @@ import React from 'react'; import styled from 'styled-components' -import { useHistory } from 'react-router-dom'; import { Theme } from './Inputs' import {Button} from "./Common/Button"; +import {useRouter} from "next/router"; const Bold = styled.span` font-weight: 700 @@ -28,10 +28,10 @@ const Flex = styled.div` ` const PasteInfo = (props) => { - const history = useHistory(); + const router = useRouter() const redirRaw = () => { const redirUrl = `/raw/${props.hash}` - history.push(redirUrl); + router.push(redirUrl); } const renderable = () => { diff --git a/frontend/src/components/hooks/shared.js b/frontend/src/components/hooks/shared.js deleted file mode 100644 index 00d41e9..0000000 --- a/frontend/src/components/hooks/shared.js +++ /dev/null @@ -1,74 +0,0 @@ -import axios from 'axios'; - -// uncomment for local dev -// const base = `http://localhost:8080/api` -const base = `https://api.ctrl-v.app/api` -export function fetchPaste(hash, pass = "") { - const serverURL = `${base}/${hash}` - - if (pass === "") { - return axios.get(serverURL) - } else { - const bodyFormData = new FormData(); - bodyFormData.set('password', pass); - return axios({ - method: 'post', - url: `${base}/${hash}`, - data: bodyFormData, - headers: { 'Content-Type': 'multipart/form-data' }, - }) - } -} - -export function newPaste(paste) { - const {title, content, language, pass, expiry} = paste - const bodyFormData = new FormData(); - bodyFormData.set('title', title); - bodyFormData.set('content', content); - bodyFormData.set('language', language); - bodyFormData.set('password', pass); - bodyFormData.set('expiry', parseExpiry(expiry)); - - return axios({ - method: 'post', - url: base, - data: bodyFormData, - headers: { 'Content-Type': 'multipart/form-data' }, - }) -} - -export function parseExpiry(e) { - var cur = new Date(); - var inSeconds = 0 - switch (e) { - case '5 years': - inSeconds = 600 * 6 * 24 * 7 * 4 * 12 * 5 - break; - case '1 year': - inSeconds = 600 * 6 * 24 * 7 * 4 * 12 - break; - case '1 month': - inSeconds = 600 * 6 * 24 * 7 * 4 - break; - case '1 day': - inSeconds = 600 * 6 * 24 - break; - case '1 hour': - inSeconds = 600 * 6 - break; - case '10 min': - inSeconds = 600 - break; - case '1 week': - default: - inSeconds = 600 * 6 * 24 * 7 - break; - } - return new Date(cur.getTime() + inSeconds * 1000).toISOString(); -} - -export function fmtDateStr(dateString) { - const d = new Date(dateString) - const options = { hour: '2-digit', minute: '2-digit', year: 'numeric', month: 'long', day: 'numeric' } - return d.toLocaleDateString("en-US", options).toLocaleLowerCase() -}
\ No newline at end of file diff --git a/frontend/src/components/hooks/useFetchPaste.js b/frontend/src/components/hooks/useFetchPaste.js deleted file mode 100644 index c394f5b..0000000 --- a/frontend/src/components/hooks/useFetchPaste.js +++ /dev/null @@ -1,67 +0,0 @@ -import {useEffect, useState} from 'react' -import {fetchPaste, fmtDateStr} from './shared' -import {LANGS} from "../renderers/Code"; - -export default (id) => { - const [loading, setLoading] = useState(true) - const [err, setErr] = useState() - const [requiresAuth, setRequiresAuth] = useState(false) - const [validPass, setValidPass] = useState(false) - const [result, setResult] = useState({ - title: 'fetching paste...', - content: '', - language: LANGS.detect, - expiry: '', - }) - - const handleErr = error => { - const resp = error.response - - // network err - if (!resp) { - setErr(error.toString()) - return - } - - // password protected - if (resp.status === 401) { - setRequiresAuth(true) - return - } - - // catch all - const errTxt = `${resp.status}: ${resp.data}` - setErr(errTxt) - } - - // callback to try verifying with password - const getWithPassword = (password, errorCallback) => { - fetchPaste(id, password) - .then(resp => { - setValidPass(true) - setStateFromData(resp.data) - }) - .catch(e => errorCallback(e.response.data)) - } - - - const setStateFromData = (data) => { - document.title = data.title - setResult({ - title: data.title, - content: data.content, - language: data.language, - expiry: fmtDateStr(data.expiry) - }) - } - - // initial fetch - useEffect(() => { - fetchPaste(id) - .then(resp => setStateFromData(resp.data)) - .catch(handleErr) - .finally(() => setLoading(false)) - }, [id]) - - return { loading, err, requiresAuth, validPass, getWithPassword, result } -}
\ No newline at end of file diff --git a/frontend/src/components/modals/PasteModal.js b/frontend/src/components/modals/PasteModal.js index e7dbed2..a0fd309 100644 --- a/frontend/src/components/modals/PasteModal.js +++ b/frontend/src/components/modals/PasteModal.js @@ -1,21 +1,21 @@ import React from 'react'; import Modal from 'react-modal'; import {Form, ModalHeader, modalStyles} from './shared' -import { useHistory } from 'react-router-dom'; +import { useRouter } from 'next/router' import { Text } from '../Inputs' import { useClipboard } from 'use-clipboard-copy'; import {Button} from "../Common/Button"; const PasteModal = (props) => { - const history = useHistory(); - const fullURL = `${window.location.origin}/${props.hash}`; + const fullURL = `https://ctrl-v.app/${props.hash}`; const clipboard = useClipboard({ copiedTimeout: 3000 }); Modal.setAppElement('body'); + const router = useRouter() const redir = (e) => { e.preventDefault(); const redirUrl = `/${props.hash}` - history.push(redirUrl); + router.push(redirUrl); } return ( diff --git a/frontend/src/components/pages/NewPaste.js b/frontend/src/components/pages/NewPaste.js deleted file mode 100644 index 19161da..0000000 --- a/frontend/src/components/pages/NewPaste.js +++ /dev/null @@ -1,150 +0,0 @@ -import React, { useEffect, useState, useRef } from 'react'; -import { Text, Code } from '../Inputs' -import OptionsContainer from '../Options' -import Error from '../Err' -import PasteModal from '../modals/PasteModal' -import styled from 'styled-components' -import CodeRenderer from '../renderers/Code' -import Latex from '../renderers/Latex' -import Markdown from '../renderers/Markdown' -import {Button, SubmitButton} from "../Common/Button"; -import {newPaste} from "../hooks/shared"; - -const Flex = styled.div` - display: flex; - flex-direction: row; -` - -const FlexLeft = styled.div` - flex: 0 0 calc(50% - 1em - 2px); -` - -const FlexRight = styled.div` - flex: 0 0 50%; - max-width: calc(50% - 1em + 2px); - margin-left: 2em; -` - -const PreviewWrapper = styled.div` - margin: 2em; -` - -const NewPaste = () => { - const [title, setTitle] = useState(''); - const [content, setContent] = useState(''); - const [pass, setPass] = useState(''); - const [language, setLanguage] = useState('detect'); - const [expiry, setExpiry] = useState(''); - const [hash, setHash] = useState(''); - const [isPreview, setIsPreview] = useState(false); - const ErrorLabel = useRef(null); - - useEffect(() => { - document.title = title === "" ? `ctrl-v` : `ctrl-v | ${title}`; - }, [title]) - - function handleSubmit(e) { - e.preventDefault(); - - // prevent resubmission - if (!hash) { - newPaste({title, content, language, pass, expiry}) - .then(resp => {setHash(resp.data.hash)}) - .catch((error) => { - const resp = error.response - - // some weird err (e.g. network) - if (!resp) { - ErrorLabel.current.showMessage(error) - return - } - - // some weird err - const errTxt = `${resp.status}: ${resp.data}` - ErrorLabel.current.showMessage(errTxt) - }); - } - } - - function renderPreview() { - const pasteInput = <Code - setContentCallback={setContent} - content={content} - maxLength="100000" /> - - if (isPreview) { - var preview - switch (language) { - case 'latex': - preview = - <PreviewWrapper> - <Latex - content={content} /> - </PreviewWrapper> - break - case 'markdown': - preview = - <PreviewWrapper className='md' > - <Markdown - content={content} /> - </PreviewWrapper> - break - default: - preview = - <CodeRenderer - lang={language} - theme='atom' - content={content} /> - } - - return ( - <Flex> - <FlexLeft> - {pasteInput} - </FlexLeft> - <FlexRight className='preview' > - {preview} - </FlexRight> - </Flex> - ); - } else { - return ( - pasteInput - ); - } - } - - return ( - <form onSubmit={handleSubmit}> - <PasteModal hash={hash} /> - <Text - label="title" - onChange={(e) => {setTitle(e.target.value)}} - value={title} - autoFocus - maxLength="100" - id="titleInput" /> - {renderPreview()} - <OptionsContainer - pass={pass} - expiry={expiry} - lang={language} - onPassChange={(e) => { setPass(e.target.value) }} - onLangChange={(e) => { setLanguage(e.target.value) }} - onExpiryChange={(e) => { setExpiry(e.target.value) }} /> - <div> - <SubmitButton type="submit" value="new paste" /> - {language !== 'detect' && <Button - secondary - type="button" - onClick={() => setIsPreview(!isPreview)}> - preview - </Button>} - </div> - <br /> - <Error ref={ErrorLabel} /> - </form> - ); -} - -export default NewPaste
\ No newline at end of file diff --git a/frontend/src/components/pages/Raw.js b/frontend/src/components/pages/Raw.js deleted file mode 100644 index 23ef6bf..0000000 --- a/frontend/src/components/pages/Raw.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import styled from 'styled-components' -import {CodeLike} from "../Common/mixins"; -import useFetchPaste from "../hooks/useFetchPaste"; - -const RawText = styled.pre` - ${CodeLike} - padding: 0 1em; -` - -const Raw = ({hash}) => { - const { err, result } = useFetchPaste(hash) - return <RawText>{result?.content || err}</RawText> -} - -export default Raw
\ No newline at end of file diff --git a/frontend/src/components/pages/ViewPaste.js b/frontend/src/components/pages/ViewPaste.js deleted file mode 100644 index bc61314..0000000 --- a/frontend/src/components/pages/ViewPaste.js +++ /dev/null @@ -1,65 +0,0 @@ -import React, { useEffect, useState, useRef } from 'react'; -import Error from '../Err'; -import { Text } from '../Inputs'; -import CodeRenderer from '../renderers/Code' -import PasteInfo from '../PasteInfo'; -import PasswordModal from '../modals/PasswordModal' -import RenderDispatch from '../renderers/RenderDispatch' -import useFetchPaste from "../hooks/useFetchPaste"; - -const ViewPaste = (props) => { - const { err, requiresAuth, validPass, getWithPassword, result } = useFetchPaste(props.hash) - const {content, language, expiry, title} = result ?? {} - const [theme, setTheme] = useState('atom'); - const [isRenderMode, setIsRenderMode] = useState(false); - const [enteredPass, setEnteredPass] = useState(''); - const ErrorLabelRef = useRef(null); - - if (err) { - ErrorLabelRef.current.showMessage(err, -1) - } - - useEffect(() => { - setIsRenderMode(language === 'latex' || language === 'markdown') - }, [language]) - - function getDisplay() { - return isRenderMode ? <RenderDispatch - language={language} - content={content} - /> : <CodeRenderer - content={content} - lang={language} - theme={theme} - id="pasteInput" /> - } - - return ( - <div> - <PasswordModal - hasPass={requiresAuth} - validPass={validPass} - value={enteredPass} - onChange={(e) => setEnteredPass(e.target.value)} - validateCallback={getWithPassword} /> - <Text - label="title" - value={title} - id="titleInput" - readOnly /> - {getDisplay()} - <PasteInfo - hash={props.hash} - lang={language} - theme={theme} - expiry={expiry} - toggleRenderCallback={() => setIsRenderMode(!isRenderMode)} - isRenderMode={isRenderMode} - onChange={(e) => setTheme(e.target.value)} - err={<Error ref={ErrorLabelRef} />} - /> - </div> - ); -} - -export default ViewPaste
\ No newline at end of file diff --git a/frontend/src/components/renderers/Code.js b/frontend/src/components/renderers/Code.js index 29531fc..85fd5ab 100644 --- a/frontend/src/components/renderers/Code.js +++ b/frontend/src/components/renderers/Code.js @@ -1,7 +1,7 @@ import React from 'react'; import SyntaxHighlighter from 'react-syntax-highlighter'; import virtualizedRenderer from 'react-syntax-highlighter-virtualized-renderer'; -import { atomOneLight, ascetic, atomOneDark, dracula, ocean } from 'react-syntax-highlighter/dist/esm/styles/hljs'; +import { atomOneLight, ascetic, atomOneDark, dracula, ocean } from 'react-syntax-highlighter/dist/cjs/styles/hljs'; import styled from 'styled-components' import {Border, CodeLike, DropShadow, Rounded} from "../Common/mixins"; diff --git a/frontend/src/components/renderers/InlineCode.js b/frontend/src/components/renderers/InlineCode.js index 44a3f58..2156503 100644 --- a/frontend/src/components/renderers/InlineCode.js +++ b/frontend/src/components/renderers/InlineCode.js @@ -1,6 +1,6 @@ import React from 'react'; import SyntaxHighlighter from 'react-syntax-highlighter'; -import { atomOneDark } from 'react-syntax-highlighter/dist/esm/styles/hljs'; +import { atomOneDark } from 'react-syntax-highlighter/dist/cjs/styles/hljs'; import { LANGS } from './Code' const MarkdownCodeRenderer = ({language, value}) => { |