diff --git a/public/language/en.json b/public/language/en.json index d7a8f98..cf29da6 100644 --- a/public/language/en.json +++ b/public/language/en.json @@ -147,5 +147,13 @@ "updating": "Updating", "new-title": "New Comic - YouthBook", "top-all": "Top All", + "payment-by-day": "Total Income In 1 Day", + "payment-by-week":"Total Income In 1 Week", + "payment-by-1-month": "Total Income In 1 Month", + "payment-by-3-months": "Total Income In 3 Months", + "payment-by-year": "Total Income In 1 Year", + "total-payment": "Total Income", + "total-users": "Total Users", + "total-comics": "Total Comics", "description_0": "The largest online comic reading website updated continuously every day - Join reading and discussing with more than 10 million members 🎉 at YouthBook ❤️💛💚" } \ No newline at end of file diff --git a/public/language/vi.json b/public/language/vi.json index 7af744f..c38918f 100644 --- a/public/language/vi.json +++ b/public/language/vi.json @@ -148,5 +148,13 @@ "updating": "Đang cập nhật", "new-title": "Truyện Mới Cập Nhật - YouthBook", "top-all": "Top Truyện", + "payment-by-day": "Thu nhập 1 ngày", + "payment-by-week":"Thu nhập 1 tuần", + "payment-by-1-month": "Thu nhập 1 tháng", + "payment-by-3-months": "Thu nhập 3 tháng", + "payment-by-year": "Thu nhập 1 năm", + "total-payment": "Tổng thu nhập", + "total-users": "Tổng tài khoản", + "total-comics": "Tổng truyện", "description_0": "Web đọc truyện tranh online lớn nhất được cập nhật liên tục mỗi ngày - Cùng tham gia đọc truyện và thảo luận với hơn 10 triệu thành viên 🎉 tại YouthBook ❤️💛💚" } \ No newline at end of file diff --git a/src/apis/dashboard.ts b/src/apis/dashboard.ts new file mode 100644 index 0000000..472dc33 --- /dev/null +++ b/src/apis/dashboard.ts @@ -0,0 +1,12 @@ +import apiClients from '@/configs/apiClients'; +import { DASHBOARD_PATH } from '@/constants/path'; +import { Dashboard } from '@/types/dashboard'; + +const dashboardApis = { + getDashboard() { + const url = DASHBOARD_PATH.dashboard; + return apiClients.get(url); + }, +}; + +export default dashboardApis; diff --git a/src/constants/path.ts b/src/constants/path.ts index ab7a590..ef165ae 100644 --- a/src/constants/path.ts +++ b/src/constants/path.ts @@ -27,6 +27,10 @@ export const AUTH_PATH = { fetch_info: '/fetch-info', } as const; +export const DASHBOARD_PATH = { + dashboard: 'dashboard', +} as const; + export const USERS_PATH = { users: '/users', } as const; @@ -67,6 +71,7 @@ export const APP_PATH = { recent: '/recent', // management + management_dashboard: '/management/dashboard', management: '/management', management_comics: '/management/comics', management_users: '/management/users', diff --git a/src/layouts/ManagementLayout.tsx b/src/layouts/ManagementLayout.tsx index 3597e25..68e0ae2 100644 --- a/src/layouts/ManagementLayout.tsx +++ b/src/layouts/ManagementLayout.tsx @@ -5,14 +5,17 @@ import useTranslation from '@/hooks/useTranslation'; import { selectLanguage } from '@/redux/slices/settings'; import { getCookie } from '@/utils/cookies'; import { decodeJWTToken } from '@/utils/token'; +import classNames from 'classnames'; import { Helmet } from 'react-helmet-async'; -import { Link, Outlet } from 'react-router-dom'; +import { Link, Outlet, useLocation } from 'react-router-dom'; const ManagementLayout = () => { const lang = useAppSelector((state) => selectLanguage(state.settings)); const translate = useTranslation(lang); const token = getCookie(COOKIE_KEYS.token); const userInfoPayload = decodeJWTToken(token); + const location = useLocation(); + const path = location.pathname; if (!userInfoPayload) { window.location.href = APP_PATH.home; @@ -30,43 +33,53 @@ const ManagementLayout = () => {
    - {(userInfoPayload?.role === ROLES.admin || userInfoPayload?.role === ROLES.collaborators) && ( -
  • - - - - - - - - - {translate('billing-management')} - -
  • - )} {userInfoPayload?.role === ROLES.admin && ( <> +
  • + + + + + + {translate('dashboard')} + +
  • + className={classNames( + 'group flex items-center rounded-lg fill-gray-700 p-2 text-gray-900 hover:bg-gray-300 dark:text-white dark:hover:bg-gray-700', + { + 'bg-gray-300 dark:bg-gray-700': + path.includes(APP_PATH.management_comics) || path.includes(APP_PATH.management_chapters), + }, + )}> @@ -94,9 +107,19 @@ const ManagementLayout = () => { + className={classNames( + 'group flex items-center rounded-lg fill-gray-700 p-2 text-gray-900 hover:bg-gray-300 dark:text-white dark:hover:bg-gray-700', + { + 'bg-gray-300 dark:bg-gray-700': path.includes(APP_PATH.management_genres), + }, + )}> @@ -124,9 +147,19 @@ const ManagementLayout = () => { + className={classNames( + 'group flex items-center rounded-lg fill-gray-700 p-2 text-gray-900 hover:bg-gray-300 dark:text-white dark:hover:bg-gray-700', + { + 'bg-gray-300 dark:bg-gray-700': path.includes(APP_PATH.management_users), + }, + )}>
  • )} + {(userInfoPayload?.role === ROLES.admin || userInfoPayload?.role === ROLES.collaborators) && ( +
  • + + + + + + + + + {translate('billing-management')} + +
  • + )}
diff --git a/src/pages/Management/Dashboard.tsx b/src/pages/Management/Dashboard.tsx new file mode 100644 index 0000000..c434aff --- /dev/null +++ b/src/pages/Management/Dashboard.tsx @@ -0,0 +1,98 @@ +import dashboardApis from '@/apis/dashboard'; +import { APP_PATH } from '@/constants/path'; +import { COOKIE_KEYS, ROLES } from '@/constants/settings'; +import { useAppSelector } from '@/hooks/reduxHook'; +import useTranslation from '@/hooks/useTranslation'; +import { selectLanguage } from '@/redux/slices/settings'; +import { getCookie } from '@/utils/cookies'; +import { formatCurrency } from '@/utils/format'; +import { decodeJWTToken } from '@/utils/token'; +import { useQuery } from 'react-query'; + +const Dashboard: React.FC = () => { + const token = getCookie(COOKIE_KEYS.token); + const userInfoPayload = decodeJWTToken(token); + const lang = useAppSelector((state) => selectLanguage(state.settings)); + const translate = useTranslation(lang); + + if (!userInfoPayload) { + window.location.href = APP_PATH.home; + } + if (userInfoPayload?.role == ROLES.collaborators) { + window.location.href = APP_PATH.management_billing; + } + + const { data: dashBoardResponse } = useQuery({ + queryKey: ['getDashboard'], + queryFn: () => dashboardApis.getDashboard(), + keepPreviousData: true, + staleTime: 3 * 60 * 1000, + }); + + const dashboardData = dashBoardResponse?.data; + + return ( + dashboardData && ( +
+
+
+
+ {dashboardData.payment.map((element) => ( +
+
{translate(element.name)}
+
{formatCurrency(element.value)}
+
+ ))} +
+
+
+
+
+
+
+

+ {translate(dashboardData?.totalComics.name)} : +

+
+
+ {dashboardData?.totalComics.value} +
+
+
+
+
+
+

+ {translate(dashboardData?.totalUsers.name)} : +

+
+
+ {dashboardData?.totalUsers.value} +
+
+
+
+
+
+

+ {translate(dashboardData?.totalViews.name)} : +

+
+
+ {dashboardData?.totalViews.value} +
+
+
+
+
+ ) + ); +}; + +export default Dashboard; diff --git a/src/pages/Management/PaymentManagement.tsx b/src/pages/Management/PaymentManagement.tsx index 8feef4c..1a9ed14 100644 --- a/src/pages/Management/PaymentManagement.tsx +++ b/src/pages/Management/PaymentManagement.tsx @@ -129,7 +129,7 @@ const PaymentManagement: React.FC = () => { />
-
+
diff --git a/src/routes/management.tsx b/src/routes/management.tsx index 5fdb871..a4f26e1 100644 --- a/src/routes/management.tsx +++ b/src/routes/management.tsx @@ -11,6 +11,7 @@ const ChapterManagement = lazy(() => import('@/pages/Management/ChapterManagemen const GenresManagement = lazy(() => import('@/pages/Management/GenresManagement')); const UserManagement = lazy(() => import('@/pages/Management/UserManagement')); const BillingManagement = lazy(() => import('@/pages/Management/PaymentManagement')); +const Dashboard = lazy(() => import('@/pages/Management/Dashboard')); export default [ { @@ -21,7 +22,15 @@ export default [ { index: true, path: APP_PATH.management, - loader: () => redirect(APP_PATH.management_billing), + loader: () => redirect(APP_PATH.management_dashboard), + }, + { + path: APP_PATH.management_dashboard, + element: ( + }> + + + ), }, { path: APP_PATH.management_comics, diff --git a/src/types/dashboard.ts b/src/types/dashboard.ts new file mode 100644 index 0000000..8b8de34 --- /dev/null +++ b/src/types/dashboard.ts @@ -0,0 +1,6 @@ +export interface Dashboard { + payment: { name: string; value: number }[]; + totalComics: { name: string; value: number }; + totalViews: { name: string; value: number }; + totalUsers: { name: string; value: number }; +}