From 25badbcca5b2ba35e1f99432434db700940e2a53 Mon Sep 17 00:00:00 2001 From: Yared Yemane Date: Fri, 13 Feb 2026 05:28:38 -0800 Subject: [PATCH] activity log + issue reporting integrations + responsiveness fix + more advanced styling + minor fixes --- .env | 1 + package-lock.json | 11 + package.json | 1 + src/App.tsx | 19 +- src/api/activity-logs.api.ts | 14 + src/api/auth.api.ts | 15 + src/api/issues.api.ts | 25 + src/app/AppRoutes.tsx | 2 + src/components/sidebar/Sidebar.tsx | 147 +-- src/components/topbar/Topbar.tsx | 173 ++-- src/components/ui/dialog.tsx | 2 +- src/layouts/AppLayout.tsx | 21 +- src/pages/ProfilePage.tsx | 266 +++-- src/pages/auth/ForgotPasswordPage.tsx | 148 ++- src/pages/auth/LoginPage.tsx | 340 ++++++- .../content-management/AddNewPracticePage.tsx | 242 ++--- .../content-management/AddPracticePage.tsx | 206 ++-- .../content-management/AddQuestionPage.tsx | 343 ++++--- src/pages/content-management/AddVideoPage.tsx | 84 +- .../ContentManagementLayout.tsx | 34 +- .../ContentOverviewPage.tsx | 220 +++-- .../content-management/CourseCategoryPage.tsx | 134 ++- src/pages/content-management/CoursesPage.tsx | 191 ++-- .../PracticeDetailsPage.tsx | 109 ++- .../PracticeMembersPage.tsx | 42 +- .../PracticeQuestionsPage.tsx | 124 +-- .../content-management/QuestionsPage.tsx | 132 ++- src/pages/content-management/SpeakingPage.tsx | 49 +- .../SubCourseContentPage.tsx | 278 +++--- .../content-management/SubCoursesPage.tsx | 202 ++-- src/pages/issues/IssuesPage.tsx | 917 ++++++++++++++++++ src/pages/team/TeamManagementPage.tsx | 12 +- src/pages/team/TeamMemberDetailPage.tsx | 2 +- src/pages/user-log/UserLogPage.tsx | 685 ++++++++++++- .../user-management/RegisterUserPage.tsx | 46 +- src/pages/user-management/UserDetailPage.tsx | 6 +- src/pages/user-management/UserGroupsPage.tsx | 93 +- .../UserManagementDashboard.tsx | 160 ++- .../user-management/UserManagementLayout.tsx | 1 - src/pages/user-management/UsersListPage.tsx | 423 ++++---- src/types/activity-log.types.ts | 47 + src/types/issue.types.ts | 52 + 42 files changed, 4416 insertions(+), 1603 deletions(-) create mode 100644 src/api/activity-logs.api.ts create mode 100644 src/api/issues.api.ts create mode 100644 src/pages/issues/IssuesPage.tsx create mode 100644 src/types/activity-log.types.ts create mode 100644 src/types/issue.types.ts diff --git a/.env b/.env index 0c0e1f5..ff1a1d8 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ VITE_API_BASE_URL=http://localhost:8080/api/v1 +VITE_GOOGLE_CLIENT_ID=google_client_id diff --git a/package-lock.json b/package-lock.json index bfdd210..6fc436d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "react-dom": "^19.2.0", "react-router-dom": "^7.10.1", "recharts": "^3.6.0", + "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "zustand": "^5.0.9" }, @@ -5658,6 +5659,16 @@ "node": ">=8" } }, + "node_modules/sonner": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", + "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", diff --git a/package.json b/package.json index 60f16ce..872fc56 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "react-dom": "^19.2.0", "react-router-dom": "^7.10.1", "recharts": "^3.6.0", + "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "zustand": "^5.0.9" }, diff --git a/src/App.tsx b/src/App.tsx index 968b8ad..ba4b6ed 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,22 @@ +import { Toaster } from 'sonner' import { AppRoutes } from './app/AppRoutes' export default function App() { - return + return ( + <> + + + + ) } diff --git a/src/api/activity-logs.api.ts b/src/api/activity-logs.api.ts new file mode 100644 index 0000000..ab1632c --- /dev/null +++ b/src/api/activity-logs.api.ts @@ -0,0 +1,14 @@ +import http from "./http"; +import type { + GetActivityLogsResponse, + GetActivityLogResponse, + ActivityLogFilters, +} from "../types/activity-log.types"; + +export const getActivityLogs = (filters?: ActivityLogFilters) => + http.get("/activity-logs", { + params: filters, + }); + +export const getActivityLogById = (id: number) => + http.get(`/activity-logs/${id}`); diff --git a/src/api/auth.api.ts b/src/api/auth.api.ts index ee09b26..1b26acd 100644 --- a/src/api/auth.api.ts +++ b/src/api/auth.api.ts @@ -20,3 +20,18 @@ export const login = async (payload: LoginRequest): Promise => { memberId: data.member_id, } } + +export const loginWithGoogle = async (credential: string): Promise => { + const res = await http.post("/team/google-login", { + token: credential, + }) + + const data: LoginResponseData = res.data.data + + return { + accessToken: data.access_token, + refreshToken: data.refresh_token, + role: data.team_role, + memberId: data.member_id, + } +} diff --git a/src/api/issues.api.ts b/src/api/issues.api.ts new file mode 100644 index 0000000..4032162 --- /dev/null +++ b/src/api/issues.api.ts @@ -0,0 +1,25 @@ +import http from "./http"; +import type { + GetIssuesResponse, + GetIssueResponse, + UpdateIssueStatusResponse, + DeleteIssueResponse, + IssueFilters, +} from "../types/issue.types"; + +export const getIssues = (filters?: IssueFilters) => + http.get("/issues", { + params: filters, + }); + +export const getIssuesByUserId = (userId: number) => + http.get(`/issues/user/${userId}`); + +export const getIssueById = (id: number) => + http.get(`/issues/${id}`); + +export const updateIssueStatus = (id: number, status: string) => + http.patch(`/issues/${id}/status`, { status }); + +export const deleteIssue = (id: number) => + http.delete(`/issues/${id}`); diff --git a/src/app/AppRoutes.tsx b/src/app/AppRoutes.tsx index 9d8f677..61a70a9 100644 --- a/src/app/AppRoutes.tsx +++ b/src/app/AppRoutes.tsx @@ -29,6 +29,7 @@ import { PracticeMembersPage } from "../pages/content-management/PracticeMembers import { QuestionsPage } from "../pages/content-management/QuestionsPage" import { AddQuestionPage } from "../pages/content-management/AddQuestionPage" import { UserLogPage } from "../pages/user-log/UserLogPage" +import { IssuesPage } from "../pages/issues/IssuesPage" import { ProfilePage } from "../pages/ProfilePage" import { TeamManagementPage } from "../pages/team/TeamManagementPage" import { TeamMemberDetailPage } from "../pages/team/TeamMemberDetailPage" @@ -79,6 +80,7 @@ export function AppRoutes() { } /> } /> + } /> } /> } /> diff --git a/src/components/sidebar/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx index 4c748fe..2001851 100644 --- a/src/components/sidebar/Sidebar.tsx +++ b/src/components/sidebar/Sidebar.tsx @@ -2,6 +2,7 @@ import { BarChart3, Bell, BookOpen, + CircleAlert, ClipboardList, LayoutDashboard, LogOut, @@ -9,6 +10,7 @@ import { UserCircle2, Users, Users2, + X, } from "lucide-react" import type { ComponentType } from "react" import { NavLink } from "react-router-dom" @@ -28,66 +30,101 @@ const navItems: NavItem[] = [ { label: "Content Management", to: "/content", icon: BookOpen }, { label: "Notifications", to: "/notifications", icon: Bell }, { label: "User Log", to: "/user-log", icon: ClipboardList }, + { label: "Issue Reports", to: "/issues", icon: CircleAlert }, { label: "Analytics", to: "/analytics", icon: BarChart3 }, { label: "Team Management", to: "/team", icon: Users2 }, { label: "Profile", to: "/profile", icon: UserCircle2 }, ] -export function Sidebar() { - return ( - - ) +type SidebarProps = { + isOpen: boolean + onClose: () => void } +export function Sidebar({ isOpen, onClose }: SidebarProps) { + return ( + <> + {/* Mobile overlay */} +