testing 127.0.0.1 issue

Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-07-07 13:40:07 +08:00
parent 244aa607f7
commit 6624c0d27f
62 changed files with 662 additions and 1889 deletions
+41 -18
View File
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { House, Timer, ChevronLeft, ChevronRight, LockIcon, Tag, Check, ShoppingCart } from "lucide-react";
import { House, Timer, ChevronLeft, ChevronRight, LockIcon, Tag, Tags, Check, ShoppingCart } from "lucide-react";
import AppBreadcrumb from "@/components/generic/Breadcrumb/AppBreadcrumb";
import { Input } from "@/components/ui/input";
import {
@@ -20,6 +20,7 @@ import { resolveTierBadge } from "@/utils/tierBadge.util";
import { Building2 } from "lucide-react";
import { useClientAdvertisements } from "@/contexts/ClientAdvertisementContext";
import { Banner, BannerSkeleton } from "@/components/generic/Blocks/Client/Advertisements/Banner";
import { GitBranch } from "lucide-react";
// ─── Helpers ──────────────────────────────────────────────────────────────────
@@ -37,8 +38,8 @@ const ITEMS_PER_PAGE = 10;
// ─── Course Card ──────────────────────────────────────────────────────────────
const CourseCard = ({ course, tierMap, onViewDetails }) => {
const slug = course.subscription ?? "free";
const locked = course.is_locked;
const slug = course.subscription ?? "free";
const locked = course.is_locked;
const duration = formatDuration(course.duration_seconds);
const { rank, label, cls } = resolveTierBadge(slug, tierMap);
@@ -58,11 +59,14 @@ const CourseCard = ({ course, tierMap, onViewDetails }) => {
{locked ? <LockIcon className="size-3" /> : <Tag className="size-3" />}
{label}
</Badge>
{course.level && (
<Badge variant="outline">{course.level.charAt(0).toUpperCase() + course.level.slice(1)}</Badge>
{course.level && !locked && (
<Badge variant="outline"><GitBranch />{course.level.charAt(0).toUpperCase() + course.level.slice(1)}</Badge>
)}
{(course.categories ?? []).map((cat) => (
<Badge key={cat.id} variant="outline"><Tags /> {cat.name}</Badge>
))}
{locked && (
<Badge variant="secondary" className="ml-auto">
<Badge variant="secondary">
<LockIcon className="size-3" /> Locked
</Badge>
)}
@@ -113,7 +117,7 @@ const CourseCardSkeleton = () => (
const Pagination = ({ currentPage, totalPages, totalItems, itemsPerPage, onPageChange }) => {
const start = (currentPage - 1) * itemsPerPage + 1;
const end = Math.min(currentPage * itemsPerPage, totalItems);
const end = Math.min(currentPage * itemsPerPage, totalItems);
const getPages = () => {
const pages = [];
@@ -165,12 +169,12 @@ const CoursesList = () => {
const { advertisements, loading: adLoading, getActiveAdvertisement, handleAdCtaClick } = useClientAdvertisements();
const [tierCategories, setTierCategories] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [search, setSearch] = useState("");
const [levelFilter, setLevelFilter] = useState("All");
const [subFilter, setSubFilter] = useState("All");
const [currentPage, setCurrentPage] = useState(1);
const [search, setSearch] = useState("");
const [levelFilter, setLevelFilter] = useState("All");
const [subFilter, setSubFilter] = useState("All");
const [categoryFilter, setCategoryFilter] = useState("All");
const [modalOpen, setModalOpen] = useState(false);
const [modalOpen, setModalOpen] = useState(false);
const [selectedCourse, setSelectedCourse] = useState(null);
const [allCategories, setAllCategories] = useState([]);
@@ -179,10 +183,10 @@ const CoursesList = () => {
getCourses();
api.get("/client/tiers/categories")
.then(({ data }) => setTierCategories(data.data ?? []))
.catch(() => {});
.catch(() => { });
api.get("/client/courses/categories")
.then(({ data }) => setAllCategories(data.data ?? []))
.catch(() => {});
.catch(() => { });
getActiveAdvertisement("course_list.banner");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -199,10 +203,10 @@ const CoursesList = () => {
const filtered = useMemo(() =>
courses
.filter((c) => {
const matchSearch = c.title.toLowerCase().includes(search.toLowerCase()) ||
const matchSearch = c.title.toLowerCase().includes(search.toLowerCase()) ||
(c.description ?? "").toLowerCase().includes(search.toLowerCase());
const matchLevel = levelFilter === "All" || (c.level ?? "").toLowerCase() === levelFilter.toLowerCase();
const matchSub = subFilter === "All" || c.subscription === subFilter;
const matchLevel = levelFilter === "All" || (c.level ?? "").toLowerCase() === levelFilter.toLowerCase();
const matchSub = subFilter === "All" || c.subscription === subFilter;
const matchCategory = categoryFilter === "All" || (c.categories ?? []).some((cat) => String(cat.id) === categoryFilter);
return matchSearch && matchLevel && matchSub && matchCategory;
})
@@ -211,7 +215,7 @@ const CoursesList = () => {
);
const totalPages = Math.max(1, Math.ceil(filtered.length / ITEMS_PER_PAGE));
const paginated = filtered.slice((currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE);
const paginated = filtered.slice((currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE);
const handleViewDetails = (course) => {
if (course.is_locked) {
@@ -299,6 +303,25 @@ const CoursesList = () => {
<Banner ad={bannerAd} onCtaClick={handleAdCtaClick} />
)}
{categoryFilter !== "All" && (
<div className="flex items-center flex-wrap gap-2">
<span className="text-sm text-muted-foreground">Tags:</span>
{allCategories
.filter((cat) => String(cat.id) === categoryFilter)
.map((cat) => (
<Badge
key={cat.id}
variant="default"
className="cursor-pointer"
onClick={() => { setCategoryFilter("All"); setCurrentPage(1); }}
>
<Tags className="size-3" />
{cat.name}
</Badge>
))}
</div>
)}
{/* Course Grid */}
{coursesLoading ? (
<div className="xs:pt-12 lg:pt-0 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">