From cd2ed669607d632d236bdc8744a55af0fd987368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Ckirukib=E2=80=9D?= <“kirubeljkl679@gmail.com”> Date: Fri, 27 Feb 2026 19:31:41 +0300 Subject: [PATCH] ui+plus --- src/api/courses.api.ts | 4 + src/api/users.api.ts | 14 + src/pages/ProfilePage.tsx | 66 +- .../content-management/AddQuestionPage.tsx | 23 +- .../content-management/CourseCategoryPage.tsx | 106 ++- src/pages/issues/IssuesPage.tsx | 122 +++- src/pages/notifications/NotificationsPage.tsx | 675 ++++++++++++++++-- .../user-management/RegisterUserPage.tsx | 113 ++- src/types/course.types.ts | 4 + 9 files changed, 979 insertions(+), 148 deletions(-) diff --git a/src/api/courses.api.ts b/src/api/courses.api.ts index 7bf5ce7..c831e5a 100644 --- a/src/api/courses.api.ts +++ b/src/api/courses.api.ts @@ -37,11 +37,15 @@ import type { CreateQuestionRequest, CreateQuestionResponse, CreateVimeoVideoRequest, + CreateCourseCategoryRequest, } from "../types/course.types" export const getCourseCategories = () => http.get("/course-management/categories") +export const createCourseCategory = (data: CreateCourseCategoryRequest) => + http.post("/course-management/categories", data) + export const getCoursesByCategory = (categoryId: number) => http.get(`/course-management/categories/${categoryId}/courses`) diff --git a/src/api/users.api.ts b/src/api/users.api.ts index 89e3ca4..30936b6 100644 --- a/src/api/users.api.ts +++ b/src/api/users.api.ts @@ -14,3 +14,17 @@ export const getUserById = (id: number) => export const getMyProfile = () => http.get("/team/me"); + +// Best-guess API for creating a new user (admin-side). +// Adjust payload shape or endpoint if backend differs. +export interface CreateUserRequest { + first_name: string; + last_name: string; + email: string; + phone_number: string; + role: string; + notes?: string; +} + +export const createUser = (payload: CreateUserRequest) => + http.post("/users", payload); diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx index b86c816..933fa24 100644 --- a/src/pages/ProfilePage.tsx +++ b/src/pages/ProfilePage.tsx @@ -226,7 +226,7 @@ export function ProfilePage() {
-
+
{/* Left column: About & details */}
{/* Identity */} @@ -348,70 +348,6 @@ export function ProfilePage() {
- {/* Middle column: Job information */} -
-
-

- Job information -

-
- - - - - - - - - - - - - - - - - - - - - -
TitleTeamDivisionManagerHire dateLocation
{profile.occupation || profile.role}{profile.role}{profile.preferred_language || "—"}{formatDate(profile.created_at)} - {[profile.region, profile.country].filter(Boolean).join(", ") || "—"} -
-
-
- - {/* Learning & goals */} -
- - - - Learning goal - - - -

- {profile.learning_goal || "No learning goal specified."} -

-
-
- - - - - Language goal - - - -

- {profile.language_goal || "No language goal specified."} -

-
-
-
-
- {/* Right column: Activity & account summary */}
{/* Activity */} diff --git a/src/pages/content-management/AddQuestionPage.tsx b/src/pages/content-management/AddQuestionPage.tsx index 13ec07c..85f7251 100644 --- a/src/pages/content-management/AddQuestionPage.tsx +++ b/src/pages/content-management/AddQuestionPage.tsx @@ -1,6 +1,7 @@ import { useState } from "react" import { useNavigate, useParams } from "react-router-dom" import { ArrowLeft, Plus, X } from "lucide-react" +import { toast } from "sonner" import { Button } from "../../components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card" import { Input } from "../../components/ui/input" @@ -105,32 +106,44 @@ export function AddQuestionPage() { // Validation if (!formData.question.trim()) { - alert("Please enter a question") + toast.error("Missing question", { + description: "Please enter a question before saving.", + }) return } if (formData.type === "multiple-choice" || formData.type === "true-false") { if (!formData.correctAnswer) { - alert("Please select a correct answer") + toast.error("Missing correct answer", { + description: "Select the correct answer for this question.", + }) return } if (formData.type === "multiple-choice") { const hasEmptyOptions = formData.options.some((opt) => !opt.trim()) if (hasEmptyOptions) { - alert("Please fill in all options") + toast.error("Incomplete options", { + description: "Fill in all answer options for this multiple choice question.", + }) return } } } else if (formData.type === "short-answer") { if (!formData.correctAnswer.trim()) { - alert("Please enter a correct answer") + toast.error("Missing correct answer", { + description: "Enter the expected correct answer.", + }) return } } // In a real app, save the question here console.log("Saving question:", formData) - alert(isEditing ? "Question updated successfully!" : "Question created successfully!") + toast.success(isEditing ? "Question updated" : "Question created", { + description: isEditing + ? "The question has been updated successfully." + : "Your new question has been created.", + }) navigate("/content/questions") } diff --git a/src/pages/content-management/CourseCategoryPage.tsx b/src/pages/content-management/CourseCategoryPage.tsx index fd44f88..6804ef6 100644 --- a/src/pages/content-management/CourseCategoryPage.tsx +++ b/src/pages/content-management/CourseCategoryPage.tsx @@ -1,14 +1,27 @@ import { useEffect, useState } from "react" import { Link } from "react-router-dom" -import { FolderOpen, RefreshCw, AlertCircle, BookOpen } from "lucide-react" +import { FolderOpen, RefreshCw, AlertCircle, BookOpen, Plus } from "lucide-react" import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card" -import { getCourseCategories } from "../../api/courses.api" +import { Button } from "../../components/ui/button" +import { Input } from "../../components/ui/input" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "../../components/ui/dialog" +import { getCourseCategories, createCourseCategory } from "../../api/courses.api" import type { CourseCategory } from "../../types/course.types" +import { toast } from "sonner" export function CourseCategoryPage() { const [categories, setCategories] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) + const [createOpen, setCreateOpen] = useState(false) + const [newCategoryName, setNewCategoryName] = useState("") + const [creating, setCreating] = useState(false) const fetchCategories = async () => { setLoading(true) @@ -68,11 +81,21 @@ export function CourseCategoryPage() { return (
{/* Page header */} -
-

Course Categories

-

- Browse and manage your course categories below -

+
+
+

Course Categories

+

+ Browse and manage your course categories below +

+
+
{categories.length === 0 ? ( @@ -126,6 +149,75 @@ export function CourseCategoryPage() { ))}
)} + + {/* Create category dialog */} + + + + + + Create course category + + + Add a new high-level bucket to organize your courses. + + + +
+
+ + setNewCategoryName(e.target.value)} + /> +
+
+ +
+ + +
+
+
) } diff --git a/src/pages/issues/IssuesPage.tsx b/src/pages/issues/IssuesPage.tsx index 7241c29..891f63c 100644 --- a/src/pages/issues/IssuesPage.tsx +++ b/src/pages/issues/IssuesPage.tsx @@ -20,6 +20,7 @@ import { CheckCircle2, XCircle, ArrowUpCircle, + MessageCircle, } from "lucide-react"; import { Button } from "../../components/ui/button"; import { Input } from "../../components/ui/input"; @@ -201,6 +202,12 @@ export function IssuesPage() { // Status update const [statusUpdating, setStatusUpdating] = useState(null); + // Create issue dialog (admin-created) + const [createOpen, setCreateOpen] = useState(false); + const [createSubject, setCreateSubject] = useState(""); + const [createType, setCreateType] = useState("bug"); + const [createDescription, setCreateDescription] = useState(""); + const fetchIssues = useCallback(async () => { setLoading(true); try { @@ -345,17 +352,26 @@ export function IssuesPage() { Review and manage user-reported issues across the platform.

- +
+ + +
{/* Stats cards */} @@ -840,6 +856,90 @@ export function IssuesPage() { + {/* Create Issue Dialog */} + + + + + + Create admin issue + + + Log an issue directly from the admin panel so it can be tracked and resolved. + + + +
+
+ + setCreateSubject(e.target.value)} + /> +
+
+ + +
+
+ +