From 57f9b5521012b602bf62ed178f87c8ae2cb14679 Mon Sep 17 00:00:00 2001 From: Remy Date: Tue, 23 Jun 2026 20:47:59 +0100 Subject: [PATCH] fix router error --- client/.env | 1 + client/package-lock.json | 43 ++++++++++++++ client/package.json | 1 + client/src/components/Breadcrumb.jsx | 44 +++++++------- client/src/components/dashboard/AddForm.jsx | 6 +- client/src/components/dashboard/Overview.jsx | 2 +- client/src/components/dashboard/Stats.jsx | 2 +- client/src/lib/utils.js | 2 +- client/src/main.jsx | 3 +- client/src/pages/dashboard/Admin.jsx | 61 +++++++++++++++++--- client/src/pages/dashboard/Overview.jsx | 20 +++---- client/src/pages/dashboard/Subscriptions.jsx | 5 +- client/vercel.json | 8 +++ server/src/controllers/admin.controller.js | 42 ++++++++++---- 14 files changed, 178 insertions(+), 62 deletions(-) create mode 100644 client/vercel.json diff --git a/client/.env b/client/.env index e69de29..394093c 100644 --- a/client/.env +++ b/client/.env @@ -0,0 +1 @@ +VITE_API_URL=https://subly-backend-iuej.onrender.com \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index 35e9714..4c6fa0c 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -13,6 +13,7 @@ "@tailwindcss/vite": "^4.3.0", "@tanstack/react-query": "^5.100.14", "@tanstack/react-query-devtools": "^5.101.0", + "@vercel/analytics": "^2.0.1", "axios": "^1.16.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -3734,6 +3735,48 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@vercel/analytics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-2.0.1.tgz", + "integrity": "sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g==", + "license": "MIT", + "peerDependencies": { + "@remix-run/react": "^2", + "@sveltejs/kit": "^1 || ^2", + "next": ">= 13", + "nuxt": ">= 3", + "react": "^18 || ^19 || ^19.0.0-rc", + "svelte": ">= 4", + "vue": "^3", + "vue-router": "^4" + }, + "peerDependenciesMeta": { + "@remix-run/react": { + "optional": true + }, + "@sveltejs/kit": { + "optional": true + }, + "next": { + "optional": true + }, + "nuxt": { + "optional": true + }, + "react": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + }, + "vue-router": { + "optional": true + } + } + }, "node_modules/@vitejs/plugin-react": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", diff --git a/client/package.json b/client/package.json index 36828ad..b6014f8 100644 --- a/client/package.json +++ b/client/package.json @@ -15,6 +15,7 @@ "@tailwindcss/vite": "^4.3.0", "@tanstack/react-query": "^5.100.14", "@tanstack/react-query-devtools": "^5.101.0", + "@vercel/analytics": "^2.0.1", "axios": "^1.16.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/client/src/components/Breadcrumb.jsx b/client/src/components/Breadcrumb.jsx index afb3411..6d7a3e9 100644 --- a/client/src/components/Breadcrumb.jsx +++ b/client/src/components/Breadcrumb.jsx @@ -1,29 +1,33 @@ -import { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbSeparator, BreadcrumbLink, BreadcrumbPage } from "./ui/breadcrumb"; +import { Fragment } from "react"; +import { + Breadcrumb, + BreadcrumbList, + BreadcrumbItem, + BreadcrumbSeparator, + BreadcrumbLink, + BreadcrumbPage, +} from "./ui/breadcrumb"; import { Link } from "react-router"; - -export default function Breadcrumbs({crumbs}) { - return ( - - - {crumbs.map((item, index) => ( - +export default function Breadcrumbs({ crumbs }) { + return ( + + + {crumbs.map((item, index) => ( + + {index === crumbs.length - 1 ? ( - - {item.name} - + {item.name} ) : ( {item.name} )} - {index < crumbs.length - 1 && } - ))} - - - ); -}; \ No newline at end of file + {index < crumbs.length - 1 && } + + ))} + + + ); +} diff --git a/client/src/components/dashboard/AddForm.jsx b/client/src/components/dashboard/AddForm.jsx index 7bf4c35..38647c8 100644 --- a/client/src/components/dashboard/AddForm.jsx +++ b/client/src/components/dashboard/AddForm.jsx @@ -49,7 +49,7 @@ const AddForm = ({ rates, isError, mutation }) => { name: "", amount: undefined, currency: "", - duration: "", + billingCycle: "", category: "", }, }); @@ -65,7 +65,9 @@ const AddForm = ({ rates, isError, mutation }) => { // We swap React Router's
action logic for RHF's handleSubmit {mutation.isError && ( -

