feat/ai-tutor-redesign
Arik Chakma 1 week ago
parent da14f05079
commit 69ed5d79de
  1. 39
      src/components/AITutor/AIFeaturedCoursesListing.tsx
  2. 32
      src/queries/ai-course.ts

@ -1,5 +1,6 @@
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { import {
listFeaturedAiCoursesOptions,
listUserAiCoursesOptions, listUserAiCoursesOptions,
type ListUserAiCoursesQuery, type ListUserAiCoursesQuery,
} from '../../queries/ai-course'; } from '../../queries/ai-course';
@ -8,6 +9,7 @@ import { useEffect, useState } from 'react';
import { Loader2 } from 'lucide-react'; import { Loader2 } from 'lucide-react';
import { getUrlParams, setUrlParams, deleteUrlParam } from '../../lib/browser'; import { getUrlParams, setUrlParams, deleteUrlParam } from '../../lib/browser';
import { AICourseCard } from '../GenerateCourse/AICourseCard'; import { AICourseCard } from '../GenerateCourse/AICourseCard';
import { Pagination } from '../Pagination/Pagination';
type AIFeaturedCoursesListingProps = {}; type AIFeaturedCoursesListingProps = {};
@ -15,21 +17,18 @@ export function AIFeaturedCoursesListing(props: AIFeaturedCoursesListingProps) {
const [isInitialLoading, setIsInitialLoading] = useState(true); const [isInitialLoading, setIsInitialLoading] = useState(true);
const [pageState, setPageState] = useState<ListUserAiCoursesQuery>({ const [pageState, setPageState] = useState<ListUserAiCoursesQuery>({
perPage: '10', perPage: '20',
currPage: '1', currPage: '1',
query: '',
}); });
const { data: userAiCourses, isFetching: isUserAiCoursesLoading } = useQuery( const { data: featuredAiCourses, isFetching: isFeaturedAiCoursesLoading } =
listUserAiCoursesOptions(pageState), useQuery(listFeaturedAiCoursesOptions(pageState), queryClient);
queryClient,
);
useEffect(() => { useEffect(() => {
setIsInitialLoading(false); setIsInitialLoading(false);
}, [userAiCourses]); }, [featuredAiCourses]);
const courses = userAiCourses?.data ?? []; const courses = featuredAiCourses?.data ?? [];
useEffect(() => { useEffect(() => {
const queryParams = getUrlParams(); const queryParams = getUrlParams();
@ -37,19 +36,16 @@ export function AIFeaturedCoursesListing(props: AIFeaturedCoursesListingProps) {
setPageState({ setPageState({
...pageState, ...pageState,
currPage: queryParams?.p || '1', currPage: queryParams?.p || '1',
query: queryParams?.q || '',
}); });
}, []); }, []);
useEffect(() => { useEffect(() => {
if (pageState?.currPage !== '1' || pageState?.query !== '') { if (pageState?.currPage !== '1') {
setUrlParams({ setUrlParams({
p: pageState?.currPage || '1', p: pageState?.currPage || '1',
q: pageState?.query || '',
}); });
} else { } else {
deleteUrlParam('p'); deleteUrlParam('p');
deleteUrlParam('q');
} }
}, [pageState]); }, [pageState]);
@ -61,7 +57,7 @@ export function AIFeaturedCoursesListing(props: AIFeaturedCoursesListingProps) {
</div> </div>
</div> </div>
{(isUserAiCoursesLoading || isInitialLoading) && ( {(isFeaturedAiCoursesLoading || isInitialLoading) && (
<div className="flex min-h-[152px] items-center justify-center gap-2 rounded-lg border border-gray-200 bg-white py-4"> <div className="flex min-h-[152px] items-center justify-center gap-2 rounded-lg border border-gray-200 bg-white py-4">
<Loader2 <Loader2
className="size-4 animate-spin text-gray-400" className="size-4 animate-spin text-gray-400"
@ -71,7 +67,7 @@ export function AIFeaturedCoursesListing(props: AIFeaturedCoursesListingProps) {
</div> </div>
)} )}
{!isUserAiCoursesLoading && courses && courses.length > 0 && ( {!isFeaturedAiCoursesLoading && courses && courses.length > 0 && (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{courses.map((course) => ( {courses.map((course) => (
<AICourseCard <AICourseCard
@ -81,11 +77,22 @@ export function AIFeaturedCoursesListing(props: AIFeaturedCoursesListingProps) {
showProgress={false} showProgress={false}
/> />
))} ))}
<Pagination
totalCount={featuredAiCourses?.totalCount || 0}
totalPages={featuredAiCourses?.totalPages || 0}
currPage={Number(featuredAiCourses?.currPage || 1)}
perPage={Number(featuredAiCourses?.perPage || 10)}
onPageChange={(page) => {
setPageState({ ...pageState, currPage: String(page) });
}}
className="rounded-lg border border-gray-200 bg-white p-4"
/>
</div> </div>
)} )}
{!isUserAiCoursesLoading && {!isFeaturedAiCoursesLoading &&
(userAiCourses?.data?.length || 0 > 0) && (featuredAiCourses?.data?.length || 0 > 0) &&
courses.length === 0 && ( courses.length === 0 && (
<div className="flex min-h-[114px] items-center justify-center rounded-lg border border-gray-200 bg-white py-4"> <div className="flex min-h-[114px] items-center justify-center rounded-lg border border-gray-200 bg-white py-4">
<p className="text-sm text-gray-600"> <p className="text-sm text-gray-600">

@ -101,6 +101,38 @@ export function listUserAiCoursesOptions(
}; };
} }
type ListFeaturedAiCoursesParams = {};
type ListFeaturedAiCoursesQuery = {
perPage?: string;
currPage?: string;
};
type ListFeaturedAiCoursesResponse = {
data: AICourseWithLessonCount[];
totalCount: number;
totalPages: number;
currPage: number;
perPage: number;
};
export function listFeaturedAiCoursesOptions(
params: ListFeaturedAiCoursesQuery = {
perPage: '10',
currPage: '1',
},
) {
return {
queryKey: ['featured-ai-courses', params],
queryFn: () => {
return httpGet<ListFeaturedAiCoursesResponse>(
`/v1-list-featured-ai-courses`,
params,
);
},
};
}
type ListExploreAiCoursesParams = {}; type ListExploreAiCoursesParams = {};
type ListExploreAiCoursesQuery = { type ListExploreAiCoursesQuery = {

Loading…
Cancel
Save