From 48bf294f51ef78edcf8e45b614f2ee2439907682 Mon Sep 17 00:00:00 2001 From: Sonny Date: Thu, 28 Dec 2023 19:08:48 +0100 Subject: [PATCH] refactor: admin dashboard page and improve style --- .../SideNavigation/UserCard/UserCard.tsx | 22 ++- .../UserCard/user-card.module.scss | 28 +-- src/constants/date.ts | 1 + src/pages/admin.tsx | 183 ++++++++++-------- src/styles/globals.scss | 8 +- src/styles/table.scss | 20 +- 6 files changed, 152 insertions(+), 110 deletions(-) create mode 100644 src/constants/date.ts diff --git a/src/components/SideNavigation/UserCard/UserCard.tsx b/src/components/SideNavigation/UserCard/UserCard.tsx index 2527edb..169736a 100644 --- a/src/components/SideNavigation/UserCard/UserCard.tsx +++ b/src/components/SideNavigation/UserCard/UserCard.tsx @@ -4,7 +4,7 @@ import PATHS from 'constants/paths'; import useUser from 'hooks/useUser'; import { useTranslation } from 'next-i18next'; import Link from 'next/link'; -import { MdOutlineAdminPanelSettings } from 'react-icons/md'; +import { MdAdminPanelSettings } from 'react-icons/md'; import styles from './user-card.module.scss'; export default function UserCard() { @@ -26,12 +26,20 @@ export default function UserCard() { /> {user.name} - {user.is_admin && ( - - - - )} - + + {user.is_admin && ( + + + + )} + + ); } diff --git a/src/components/SideNavigation/UserCard/user-card.module.scss b/src/components/SideNavigation/UserCard/user-card.module.scss index 7cc49b0..4ad9954 100644 --- a/src/components/SideNavigation/UserCard/user-card.module.scss +++ b/src/components/SideNavigation/UserCard/user-card.module.scss @@ -12,17 +12,8 @@ justify-content: space-between; align-items: center; - & .user-card { - display: flex; - gap: 0.5em; - align-items: center; - - & img { - border-radius: 50%; - } - } - - & button { + & button, + & a { cursor: pointer; color: $blue; display: flex; @@ -33,3 +24,18 @@ } } } + +.user-card { + display: flex; + gap: 0.5em; + align-items: center; + + & img { + border-radius: 50%; + } +} + +.user-controls { + display: flex; + gap: 0.35em; +} diff --git a/src/constants/date.ts b/src/constants/date.ts new file mode 100644 index 0000000..0f31091 --- /dev/null +++ b/src/constants/date.ts @@ -0,0 +1 @@ +export const DATE_FORMAT = 'DD MMM YYYY (HH:mm)'; diff --git a/src/pages/admin.tsx b/src/pages/admin.tsx index 055d4d0..51df03d 100644 --- a/src/pages/admin.tsx +++ b/src/pages/admin.tsx @@ -3,13 +3,13 @@ import clsx from 'clsx'; import Navbar from 'components/Navbar/Navbar'; import PageTransition from 'components/PageTransition'; import RoundedImage from 'components/RoundedImage/RoundedImage'; +import { DATE_FORMAT } from 'constants/date'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import { getServerSideTranslation } from 'i18n'; import getUsers from 'lib/user/getUsers'; import { useTranslation } from 'next-i18next'; import { ReactNode } from 'react'; -import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; import 'react-tabs/style/react-tabs.css'; import styles from 'styles/admin.module.scss'; import { withAuthentication } from 'utils/session'; @@ -19,103 +19,114 @@ dayjs.extend(relativeTime); type UserExtended = User & { _count: { categories: number; links: number } }; export default function AdminDashboard({ users }: { users: UserExtended[] }) { - const { t } = useTranslation('common'); + const { t } = useTranslation(); + const totalCategories = users.reduce( + (acc, user) => (acc = acc + user._count.categories), + 0, + ); + const totalLinks = users.reduce( + (acc, user) => (acc = acc + user._count.links), + 0, + ); return ( - - - {t('common:users')} - {t('common:stats')} - - - -

- {users.length} {t('admin:users')} -

- - - - - - - - - - - - - - - {users.length !== 0 && - users.map( - ({ - id, - image, - name, - email, - _count, - is_admin, - createdAt, - updatedAt, - }) => ( - - - - - - - - - - - ), - )} - -
#{t('common:name')}{t('common:email')}{t('common:category.categories')}{t('common:link.links')}{t('admin:role')}{t('admin:created_at')}{t('admin:updated_at')}
{id} - {image && ( - - )} - {name ?? '-'} - {email}{_count.categories}{_count.links} - {is_admin ? ( - - {t('admin:admin')} - - ) : ( - - {t('admin:user')} - - )} - {dayjs(createdAt).fromNow()}{dayjs(updatedAt).fromNow()}
-
- {/* // stats */} -
+
+ + + + # + {t('common:name')} + {t('common:email')} + + {t('common:category.categories')} ({totalCategories}) + + + {t('common:link.links')} ({totalLinks}) + + {t('admin:role')} + {t('admin:created_at')} + {t('admin:updated_at')} + + + + {users.length !== 0 && + users.map((user) => ( + + ))} + +
+
); } -type TableItem = { children: ReactNode; fixed?: boolean }; -function TH({ children, fixed = false }: TableItem) { +function TableUserRow({ user }: { user: UserExtended }) { + const { t } = useTranslation(); + const { id, image, name, email, _count, is_admin, createdAt, updatedAt } = + user; return ( - -
{children}
- + + {id} + + {image && ( + + )} + {name ?? '-'} + + {email} + {_count.categories} + {_count.links} + + {is_admin ? ( + {t('admin:admin')} + ) : ( + {t('admin:user')} + )} + + + {dayjs(createdAt).fromNow()} + {dayjs(createdAt).format(DATE_FORMAT)} + + {dayjs(updatedAt).fromNow()} + ); } -function TD({ children, fixed = false }: TableItem) { - return ( - -
{children}
- +type TableItem = { + children: ReactNode; + fixed?: boolean; + column?: boolean; + type: 'td' | 'th'; +}; + +function TableCell({ + children, + fixed = false, + column = false, + type, +}: TableItem) { + const child = ( +
+ {children} +
); + return type === 'td' ? {child} : {child}; } export const getServerSideProps = withAuthentication( diff --git a/src/styles/globals.scss b/src/styles/globals.scss index b033b55..c80aeb2 100644 --- a/src/styles/globals.scss +++ b/src/styles/globals.scss @@ -37,7 +37,7 @@ body { flex-direction: column; } -a { +a:not(.reset) { width: fit-content; color: $blue; border-bottom: 1px solid transparent; @@ -51,6 +51,12 @@ a { } } +a.reset { + color: $blue; + text-decoration: none; + transition: 0; +} + h1, h2, h3, diff --git a/src/styles/table.scss b/src/styles/table.scss index dc71447..cdd7535 100644 --- a/src/styles/table.scss +++ b/src/styles/table.scss @@ -4,16 +4,21 @@ table { height: auto; width: 100%; border-collapse: collapse; - width: 100%; +} + +th { + font-weight: 400; + background-color: $lightest-blue; } td, th { - padding: 1em; + padding: 0.45em; } -th { - background-color: $lightest-blue; +th, +td { + white-space: nowrap; } tr:nth-child(even) { @@ -24,9 +29,14 @@ table .cell { width: 100%; display: flex; align-items: center; - gap: 0.25em; + gap: 0.35em; &:not(.fixed) { justify-content: center; } + + &.column { + gap: 0; + flex-direction: column; + } }