{mutation.error.message}

+

+ {mutation.error.message} +

)}
diff --git a/client/src/components/dashboard/Overview.jsx b/client/src/components/dashboard/Overview.jsx index c3d8f9c..63fb76b 100644 --- a/client/src/components/dashboard/Overview.jsx +++ b/client/src/components/dashboard/Overview.jsx @@ -232,7 +232,7 @@ export function OverviewTable({ subscriptions, baseCurrency }) { // ensure we always have an array to pass down to Desktop/Mobile - console.log(subscriptions); + return ( diff --git a/client/src/components/dashboard/Stats.jsx b/client/src/components/dashboard/Stats.jsx index fdf3ba2..bf5501f 100644 --- a/client/src/components/dashboard/Stats.jsx +++ b/client/src/components/dashboard/Stats.jsx @@ -23,7 +23,7 @@ const toneStyles = { export function StatCard({ stat , baseCurrency }) { - console.log("StatCard received stat:", stat); + return ( <> diff --git a/client/src/lib/utils.js b/client/src/lib/utils.js index 27e270f..b2e7b10 100644 --- a/client/src/lib/utils.js +++ b/client/src/lib/utils.js @@ -7,7 +7,7 @@ export function cn(...inputs) { } export function getApiBaseUrl() { - return import.meta.env.VITE_API_URL || "http://localhost:3000"; + return import.meta.env.VITE_API_URL; } export function formatMoney(amountInMinorUnit, currency) { diff --git a/client/src/main.jsx b/client/src/main.jsx index 125d757..ac0e9ff 100644 --- a/client/src/main.jsx +++ b/client/src/main.jsx @@ -21,7 +21,7 @@ import NotFound from "./pages/NotFound"; import { adminLoader, authLoader, dashboardLoader } from "./lib/loader.js"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; - +import { Analytics } from "@vercel/analytics/react"; const queryClient = new QueryClient({ defaultOptions: { queries: { @@ -90,6 +90,7 @@ createRoot(document.getElementById("root")).render( + , ); diff --git a/client/src/pages/dashboard/Admin.jsx b/client/src/pages/dashboard/Admin.jsx index 2e0c64d..01bd320 100644 --- a/client/src/pages/dashboard/Admin.jsx +++ b/client/src/pages/dashboard/Admin.jsx @@ -1,5 +1,12 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { ShieldCheck, Users, CreditCard, History, RefreshCw } from "lucide-react"; +import { + ShieldCheck, + Users, + CreditCard, + History, + RefreshCw, + Shield, +} from "lucide-react"; import { toast } from "sonner"; import Breadcrumbs from "@/components/Breadcrumb"; @@ -22,6 +29,7 @@ import { TableRow, } from "@/components/ui/table"; import { fetchWithAuth, formatDate } from "@/lib/utils"; +import { toneStyles } from "@/lib/var"; const metricCards = [ { @@ -29,25 +37,49 @@ const metricCards = [ label: "Total users", icon: Users, getValue: (stats) => stats?.users?.total ?? 0, + + color: "blue", + }, + { + key: "admin", + label: "Total user with admin role", + icon: Shield, + getValue: (stats) => stats?.totalUserByRoles?.ADMIN ?? 0, + + color: "success", + }, + { + key: "user", + label: "Total user with user role", + icon: Users, + getValue: (stats) => stats?.totalUserByRoles?.USER ?? 0, + + color: "danger", }, { key: "subscriptions", - label: "Subscriptions", + label: "Total Subscriptions", icon: CreditCard, getValue: (stats) => stats?.subscriptions?.total ?? 0, + + color: "purple", }, { key: "history", label: "History records", icon: History, getValue: (stats) => stats?.history?.total ?? 0, + color: "purple", }, { key: "currency", label: "Rates updated", icon: RefreshCw, getValue: (stats) => - stats?.currency?.lastUpdated ? formatDate(stats.currency.lastUpdated) : "N/A", + stats?.currency?.lastUpdated + ? formatDate(stats.currency.lastUpdated) + : "N/A", + color: "danger", }, ]; @@ -56,15 +88,23 @@ function AdminMetricCard({ item, stats }) { return ( - +
-

{item.label}

-

+

+ {item.key} +

+

{item.getValue(stats)}

+

+ + {item.label} +

@@ -184,12 +224,14 @@ export default function Admin() { Name Username Email + Roles Role actions {users.map((user) => { - const pendingUser = roleMutation.variables?.userId === user.id; + const pendingUser = + roleMutation.variables?.userId === user.id; return ( @@ -198,6 +240,11 @@ export default function Admin() { {user.username} {user.email} + + {user.role} +