diff options
| author | Ryan Mehri <[email protected]> | 2020-07-18 22:20:19 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2020-07-18 22:20:19 -0600 |
| commit | 31ed54cd210df9784801bbf4c867c4d84b31abc5 (patch) | |
| tree | 762f5372454cd1af0a5c3123906d35259542fd96 /frontend/src/components | |
| parent | Merge pull request #50 from jackyzha0/cache-invalidation (diff) | |
| parent | refactor viewpaste and fixed button height (diff) | |
| download | ctrl-v-31ed54cd210df9784801bbf4c867c4d84b31abc5.tar.xz ctrl-v-31ed54cd210df9784801bbf4c867c4d84b31abc5.zip | |
Merge pull request #52 from jackyzha0/refactor-react
Refactor to use functional components instead of class components
Diffstat (limited to 'frontend/src/components')
| -rw-r--r-- | frontend/src/components/App.js | 2 | ||||
| -rw-r--r-- | frontend/src/components/Inputs.js | 233 | ||||
| -rw-r--r-- | frontend/src/components/NewPaste.js | 187 | ||||
| -rw-r--r-- | frontend/src/components/Options.js | 36 | ||||
| -rw-r--r-- | frontend/src/components/PasteInfo.js | 3 | ||||
| -rw-r--r-- | frontend/src/components/ViewPaste.js | 212 | ||||
| -rw-r--r-- | frontend/src/components/decorators/CharLimit.js | 10 | ||||
| -rw-r--r-- | frontend/src/components/decorators/FloatingLabel.js | 22 | ||||
| -rw-r--r-- | frontend/src/components/modals/PasswordModal.js | 72 | ||||
| -rw-r--r-- | frontend/src/components/renderers/Latex.js | 56 | ||||
| -rw-r--r-- | frontend/src/components/renderers/Raw.js | 75 |
11 files changed, 396 insertions, 512 deletions
diff --git a/frontend/src/components/App.js b/frontend/src/components/App.js index ae95dcb..0a5fb8b 100644 --- a/frontend/src/components/App.js +++ b/frontend/src/components/App.js @@ -38,7 +38,7 @@ const GetRawWithParam = () => { ); } -function App() { +const App = () => { return ( <Router> <Switch> diff --git a/frontend/src/components/Inputs.js b/frontend/src/components/Inputs.js index 08cf3fc..a9b08b7 100644 --- a/frontend/src/components/Inputs.js +++ b/frontend/src/components/Inputs.js @@ -15,43 +15,33 @@ const FlexChild = styled.div` margin-left: 2em; ` -class TitleInput extends React.Component { - render() { - return ( - <RelPositioning> - <FloatingLabel - label="title" - id={this.props.id} - value={this.props.value} /> - <input - name="title" - readOnly={this.props.readOnly} - className="lt-shadow" - placeholder="Title" - id={this.props.id} - type="text" - autoFocus - autoComplete="off" - onChange={this.props.onChange} - value={this.props.value} /> - <CharLimit - content={this.props.value} - maxLength={this.props.maxLength} /> - </RelPositioning> - ); - } +const TitleInput = (props) => { + return ( + <RelPositioning> + <FloatingLabel + label="title" + id={props.id} + value={props.value} /> + <input + name="title" + readOnly={props.readOnly} + className="lt-shadow" + placeholder="Title" + id={props.id} + type="text" + autoFocus + autoComplete="off" + onChange={props.onChange} + value={props.value} /> + <CharLimit + content={props.value} + maxLength={props.maxLength} /> + </RelPositioning> + ); } -class PasteInput extends React.Component { - - constructor(props) { - super(props) - - this.textArea = React.createRef() - this.handleKeyDown = this.handleKeyDown.bind(this) - } - - handleKeyDown(e) { +const PasteInput = (props) => { + function handleKeyDown(e) { if (e.keyCode === 9) { // tab was pressed // prevent autofocus on next intput @@ -61,96 +51,83 @@ class PasteInput extends React.Component { const start = e.target.selectionStart const end = e.target.selectionEnd - this.props.insertTabCallback(start, end) + props.insertTabCallback(start, end) // set cursor position to be at start e.target.selectionEnd = end + 4; } } - render() { - return ( + return ( + <RelPositioning> + <FloatingLabel + label="content" + id={props.id} + value={props.content} /> + <textarea + name="content" + readOnly={props.readOnly} + placeholder="Paste your text here" + value={props.content} + id={props.id} + required + onChange={props.onChange} + onKeyDown={handleKeyDown} + className="lt-shadow" /> + <CharLimit + content={props.content} + maxLength={props.maxLength} /> + </RelPositioning> + ); +} + +const PassInput = (props) => { + return ( + <FlexChild> <RelPositioning> <FloatingLabel - label="content" - id={this.props.id} - value={this.props.content} /> - <textarea - name="content" - readOnly={this.props.readOnly} - placeholder="Paste your text here" - value={this.props.content} - id={this.props.id} - required - onChange={this.props.onChange} - onKeyDown={this.handleKeyDown} - className="lt-shadow" /> - <CharLimit - content={this.props.content} - maxLength={this.props.maxLength} /> + label="password" + id={props.id} + value={props.value} /> + <input + name="pass" + className="lt-shadow" + placeholder="password" + type="password" + autoComplete="off" + onChange={props.onChange} + value={props.value} + id={props.id} /> </RelPositioning> - ); - } -} - -class PassInput extends React.Component { - render() { - return ( - <FlexChild> - <RelPositioning> - <FloatingLabel - label="password" - id={this.props.id} - value={this.props.value} /> - <input - name="pass" - className="lt-shadow" - placeholder="password" - type="password" - autoComplete="off" - onChange={this.props.onChange} - value={this.props.value} - id={this.props.id} /> - </RelPositioning> - </FlexChild> - ); - } + </FlexChild> + ); } -class GenericDropdown extends React.Component { - - constructor(props) { - super(props) - - this._onSelect = this._onSelect.bind(this) - } - - _onSelect(option) { - this.props.onChange({ +const GenericDropdown = (props) => { + function _onSelect(option) { + props.onChange({ target: { - name: this.props.label, + name: props.label, value: option.label } }); } - render() { - return ( - <FlexChild> - <Dropdown - options={this.props.options} - onChange={this._onSelect} - callBackRef={this.props.onChange} - value={this.props.value} - placeholder={this.props.placeholder} - id={this.props.id} /> - <FloatingLabel - label={this.props.label} - id={this.props.id} - value={this.props.value} /> - </FlexChild> - ); - } + return ( + <FlexChild> + <Dropdown + options={props.options} + onChange={_onSelect} + callBackRef={props.onChange} + value={props.value} + placeholder={props.placeholder} + id={props.id} /> + <FloatingLabel + label={props.label} + id={props.id} + value={props.value} /> + </FlexChild> + ); } const ExpiryInput = (props) => { @@ -210,27 +187,25 @@ const ThemeInput = (props) => { ); } -class PasteURLInput extends React.Component { - render() { - return ( - <FlexChild> - <RelPositioning> - <FloatingLabel - label="url" - id={this.props.id} - value={this.props.id} /> - <input - name="paste_url" - className="lt-shadow" - type="text" - readOnly - autoFocus - id={this.props.id} - value={this.props.fullURL} /> - </RelPositioning> - </FlexChild> - ); - } +const PasteURLInput = ({id, fullURL}) => { + return ( + <FlexChild> + <RelPositioning> + <FloatingLabel + label="url" + id={id} + value={id} /> + <input + name="paste_url" + className="lt-shadow" + type="text" + readOnly + autoFocus + id={id} + value={fullURL} /> + </RelPositioning> + </FlexChild> + ); } export { TitleInput, PasteInput, PassInput, ExpiryInput, PasteURLInput, LangInput, ThemeInput }
\ No newline at end of file diff --git a/frontend/src/components/NewPaste.js b/frontend/src/components/NewPaste.js index afe1fc3..9729655 100644 --- a/frontend/src/components/NewPaste.js +++ b/frontend/src/components/NewPaste.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import { TitleInput, PasteInput } from './Inputs' import OptionsContainer from './Options' import Error from './Err' @@ -35,114 +35,85 @@ const PreviewWrapper = styled.div` margin: 2em; ` -class NewPaste extends React.Component { - constructor(props) { - super(props); - this.state = { - title: '', - content: '', - pass: '', - language: LANGS.raw, - expiry: '', - hash: '', - error: '', - preview: false, - }; - - this.handleChange = this.handleChange.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); - this.togglePreview = this.togglePreview.bind(this); - this.renderPreview = this.renderPreview.bind(this); - this.insertTab = this.insertTab.bind(this); - this.ErrorLabel = React.createRef(); - } - - componentDidUpdate() { - if (this.state.title === "") { +const NewPaste = () => { + const [title, setTitle] = useState(''); + const [content, setContent] = useState(''); + const [pass, setPass] = useState(''); + const [language, setLanguage] = useState(LANGS.raw); + const [expiry, setExpiry] = useState(''); + const [hash, setHash] = useState(''); + const [isPreview, setIsPreview] = useState(false); + const ErrorLabel = useRef(null); + + useEffect(() => { + if (title === "") { document.title = `ctrl-v`; } else { - document.title = `ctrl-v | ${this.state.title}`; + document.title = `ctrl-v | ${title}`; } - } - - handleChange(event) { - const target = event.target; - const name = target.name; + }, [title]) - this.setState({ - [name]: target.value - }); - } - - togglePreview() { - const state = this.state.preview - this.setState({ preview: !state }) - } - - handleSubmit(event) { - event.preventDefault(); + function handleSubmit(e) { + e.preventDefault(); // prevent resubmission - if (!this.state.hash) { - PostNewPaste(this.state) + if (!hash) { + PostNewPaste(title, content, language, pass, expiry) .then((response) => { // on success, redir - this.setState({ hash: response.data.hash }) + setHash(response.data.hash) }).catch((error) => { const resp = error.response // some weird err if (resp !== undefined) { const errTxt = `${resp.status}: ${resp.data}` - this.ErrorLabel.current.showMessage(errTxt) + ErrorLabel.current.showMessage(errTxt) } else { // some weird err (e.g. network) - this.ErrorLabel.current.showMessage(error) + ErrorLabel.current.showMessage(error) } }); } } - insertTab(start, end) { - const oldContent = this.state.content - this.setState({ - content: oldContent.substring(0, start) + ' ' + oldContent.substring(end) - }) + function insertTab(start, end) { + setContent(content.substring(0, start) + ' ' + content.substring(end)) } - renderPreview() { + function renderPreview() { const pasteInput = <PasteInput - onChange={this.handleChange} - insertTabCallback={this.insertTab} - content={this.state.content} + onChange={(e) => { setContent(e.target.value) }} + insertTabCallback={insertTab} + content={content} maxLength="100000" id="pasteInput" /> - var preview - switch (this.state.language) { - case 'latex': - preview = - <PreviewWrapper> - <Latex - content={this.state.content} /> - </PreviewWrapper> - break - case 'markdown': - preview = - <PreviewWrapper> - <Markdown - content={this.state.content} /> - </PreviewWrapper> - break - default: - preview = - <CodeRenderer - lang={this.state.language} - theme='atom' - content={this.state.content} /> - } + if (isPreview) { + var preview + switch (language) { + case 'latex': + preview = + <PreviewWrapper> + <Latex + content={content} /> + </PreviewWrapper> + break + case 'markdown': + preview = + <PreviewWrapper> + <Markdown + content={content} /> + </PreviewWrapper> + break + default: + preview = + <CodeRenderer + lang={language} + theme='atom' + content={content} /> + } - if (this.state.preview) { return ( <Flex> <FlexLeft> @@ -160,33 +131,33 @@ class NewPaste extends React.Component { } } - render() { - return ( - <form onSubmit={this.handleSubmit}> - <PasteModal hash={this.state.hash} /> - <TitleInput - onChange={this.handleChange} - value={this.state.title} - maxLength="100" - id="titleInput" /> - {this.renderPreview()} - <OptionsContainer - pass={this.state.pass} - expiry={this.state.expiry} - lang={this.state.language} - onChange={this.handleChange} /> - <input className="lt-button lt-shadow lt-hover" type="submit" value="new paste" /> - <Button - className="lt-shadow lt-hover" - type="button" - onClick={this.togglePreview} > - preview - </Button> - <br /> - <Error ref={this.ErrorLabel} /> - </form> - ); - } + return ( + <form onSubmit={handleSubmit}> + <PasteModal hash={hash} /> + <TitleInput + onChange={(e) => {setTitle(e.target.value)}} + value={title} + 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) }} /> + <input className="lt-button lt-shadow lt-hover" type="submit" value="new paste" /> + <Button + className="lt-shadow lt-hover" + type="button" + onClick={() => setIsPreview(!isPreview)}> + preview + </Button> + <br /> + <Error ref={ErrorLabel} /> + </form> + ); } export default NewPaste
\ No newline at end of file diff --git a/frontend/src/components/Options.js b/frontend/src/components/Options.js index 26391c1..09f92f3 100644 --- a/frontend/src/components/Options.js +++ b/frontend/src/components/Options.js @@ -14,25 +14,23 @@ const Flex = styled.div` } ` -class OptionsContainer extends React.Component { - render() { - return ( - <Flex> - <PassInput - value={this.props.pass} - onChange={this.props.onChange} - id="passwordInput" /> - <LangInput - value={this.props.lang} - onChange={this.props.onChange} - id="langInput" /> - <ExpiryInput - value={this.props.expiry} - onChange={this.props.onChange} - id="expiryInput" /> - </Flex> - ); - } +const OptionsContainer = ({pass, lang, expiry, onPassChange, onLangChange, onExpiryChange}) => { + return ( + <Flex> + <PassInput + value={pass} + onChange={onPassChange} + id="passwordInput" /> + <LangInput + value={lang} + onChange={onLangChange} + id="langInput" /> + <ExpiryInput + value={expiry} + onChange={onExpiryChange} + id="expiryInput" /> + </Flex> + ); } export default OptionsContainer
\ No newline at end of file diff --git a/frontend/src/components/PasteInfo.js b/frontend/src/components/PasteInfo.js index 8669b20..bab7e23 100644 --- a/frontend/src/components/PasteInfo.js +++ b/frontend/src/components/PasteInfo.js @@ -16,7 +16,8 @@ const StyledDiv = styled.div` const Button = styled.button` margin-right: 0 !important; margin-left: 2em !important; - height: calc(16px + 1.6em + 2px); + height: calc(16px + 1.6em); + margin-top: 1.6em !important; ` const SpacedText = styled.span` diff --git a/frontend/src/components/ViewPaste.js b/frontend/src/components/ViewPaste.js index 117bb18..ebdc950 100644 --- a/frontend/src/components/ViewPaste.js +++ b/frontend/src/components/ViewPaste.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import Error from './Err'; import { TitleInput } from './Inputs'; import CodeRenderer from './renderers/Code' @@ -8,173 +8,139 @@ import { FetchPaste, FetchPasswordPaste } from '../helpers/httpHelper' import { LANGS } from './renderers/Code' import RenderDispatch from './renderers/RenderDispatch' -class ViewPaste extends React.Component { - - constructor(props) { - super(props); - this.state = { - title: 'untitled paste', - content: '', - hasPass: false, - enteredPass: '', - validPass: false, - expiry: 'no expiry', - error: '', - passError: '', - theme: 'atom', - inRenderMode: false, - language: LANGS.raw, - }; - - this.handleChange = this.handleChange.bind(this); - this.typedPass = this.typedPass.bind(this); - this.toggleRender = this.toggleRender.bind(this); - this.validatePass = this.validatePass.bind(this); - this.ErrorLabel = React.createRef(); - this.PasswordModal = React.createRef(); - this.componentRef = React.createRef(); - } - - handleChange(event) { - const target = event.target; - const name = target.name; - - this.setState({ - [name]: target.value - }); - } - - typedPass(event) { - this.setState({ enteredPass: event.target.value }); - } - - toggleRender() { - this.setState({ isRenderMode: !this.state.isRenderMode }); - } +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() +} - validatePass(pass) { - FetchPasswordPaste(this.props.hash, pass) +const ViewPaste = (props) => { + const [title, setTitle] = useState('untitled paste'); + const [content, setContent] = useState(''); + const [hasPass, setHasPass] = useState(false); + const [enteredPass, setEnteredPass] = useState(''); + const [validPass, setValidPass] = useState(false); + const [expiry, setExpiry] = useState(''); + const [theme, setTheme] = useState('atom'); + const [isRenderMode, setIsRenderMode] = useState(false); + const [language, setLanguage] = useState(LANGS.raw); + + const ErrorLabelRef = useRef(null); + const PasswordModalRef = useRef(null); + const ComponentRef = useRef(null); + + function validatePass(pass, onErrorCallBack) { + FetchPasswordPaste(props.hash, pass) .then((response) => { - this.setState({ validPass: true }) - this.setStateFromData(response.data) + setValidPass(true) + setStateFromData(response.data) }).catch((error) => { const resp = error.response // 401 unauth (bad pass) if (resp.status === 401) { - this.PasswordModal.current - .ErrorLabel.current - .showMessage("incorrect pass") + onErrorCallBack("incorrect pass") return } // otherwise, just log it lmao if (resp !== undefined) { const errTxt = `${resp.status}: ${resp.data}` - this.ErrorLabel.current.showMessage(errTxt) + onErrorCallBack(errTxt) } else { // some weird err (e.g. network) - this.ErrorLabel.current.showMessage(error) + onErrorCallBack(error) } }); } - render() { - - var display - if (this.state.isRenderMode) { - display = - <RenderDispatch - language={this.state.language} - content={this.state.content} - ref={this.componentRef} - /> - } else { - display = - <CodeRenderer - content={this.state.content} - lang={this.state.language} - theme={this.state.theme} - ref={this.componentRef} - id="pasteInput" /> - } - - return ( - <div> - <PasswordModal - ref={this.PasswordModal} - hasPass={this.state.hasPass} - validPass={this.state.validPass} - value={this.state.enteredPass} - onChange={this.typedPass} - validateCallback={this.validatePass} /> - <TitleInput - value={this.state.title} - id="titleInput" - readOnly /> - {display} - <PasteInfo - hash={this.props.hash} - lang={this.state.language} - theme={this.state.theme} - expiry={this.state.expiry} - toggleRenderCallback={this.toggleRender} - isRenderMode={this.state.isRenderMode} - onChange={this.handleChange} - compref={this.componentRef} - err={<Error ref={this.ErrorLabel} />} - /> - </div> - ); - } - - 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() - } - - setStateFromData(data) { - console.log(data) - this.setState({ - title: data.title, - content: data.content, - language: data.language, - expiry: this.fmtDateStr(data.expiry), - }) + function setStateFromData(data) { + setTitle(data.title) + setContent(data.content) + setLanguage(data.language) + setExpiry(fmtDateStr(data.expiry)) } - componentDidMount() { - FetchPaste(this.props.hash) + useEffect(() => { + FetchPaste(props.hash) .then((response) => { const data = response.data - this.setStateFromData(data) + setStateFromData(data) }).catch((error) => { const resp = error.response // network err if (!resp) { - this.ErrorLabel.current.showMessage(error) + ErrorLabelRef.current.showMessage(error) return } // catch 401 unauth (password protected) if (resp.status === 401) { - this.setState({hasPass: true}) + setHasPass(true) return } // some weird err if (resp !== undefined) { const errTxt = `${resp.status}: ${resp.data}` - this.ErrorLabel.current.showMessage(errTxt, -1) + ErrorLabelRef.current.showMessage(errTxt, -1) return } // some weird err (e.g. network) - this.ErrorLabel.current.showMessage(error, -1) + ErrorLabelRef.current.showMessage(error, -1) }) + }, [props.hash]) + + function getDisplay() { + if (isRenderMode) { + return ( + <RenderDispatch + language={language} + content={content} + ref={ComponentRef} + /> + ) + } else { + return ( + <CodeRenderer + content={content} + lang={language} + theme={theme} + ref={ComponentRef} + id="pasteInput" /> + ) + } } + + return ( + <div> + <PasswordModal + ref={PasswordModalRef} + hasPass={hasPass} + validPass={validPass} + value={enteredPass} + onChange={(e) => setEnteredPass(e.target.value)} + validateCallback={validatePass} /> + <TitleInput + 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)} + compref={ComponentRef} + err={<Error ref={ErrorLabelRef} />} + /> + </div> + ); } export default ViewPaste
\ No newline at end of file diff --git a/frontend/src/components/decorators/CharLimit.js b/frontend/src/components/decorators/CharLimit.js index 623b378..5a6fdca 100644 --- a/frontend/src/components/decorators/CharLimit.js +++ b/frontend/src/components/decorators/CharLimit.js @@ -26,12 +26,10 @@ const Chars = styled.p` `}; `; -class CharLimit extends React.Component { - render() { - return ( - <Chars {...this.props} >{this.props.maxLength - this.props.content.length}/{this.props.maxLength}</Chars> - ); - } +const CharLimit = (props) => { + return ( + <Chars {...props} >{props.maxLength - props.content.length}/{props.maxLength}</Chars> + ); } export default CharLimit
\ No newline at end of file diff --git a/frontend/src/components/decorators/FloatingLabel.js b/frontend/src/components/decorators/FloatingLabel.js index e1fc0ba..ef56b44 100644 --- a/frontend/src/components/decorators/FloatingLabel.js +++ b/frontend/src/components/decorators/FloatingLabel.js @@ -17,18 +17,16 @@ const StyledLabel = styled.label` `}; ` -class FloatingLabel extends React.Component { - render() { - return ( - <StyledLabel - label={this.props.label} - value={this.props.value} - className={this.props.id} - htmlFor={this.props.id}> - {this.props.label} - </StyledLabel> - ); - } +const FloatingLabel = (props) => { + return ( + <StyledLabel + label={props.label} + value={props.value} + className={props.id} + htmlFor={props.id}> + {props.label} + </StyledLabel> + ); } export default FloatingLabel
\ No newline at end of file diff --git a/frontend/src/components/modals/PasswordModal.js b/frontend/src/components/modals/PasswordModal.js index 527fc54..bf373cc 100644 --- a/frontend/src/components/modals/PasswordModal.js +++ b/frontend/src/components/modals/PasswordModal.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useRef } from 'react'; import Modal from 'react-modal'; import { PassInput } from '../Inputs' import { RightPad, LeftPad, ModalHeader, Padding } from './shared' @@ -15,49 +15,39 @@ const modalStyles = { } }; -class PasswordModal extends React.Component { +const PasswordModal = (props) => { + const ErrorLabel = useRef(null); + Modal.setAppElement('body'); - componentWillMount() { - Modal.setAppElement('body'); + function submitPassword(e) { + e.preventDefault(); + const password = props.value + props.validateCallback(password, ErrorLabel.current.showMessage) } - constructor(props) { - super(props); - this.submitPassword = this.submitPassword.bind(this); - this.ErrorLabel = React.createRef(); - } - - submitPassword(event) { - const password = this.props.value - this.props.validateCallback(password) - event.preventDefault(); - } - - render() { - return( - <Modal - isOpen={this.props.hasPass && !this.props.validPass} - style={modalStyles} - contentLabel="enter paste password" - > - <form onSubmit={this.submitPassword}> - <LeftPad> - <ModalHeader><span role="img" aria-label="warning">🚧 </span>err: password protected</ModalHeader> - </LeftPad> - <RightPad> - <PassInput - value={this.props.value} - onChange={this.props.onChange} /> - </RightPad> - <LeftPad> - <input className="lt-button lt-shadow lt-hover" type="submit" value="continue" /> - <Padding /> - <Error ref={this.ErrorLabel} /> - </LeftPad> - </form> - </Modal> - ); - } + return( + <Modal + isOpen={props.hasPass && !props.validPass} + style={modalStyles} + contentLabel="enter paste password" + > + <form onSubmit={submitPassword}> + <LeftPad> + <ModalHeader><span role="img" aria-label="warning">🚧 </span>err: password protected</ModalHeader> + </LeftPad> + <RightPad> + <PassInput + value={props.value} + onChange={props.onChange} /> + </RightPad> + <LeftPad> + <input className="lt-button lt-shadow lt-hover" type="submit" value="continue" /> + <Padding /> + <Error ref={ErrorLabel} /> + </LeftPad> + </form> + </Modal> + ); } export default PasswordModal
\ No newline at end of file diff --git a/frontend/src/components/renderers/Latex.js b/frontend/src/components/renderers/Latex.js index dcb9ea3..fd3d4e2 100644 --- a/frontend/src/components/renderers/Latex.js +++ b/frontend/src/components/renderers/Latex.js @@ -8,37 +8,35 @@ const StyledInlineLatex = styled.div` margin-bottom: 1em; ` -class Latex extends React.Component { - render() { - // split by \begin{...} and \end{...} flags - const els = this.props.content.split(/(\\begin\{.*\}[\s\S]*?\\end\{.*\})/gm).map(line => { - // line doesnt start with \begin{...}, safe to split on \\ - if (!line.match(/^(\\begin\{.*\})/)) { - return line.split("\\\\") - } else { - return line - } - }).flat() - - // if <=1 lines, just render block - if (els.length <= 1) { - return ( - <BlockMath> - {this.props.content} - </BlockMath> - ); +const Latex = (props) => { + // split by \begin{...} and \end{...} flags + const els = props.content.split(/(\\begin\{.*\}[\s\S]*?\\end\{.*\})/gm).map(line => { + // line doesnt start with \begin{...}, safe to split on \\ + if (!line.match(/^(\\begin\{.*\})/)) { + return line.split("\\\\") } else { - // new inline block for every line - const blocks = els.map(line => - <StyledInlineLatex> - <InlineMath> - {line} - </InlineMath> - </StyledInlineLatex> - ) - - return blocks; + return line } + }).flat() + + // if <=1 lines, just render block + if (els.length <= 1) { + return ( + <BlockMath> + {props.content} + </BlockMath> + ); + } else { + // new inline block for every line + const blocks = els.map(line => + <StyledInlineLatex> + <InlineMath> + {line} + </InlineMath> + </StyledInlineLatex> + ) + + return blocks; } } diff --git a/frontend/src/components/renderers/Raw.js b/frontend/src/components/renderers/Raw.js index 7f8e7c1..d4dc830 100644 --- a/frontend/src/components/renderers/Raw.js +++ b/frontend/src/components/renderers/Raw.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import styled from 'styled-components' import { FetchPaste } from '../../helpers/httpHelper' @@ -10,48 +10,37 @@ const RawText = styled.pre` padding: 0 1em; ` -class Raw extends React.Component { - - constructor(props) { - super(props); - this.state = { - content: '', - }; - } - - render() { - return ( - <RawText> - {this.state.content} - </RawText> - ); - } - - componentDidMount() { - FetchPaste(this.props.hash) - .then((response) => { - const data = response.data - this.setState({ content: data.content }) - }).catch((error) => { - const resp = error.response - - // catch 401 unauth (password protected) - if (resp.status === 401) { - this.setState({ content: 'err: password protected' }) - return - } - - // some weird err - if (resp !== undefined) { - const errTxt = `${resp.statusText}: ${resp.data}` - this.setState({ content: errTxt }) - return - } - - // some weird err (e.g. network) - this.setState({ content: error }) - }) - } +const Raw = ({hash}) => { + const [content, setContent] = useState(''); + + useEffect(() => { + FetchPaste(hash) + .then((response) => { + const data = response.data + setContent(data.content) + }).catch((error) => { + const resp = error.response + + // catch 401 unauth (password protected) + if (resp.status === 401) { + setContent('err: password protected') + return + } + + // some weird err + if (resp !== undefined) { + const errTxt = `${resp.statusText}: ${resp.data}` + setContent(errTxt) + return + } + + // some weird err (e.g. network) + setContent(error) + })}, [hash]) + + return ( + <RawText>{content}</RawText> + ); } export default Raw
\ No newline at end of file |