about summary refs log tree commit diff
path: root/client/src/Components
diff options
context:
space:
mode:
authorMelonai <einebeere@gmail.com>2020-05-20 19:52:18 +0200
committerMelonai <einebeere@gmail.com>2020-05-20 19:52:18 +0200
commite58b453f24c8b4081361112862d29c34eb22009d (patch)
tree3437fb38ecb8b22ad5475d88f7e9ca901b320917 /client/src/Components
parenta00a8a867cae381982c7b8b77f07836ab4a504ed (diff)
downloadshorest-e58b453f24c8b4081361112862d29c34eb22009d.tar.zst
shorest-e58b453f24c8b4081361112862d29c34eb22009d.zip
port to react and better error handling in backend
Diffstat (limited to 'client/src/Components')
-rw-r--r--client/src/Components/Button.js11
-rw-r--r--client/src/Components/CopyButton.js24
-rw-r--r--client/src/Components/Form.js33
-rw-r--r--client/src/Components/Loader.js13
-rw-r--r--client/src/Components/Response.js50
-rw-r--r--client/src/Components/ResponseContainer.js12
-rw-r--r--client/src/Components/Title.js12
7 files changed, 155 insertions, 0 deletions
diff --git a/client/src/Components/Button.js b/client/src/Components/Button.js
new file mode 100644
index 0000000..46c0c27
--- /dev/null
+++ b/client/src/Components/Button.js
@@ -0,0 +1,11 @@
+import React from 'react';
+
+function Button(props) {
+    return (
+        <div className="button-container">
+            <input type="submit" value={props.valid ? "→" : ""} className="button" id="btn" onClick={props.submit}/>
+        </div>
+    )
+}
+
+export default Button;
\ No newline at end of file
diff --git a/client/src/Components/CopyButton.js b/client/src/Components/CopyButton.js
new file mode 100644
index 0000000..0ae8e83
--- /dev/null
+++ b/client/src/Components/CopyButton.js
@@ -0,0 +1,24 @@
+import React, {useState} from 'react';
+import copy from 'clipboard-copy';
+
+function CopyButton(props) {
+    const [copied, setCopied] = useState(false);
+
+    const handleClick = async () => {
+        await copy("https://sho.rest/" + props.hash);
+        setCopied(true);
+    };
+
+    let content;
+    if (copied) {
+        content = <span>Link Copied!</span>;
+    } else {
+        content = <strong>Copy Link</strong>;
+    }
+
+    return (
+        <span className="copy-text" onClick={handleClick}>{content}</span>
+    )
+}
+
+export default CopyButton;
\ No newline at end of file
diff --git a/client/src/Components/Form.js b/client/src/Components/Form.js
new file mode 100644
index 0000000..4d10f98
--- /dev/null
+++ b/client/src/Components/Form.js
@@ -0,0 +1,33 @@
+import React, {useState} from 'react';
+import Button from './Button';
+import isURL from "validator/lib/isURL";
+
+function Form(props) {
+    const [state, setState] = useState({value: '', valid: false});
+
+    const handleSubmit = () => {
+        if (state.valid) {
+            props.addRequest(state.value);
+        }
+    };
+
+    const handleChange = (e) => {
+        const userInput = e.target.value;
+        const valid = isURL('https://' + userInput);
+        setState({value: userInput, valid: valid});
+    };
+
+    return (
+        <form id="form" onSubmit={(e) => e.preventDefault()}>
+            <div className={"input-group" + (state.valid ? "" : " disabled")}>
+                <div className={"input-container" + (state.valid ? "" : " border-r-none")}>
+                    <span className="input-field-text">https://</span>
+                    <input className="input-field" required onChange={handleChange}/>
+                </div>
+                <Button valid={state.valid} submit={handleSubmit}/>
+            </div>
+        </form>
+    )
+}
+
+export default Form;
\ No newline at end of file
diff --git a/client/src/Components/Loader.js b/client/src/Components/Loader.js
new file mode 100644
index 0000000..3f4c47f
--- /dev/null
+++ b/client/src/Components/Loader.js
@@ -0,0 +1,13 @@
+import React from 'react';
+
+function Loader() {
+    return (
+        <div className="ball-pulse">
+            <div/>
+            <div/>
+            <div/>
+        </div>
+    )
+}
+
+export default Loader;
\ No newline at end of file
diff --git a/client/src/Components/Response.js b/client/src/Components/Response.js
new file mode 100644
index 0000000..83c6ff1
--- /dev/null
+++ b/client/src/Components/Response.js
@@ -0,0 +1,50 @@
+import React, {useEffect, useState} from 'react';
+import axios from "axios";
+import Loader from "./Loader";
+import CopyButton from "./CopyButton";
+
+function Response(props){
+    const CancelToken = axios.CancelToken;
+    const [requestState, setRequestState] = useState({loading: true, cancel: CancelToken.source()});
+
+    useEffect(() => {
+        axios.post('/', {url: "https://" + props.url}, {cancelToken: requestState.cancel.token})
+            .then((r) => {
+                setRequestState({loading: false, hash: r.data.hash, cancel: requestState.cancel});
+            }).catch((e) => {
+                if (!axios.isCancel(e)) {
+                    setRequestState({loading: false, error: true, cancel: requestState.cancel});
+                }
+            });
+
+        return () => {
+            requestState.cancel.cancel();
+        };
+    }, [props.url, requestState.cancel])
+
+    let text;
+    if (!requestState.loading) {
+        if (!requestState.error) {
+            if (props.url.length < 20) {
+                text =
+                    <span>The short link for <strong>{props.url}</strong> is<br/><strong>sho.rest/{requestState.hash}</strong></span>;
+            } else {
+                text =
+                    <span>The short link for your URL is<br/><strong>sho.rest/{requestState.hash}</strong></span>;
+            }
+        } else {
+            text = <span>There was an error.</span>
+        }
+    } else {
+        text = <Loader/>
+    }
+
+    return (
+        <div className={"response-container" + (requestState.error ? " disabled" : "")}>
+            <div className={"title response-text" + (requestState.error ? " disabled" : "")}>{text}</div>
+            {requestState.error || requestState.loading ? "" : <CopyButton hash={requestState.hash}/>}
+        </div>
+    )
+}
+
+export default Response;
\ No newline at end of file
diff --git a/client/src/Components/ResponseContainer.js b/client/src/Components/ResponseContainer.js
new file mode 100644
index 0000000..8fad4bd
--- /dev/null
+++ b/client/src/Components/ResponseContainer.js
@@ -0,0 +1,12 @@
+import React from 'react';
+import Response from "./Response";
+
+function ResponseContainer(props){
+    const responseContent = props.requests.map((r) => <Response key={r.key} url={r.url}/>);
+
+    return (
+        responseContent
+    )
+}
+
+export default ResponseContainer;
\ No newline at end of file
diff --git a/client/src/Components/Title.js b/client/src/Components/Title.js
new file mode 100644
index 0000000..8ea96a9
--- /dev/null
+++ b/client/src/Components/Title.js
@@ -0,0 +1,12 @@
+import React from 'react';
+
+function Title() {
+    return (
+        <div className="title">
+            <span><b>sho.rest</b><br/></span>
+            <span>Made with ❤ by <b>Mel</b></span>
+        </div>
+    )
+}
+
+export default Title;
\ No newline at end of file