feat(pages): add create url
This commit is contained in:
parent
f1c46da47d
commit
5818440721
1 changed files with 94 additions and 7 deletions
|
@ -1,20 +1,44 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Grid, Card, CardHeader, Box, Typography, IconButton, Link } from '@material-ui/core';
|
import { Grid, Card, CardHeader, Box, Typography, IconButton, Link, Dialog, DialogContent, DialogActions, Button, DialogTitle, TextField } from '@material-ui/core';
|
||||||
import { ContentCopy as CopyIcon, DeleteForever as DeleteIcon } from '@material-ui/icons';
|
import { ContentCopy as CopyIcon, DeleteForever as DeleteIcon, Add as AddIcon } from '@material-ui/icons';
|
||||||
|
|
||||||
import Backdrop from 'components/Backdrop';
|
import Backdrop from 'components/Backdrop';
|
||||||
import useFetch from 'hooks/useFetch';
|
import useFetch from 'hooks/useFetch';
|
||||||
import Alert from 'components/Alert';
|
import Alert from 'components/Alert';
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
|
import { useFormik } from 'formik';
|
||||||
|
import { useStoreSelector } from 'lib/redux/store';
|
||||||
|
import * as yup from 'yup';
|
||||||
|
|
||||||
|
function TextInput({ id, label, formik, ...other }) {
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
id={id}
|
||||||
|
name={id}
|
||||||
|
label={label}
|
||||||
|
value={formik.values[id]}
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
error={formik.touched[id] && Boolean(formik.errors[id])}
|
||||||
|
helperText={formik.touched[id] && formik.errors[id]}
|
||||||
|
variant='standard'
|
||||||
|
fullWidth
|
||||||
|
sx={{ pb: 0.5 }}
|
||||||
|
{...other}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function Urls() {
|
export default function Urls() {
|
||||||
|
const user = useStoreSelector(state => state.user);
|
||||||
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [urls, setURLS] = useState([]);
|
const [urls, setURLS] = useState([]);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
const [createOpen, setCreateOpen] = useState(false);
|
||||||
const [severity, setSeverity] = useState('success');
|
const [severity, setSeverity] = useState('success');
|
||||||
const [message, setMessage] = useState('Deleted');
|
const [message, setMessage] = useState('Deleted');
|
||||||
|
|
||||||
const updatePages = async () => {
|
const updateURLs = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const urls = await useFetch('/api/user/urls');
|
const urls = await useFetch('/api/user/urls');
|
||||||
|
|
||||||
|
@ -34,7 +58,7 @@ export default function Urls() {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePages();
|
updateURLs();
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyURL = u => {
|
const copyURL = u => {
|
||||||
|
@ -44,8 +68,55 @@ export default function Urls() {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues: {
|
||||||
|
url: '',
|
||||||
|
vanity: '',
|
||||||
|
},
|
||||||
|
validationSchema: yup.object({
|
||||||
|
|
||||||
|
}),
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const cleanURL = values.url.trim();
|
||||||
|
const cleanVanity = values.vanity.trim();
|
||||||
|
|
||||||
|
if (cleanURL === '') return formik.setFieldError('username', 'Username can\'t be nothing');
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
url: cleanURL,
|
||||||
|
vanity: cleanVanity === '' ? null : cleanVanity,
|
||||||
|
};
|
||||||
|
|
||||||
|
setCreateOpen(false);
|
||||||
|
setLoading(true);
|
||||||
|
const res = await fetch('/api/shorten', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': user.token,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
const json = await res.json();
|
||||||
|
|
||||||
|
if (json.error) {
|
||||||
|
setSeverity('error');
|
||||||
|
setMessage('Could\'nt create URL: ' + json.error);
|
||||||
|
setOpen(true);
|
||||||
|
} else {
|
||||||
|
setSeverity('success');
|
||||||
|
setMessage('Copied URL: ' + json.url);
|
||||||
|
copy(json.url);
|
||||||
|
setOpen(true);
|
||||||
|
setCreateOpen(false);
|
||||||
|
updateURLs();
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updatePages();
|
updateURLs();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -53,6 +124,22 @@ export default function Urls() {
|
||||||
<Backdrop open={loading}/>
|
<Backdrop open={loading}/>
|
||||||
<Alert open={open} setOpen={setOpen} message={message} severity={severity} />
|
<Alert open={open} setOpen={setOpen} message={message} severity={severity} />
|
||||||
|
|
||||||
|
<Dialog open={createOpen} onClose={() => setCreateOpen(false)}>
|
||||||
|
<DialogTitle>Shorten URL</DialogTitle>
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
<DialogContent>
|
||||||
|
<TextInput id='url' label='URL' formik={formik} />
|
||||||
|
<TextInput id='vanity' label='Vanity' formik={formik} />
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={() => setCreateOpen(false)} color='inherit' autoFocus>Cancel</Button>
|
||||||
|
<Button type='submit' color='inherit'>
|
||||||
|
Create
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</form>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
{!urls.length ? (
|
{!urls.length ? (
|
||||||
<Box
|
<Box
|
||||||
display='flex'
|
display='flex'
|
||||||
|
@ -61,9 +148,9 @@ export default function Urls() {
|
||||||
pt={2}
|
pt={2}
|
||||||
pb={3}
|
pb={3}
|
||||||
>
|
>
|
||||||
<Typography variant='h4'>No URLs</Typography>
|
<Typography variant='h4' sx={{ mb: 1 }}>No URLs <IconButton onClick={() => setCreateOpen(true)}><AddIcon/></IconButton></Typography>
|
||||||
</Box>
|
</Box>
|
||||||
) : <Typography variant='h4'>URLs</Typography>}
|
) : <Typography variant='h4' sx={{ mb: 1 }}>URLs <IconButton onClick={() => setCreateOpen(true)}><AddIcon/></IconButton></Typography>}
|
||||||
|
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
{urls.length ? urls.map(url => (
|
{urls.length ? urls.map(url => (
|
||||||
|
|
Loading…
Reference in a new issue