feat(pages): add urls page

This commit is contained in:
diced 2021-09-25 17:30:23 -07:00
parent 212c69d303
commit f1c46da47d
No known key found for this signature in database
GPG key ID: 85AB64C74535D76E
5 changed files with 162 additions and 1 deletions

View file

@ -35,6 +35,7 @@ import {
Logout as LogoutIcon,
PeopleAlt as UsersIcon,
Brush as BrushIcon,
Link as URLIcon,
} from '@material-ui/icons';
import copy from 'copy-to-clipboard';
import Backdrop from './Backdrop';
@ -55,6 +56,11 @@ const items = [
text: 'Files',
link: '/dashboard/files',
},
{
icon: <URLIcon />,
text: 'URLs',
link: '/dashboard/urls',
},
{
icon: <UploadIcon />,
text: 'Upload',

View file

@ -0,0 +1,92 @@
import React, { useEffect, useState } from 'react';
import { Grid, Card, CardHeader, Box, Typography, IconButton, Link } from '@material-ui/core';
import { ContentCopy as CopyIcon, DeleteForever as DeleteIcon } from '@material-ui/icons';
import Backdrop from 'components/Backdrop';
import useFetch from 'hooks/useFetch';
import Alert from 'components/Alert';
import copy from 'copy-to-clipboard';
export default function Urls() {
const [loading, setLoading] = useState(true);
const [urls, setURLS] = useState([]);
const [open, setOpen] = useState(false);
const [severity, setSeverity] = useState('success');
const [message, setMessage] = useState('Deleted');
const updatePages = async () => {
setLoading(true);
const urls = await useFetch('/api/user/urls');
setURLS(urls);
setLoading(false);
};
const deleteURL = async u => {
const url = await useFetch('/api/user/urls', 'DELETE', { id: u.id });
if (url.error) {
setSeverity('error');
setMessage('Error: ' + url.error);
setOpen(true);
} else {
setSeverity('success');
setMessage(`Deleted ${u.vanity ?? u.id}`);
setOpen(true);
}
updatePages();
};
const copyURL = u => {
copy(`${window.location.protocol}//${window.location.host}${u.url}`);
setSeverity('success');
setMessage(`Copied URL: ${window.location.protocol}//${window.location.host}${u.url}`);
setOpen(true);
};
useEffect(() => {
updatePages();
}, []);
return (
<>
<Backdrop open={loading}/>
<Alert open={open} setOpen={setOpen} message={message} severity={severity} />
{!urls.length ? (
<Box
display='flex'
justifyContent='center'
alignItems='center'
pt={2}
pb={3}
>
<Typography variant='h4'>No URLs</Typography>
</Box>
) : <Typography variant='h4'>URLs</Typography>}
<Grid container spacing={2}>
{urls.length ? urls.map(url => (
<Grid item xs={12} sm={3} key={url.id}>
<Card sx={{ maxWidth: '100%' }}>
<CardHeader
action={
<>
<IconButton aria-label='copy' onClick={() => copyURL(url)}>
<CopyIcon />
</IconButton>
<IconButton aria-label='delete' onClick={() => deleteURL(url)}>
<DeleteIcon />
</IconButton>
</>
}
title={url.vanity ?? url.id}
subheader={<Link href={url.destination}>{url.destination}</Link>}
/>
</Card>
</Grid>
)) : null}
</Grid>
</>
);
}

View file

@ -54,7 +54,7 @@ async function handler(req: NextApiReq, res: NextApiRes) {
// @ts-ignore
images.map(image => image.url = `/r/${image.file}`);
images.map(image => image.url = `${config.uploader.route}/${image.file}`);
if (req.query.filter && req.query.filter === 'media') images = images.filter(x => /^(video|audio|image)/.test(x.mimetype));
return res.json(req.query.paged ? chunk(images, 16) : images);

View file

@ -0,0 +1,41 @@
import { NextApiReq, NextApiRes, withZipline } from 'middleware/withZipline';
import prisma from 'lib/prisma';
import config from 'lib/config';
import Logger from 'lib/logger';
async function handler(req: NextApiReq, res: NextApiRes) {
const user = await req.user();
if (!user) return res.forbid('not logged in');
if (req.method === 'DELETE') {
if (!req.body.id) return res.error('no url id');
const url = await prisma.url.delete({
where: {
id: req.body.id,
},
});
Logger.get('url').info(`User ${user.username} (${user.id}) deleted a url ${url.destination} (${url.id})`);
return res.json(url);
} else {
let urls = await prisma.url.findMany({
where: {
userId: user.id,
},
select: {
created_at: true,
id: true,
destination: true,
vanity: true,
},
});
// @ts-ignore
urls.map(url => url.url = `${config.urls.route}/${url.vanity ?? url.id}`);
return res.json(urls);
}
}
export default withZipline(handler);

View file

@ -0,0 +1,22 @@
import React from 'react';
import useLogin from 'hooks/useLogin';
import Layout from 'components/Layout';
import Urls from 'components/pages/Urls';
export default function UrlsPage() {
const { user, loading } = useLogin();
if (loading) return null;
return (
<Layout
user={user}
loading={loading}
noPaper={false}
>
<Urls />
</Layout>
);
}
UrlsPage.title = 'Zipline - URLs';