feat(api): image favoriting (#67)

This commit is contained in:
diced 2021-08-27 13:48:22 -07:00
parent 53c53c009e
commit e8b82ffe62
No known key found for this signature in database
GPG key ID: 85AB64C74535D76E
8 changed files with 66 additions and 12 deletions

View file

@ -10,7 +10,6 @@
"start": "node server",
"lint": "next lint",
"ts-node": "ts-node --compiler-options \"{\\\"module\\\":\\\"commonjs\\\"}\" --transpile-only",
"create-all-migrations": "node scripts/create-migrations",
"semantic-release": "semantic-release"
},
"dependencies": {

View file

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Image" ADD COLUMN "favorite" BOOLEAN NOT NULL DEFAULT false;

View file

@ -42,6 +42,7 @@ model Image {
mimetype String @default("image/png")
created_at DateTime @default(now())
views Int @default(0)
favorite Boolean @default(false)
invisible InvisibleImage?
user User @relation(fields: [userId], references: [id])
userId Int

View file

@ -16,7 +16,7 @@ export default function Image({ image, updateImages }) {
const handleDelete = async () => {
const res = await useFetch('/api/user/images', 'DELETE', { id: image.id });
if (!res.error) updateImages();
if (!res.error) updateImages(true);
setAnchorEl(null);
};
@ -26,6 +26,11 @@ export default function Image({ image, updateImages }) {
setAnchorEl(null);
};
const handleFavorite = async () => {
const data = await useFetch('/api/user/images', 'PATCH', { id: image.id, favorite: !image.favorite });
if (!data.error) updateImages(true);
};
return (
<>
<Card sx={{ maxWidth: '100%' }}>
@ -54,6 +59,7 @@ export default function Image({ image, updateImages }) {
<ButtonGroup variant='contained'>
<Button onClick={handleDelete} color='primary'>Delete</Button>
<Button onClick={handleCopy} color='primary'>Copy URL</Button>
<Button onClick={handleFavorite} color='primary'>{image.favorite ? 'Unfavorite' : 'Favorite'}</Button>
</ButtonGroup>
</Popover>
</>

View file

@ -97,7 +97,7 @@ export default function Dashboard() {
const imgs = await useFetch('/api/user/images');
const stts = await useFetch('/api/stats');
setImages(imgs);
setStats(stts);console.log(stts);
setStats(stts);
setApiLoading(false);
};

View file

@ -1,30 +1,37 @@
import React, { useEffect, useState } from 'react';
import { Grid, Pagination, Box, Typography } from '@material-ui/core';
import { Grid, Pagination, Box, Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core';
import Backdrop from 'components/Backdrop';
import ZiplineImage from 'components/Image';
import useFetch from 'hooks/useFetch';
import { ExpandMore } from '@material-ui/icons';
export default function Upload() {
const [pages, setPages] = useState([]);
const [page, setPage] = useState(1);
const [favoritePages, setFavoritePages] = useState([]);
const [favoritePage, setFavoritePage] = useState(1);
const [loading, setLoading] = useState(true);
const updatePages = async () => {
const updatePages = async favorite => {
setLoading(true);
const pages = await useFetch('/api/user/images?paged=true&filter=image');
if (favorite) {
const fPages = await useFetch('/api/user/images?paged=true&favorite=true');
setFavoritePages(fPages);
}
setPages(pages);
setLoading(false);
};
useEffect(() => {
updatePages();
updatePages(true);
}, []);
return (
<>
<Backdrop open={loading}/>
{!pages.length && (
{!pages.length ? (
<Box
display='flex'
justifyContent='center'
@ -34,7 +41,33 @@ export default function Upload() {
>
<Typography variant='h4'>No Images</Typography>
</Box>
)}
) : <Typography variant='h4'>Images</Typography>}
{favoritePages.length ? (
<Accordion sx={{ my: 2, border: 1, borderColor: t => t.palette.divider }} elevation={0}>
<AccordionSummary expandIcon={<ExpandMore />}>
<Typography variant='h4'>Favorite Images</Typography>
</AccordionSummary>
<AccordionDetails>
<Grid container spacing={2}>
{favoritePages.length ? favoritePages[(favoritePage - 1) ?? 0].map(image => (
<Grid item xs={12} sm={3} key={image.id}>
<ZiplineImage image={image} updateImages={() => updatePages(true)} />
</Grid>
)) : null}
</Grid>
{favoritePages.length ? (
<Box
display='flex'
justifyContent='center'
alignItems='center'
pt={2}
>
<Pagination count={favoritePages.length} page={favoritePage} onChange={(_, v) => setFavoritePage(v)}/>
</Box>
) : null}
</AccordionDetails>
</Accordion>
) : null}
<Grid container spacing={2}>
{pages.length ? pages[(page - 1) ?? 0].map(image => (
<Grid item xs={12} sm={3} key={image.id}>
@ -42,7 +75,6 @@ export default function Upload() {
</Grid>
)) : null}
</Grid>
{pages.length ? (
<Box
display='flex'

View file

@ -142,7 +142,6 @@ export default function Manage() {
setLoading(true);
const newUser = await useFetch('/api/user', 'PATCH', { customTheme: values });
console.log(newUser);
if (newUser.error) {
setLoading(false);

View file

@ -23,17 +23,32 @@ async function handler(req: NextApiReq, res: NextApiRes) {
Logger.get('image').info(`User ${user.username} (${user.id}) deleted an image ${image.file} (${image.id})`);
return res.json(image);
} else if (req.method === 'PATCH') {
if (!req.body.id) return res.error('no file id');
let image;
if (req.body.favorite !== null) image = await prisma.image.update({
where: { id: req.body.id },
data: {
favorite: req.body.favorite
}
});
return res.json(image);
} else {
let images = await prisma.image.findMany({
where: {
userId: user.id
userId: user.id,
favorite: !!req.query.favorite
},
select: {
created_at: true,
file: true,
mimetype: true,
id: true
id: true,
favorite: true
}
});