From d41f6058f73088eb12263f0a7dab645d556be3db Mon Sep 17 00:00:00 2001 From: diced Date: Tue, 16 Aug 2022 14:50:59 -0700 Subject: [PATCH] feat: user avatars --- next.config.js | 3 + .../20220816212407_avatar/migration.sql | 2 + prisma/schema.prisma | 9 +- src/components/Layout.tsx | 6 +- src/components/pages/Manage.tsx | 87 ++++++++++++++++++- src/components/pages/Users.tsx | 2 +- src/lib/middleware/withZipline.ts | 2 + src/lib/redux/reducers/user.ts | 1 + src/pages/api/user/index.ts | 12 ++- src/pages/api/users.ts | 5 +- 10 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 prisma/migrations/20220816212407_avatar/migration.sql diff --git a/next.config.js b/next.config.js index 72c9adc..09d99c9 100644 --- a/next.config.js +++ b/next.config.js @@ -1,3 +1,6 @@ +/** + * @type {import('next').NextConfig} + **/ module.exports = { async redirects() { return [ diff --git a/prisma/migrations/20220816212407_avatar/migration.sql b/prisma/migrations/20220816212407_avatar/migration.sql new file mode 100644 index 0000000..3766c23 --- /dev/null +++ b/prisma/migrations/20220816212407_avatar/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "avatar" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index abd4950..f50b8e7 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -11,6 +11,7 @@ model User { id Int @id @default(autoincrement()) username String password String + avatar String? token String administrator Boolean @default(false) systemTheme String @default("system") @@ -79,11 +80,11 @@ model Stats { } model Invite { - id Int @id @default(autoincrement()) - code String @unique - created_at DateTime @default(now()) + id Int @id @default(autoincrement()) + code String @unique + created_at DateTime @default(now()) expires_at DateTime? - used Boolean @default(false) + used Boolean @default(false) createdBy User @relation(fields: [createdById], references: [id]) createdById Int diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 7e6f755..3372c9e 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -1,4 +1,4 @@ -import { AppShell, Box, Burger, Button, Divider, Header, MediaQuery, Navbar, NavLink, Paper, Popover, ScrollArea, Select, Stack, Text, Title, UnstyledButton, useMantineTheme, Group } from '@mantine/core'; +import { AppShell, Box, Burger, Button, Divider, Header, MediaQuery, Navbar, NavLink, Paper, Popover, ScrollArea, Select, Stack, Text, Title, UnstyledButton, useMantineTheme, Group, Image } from '@mantine/core'; import { useClipboard } from '@mantine/hooks'; import { useModals } from '@mantine/modals'; import { showNotification } from '@mantine/notifications'; @@ -111,8 +111,10 @@ const admin_items = [ export default function Layout({ children, user, title }) { const [token, setToken] = useState(user?.token); const [systemTheme, setSystemTheme] = useState(user.systemTheme ?? 'system'); + const [avatar, setAvatar] = useState(user.avatar ?? null); const [opened, setOpened] = useState(false); // navigation open const [open, setOpen] = useState(false); // manage acc dropdown + const router = useRouter(); const dispatch = useStoreDispatch(); const theme = useMantineTheme(); @@ -258,7 +260,7 @@ export default function Layout({ children, user, title }) { > + + + + + + + + Manage Data Delete, or export your data into a zip file. diff --git a/src/components/pages/Users.tsx b/src/components/pages/Users.tsx index 8a82f1b..48d8d15 100644 --- a/src/components/pages/Users.tsx +++ b/src/components/pages/Users.tsx @@ -157,7 +157,7 @@ export default function Users() { - {user.username[0]} + {user.username[0]} {user.username} ID: {user.id} diff --git a/src/lib/middleware/withZipline.ts b/src/lib/middleware/withZipline.ts index 1c1c252..d7abbf8 100644 --- a/src/lib/middleware/withZipline.ts +++ b/src/lib/middleware/withZipline.ts @@ -26,6 +26,7 @@ export type NextApiReq = NextApiRequest & { id: number; password: string; domains: string[]; + avatar?: string; } | null | void>; getCookie: (name: string) => string | null; cleanCookie: (name: string) => void; @@ -114,6 +115,7 @@ export const withZipline = (handler: (req: NextApiRequest, res: NextApiResponse) token: true, username: true, domains: true, + avatar: true, }, }); diff --git a/src/lib/redux/reducers/user.ts b/src/lib/redux/reducers/user.ts index b9e5e59..db44d8e 100644 --- a/src/lib/redux/reducers/user.ts +++ b/src/lib/redux/reducers/user.ts @@ -8,6 +8,7 @@ export interface User { embedSiteName: string; systemTheme: string; domains: string[]; + avatar?: string; } const initialState: User = null; diff --git a/src/pages/api/user/index.ts b/src/pages/api/user/index.ts index 38783c1..b2b22d8 100644 --- a/src/pages/api/user/index.ts +++ b/src/pages/api/user/index.ts @@ -23,7 +23,7 @@ async function handler(req: NextApiReq, res: NextApiRes) { username: req.body.username, }, }); - if (existing && user.username !== req.body.username) { + if (existing && user.username !== req.body.username) { return res.forbid('Username is already taken'); } await prisma.user.update({ @@ -32,6 +32,11 @@ async function handler(req: NextApiReq, res: NextApiRes) { }); } + if (req.body.avatar) await prisma.user.update({ + where: { id: user.id }, + data: { avatar: req.body.avatar }, + }); + if (req.body.embedTitle) await prisma.user.update({ where: { id: user.id }, data: { embedTitle: req.body.embedTitle }, @@ -57,7 +62,7 @@ async function handler(req: NextApiReq, res: NextApiRes) { where: { id: user.id }, data: { domains: [] }, }); - + const invalidDomains = []; for (const domain of req.body.domains) { @@ -98,6 +103,7 @@ async function handler(req: NextApiReq, res: NextApiRes) { token: true, username: true, domains: true, + avatar: true, }, }); @@ -111,4 +117,4 @@ async function handler(req: NextApiReq, res: NextApiRes) { } } -export default withZipline(handler); +export default withZipline(handler); \ No newline at end of file diff --git a/src/pages/api/users.ts b/src/pages/api/users.ts index de3dc57..22b300a 100644 --- a/src/pages/api/users.ts +++ b/src/pages/api/users.ts @@ -10,7 +10,7 @@ async function handler(req: NextApiReq, res: NextApiRes) { where: { code }, }); if (!invite) return res.bad('invalid invite code'); - + const user = await prisma.user.findFirst({ where: { username }, }); @@ -25,7 +25,7 @@ async function handler(req: NextApiReq, res: NextApiRes) { if (req.method === 'DELETE') { if (req.body.id === user.id) return res.forbid('you can\'t delete your own account'); - + const deleteUser = await prisma.user.findFirst({ where: { id: req.body.id, @@ -70,6 +70,7 @@ async function handler(req: NextApiReq, res: NextApiRes) { embedColor: true, embedTitle: true, systemTheme: true, + avatar: true, }, }); return res.json(users);