Roadmap to becoming a developer in 2022
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

185 lines
4.5 KiB

import { useEffect, useState } from 'react';
import { useToast } from '../../hooks/use-toast';
import { httpGet } from '../../lib/http';
import { AIRoadmapAlert } from '../GenerateRoadmap/AIRoadmapAlert.tsx';
import { ExploreAISorting, type SortByValues } from './ExploreAISorting.tsx';
import {
deleteUrlParam,
getUrlParams,
setUrlParams,
} from '../../lib/browser.ts';
import { Pagination } from '../Pagination/Pagination.tsx';
import { LoadingRoadmaps } from './LoadingRoadmaps.tsx';
import { EmptyRoadmaps } from './EmptyRoadmaps.tsx';
import { AIRoadmapsList } from './AIRoadmapsList.tsx';
import { ExploreAISearch } from './ExploreAISearch.tsx';
export interface AIRoadmapDocument {
_id?: string;
term: string;
title: string;
data: string;
viewCount: number;
createdAt: Date;
updatedAt: Date;
}
type ExploreRoadmapsResponse = {
data: AIRoadmapDocument[];
totalCount: number;
totalPages: number;
currPage: number;
perPage: number;
};
type QueryParams = {
q?: string;
s?: SortByValues;
p?: string;
};
type PageState = {
searchTerm: string;
sortBy: SortByValues;
currentPage: number;
};
export function ExploreAIRoadmap() {
const toast = useToast();
const [pageState, setPageState] = useState<PageState>({
searchTerm: '',
sortBy: 'createdAt',
currentPage: 0,
});
useEffect(() => {
const queryParams = getUrlParams() as QueryParams;
setPageState({
searchTerm: queryParams.q || '',
sortBy: queryParams.s || 'createdAt',
currentPage: +(queryParams.p || '1'),
});
}, []);
useEffect(() => {
setIsLoading(true);
if (!pageState.currentPage) {
return;
}
// only set the URL params if the user modified anything
if (
pageState.currentPage !== 1 ||
pageState.searchTerm !== '' ||
pageState.sortBy !== 'createdAt'
) {
setUrlParams({
q: pageState.searchTerm,
s: pageState.sortBy,
p: String(pageState.currentPage),
});
} else {
deleteUrlParam('q');
deleteUrlParam('s');
deleteUrlParam('p');
}
loadAIRoadmaps(
pageState.currentPage,
pageState.searchTerm,
pageState.sortBy,
).finally(() => {
setIsLoading(false);
});
}, [pageState]);
const [isLoading, setIsLoading] = useState(true);
const [roadmapsResponse, setRoadmapsResponse] =
useState<ExploreRoadmapsResponse | null>(null);
const loadAIRoadmaps = async (
currPage: number = 1,
searchTerm: string = '',
sortBy: SortByValues = 'createdAt',
) => {
const { response, error } = await httpGet<ExploreRoadmapsResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-list-ai-roadmaps`,
{
currPage,
...(searchTerm && { term: searchTerm }),
...(sortBy && { sortBy }),
},
);
if (error || !response) {
toast.error(error?.message || 'Something went wrong');
return;
}
setRoadmapsResponse(response);
};
const roadmaps = roadmapsResponse?.data || [];
const loadingIndicator = isLoading && <LoadingRoadmaps />;
const emptyRoadmaps = !isLoading && roadmaps.length === 0 && (
<EmptyRoadmaps />
);
const roadmapsList = !isLoading && roadmaps.length > 0 && (
<>
<AIRoadmapsList response={roadmapsResponse} />
<Pagination
currPage={roadmapsResponse?.currPage || 1}
totalPages={roadmapsResponse?.totalPages || 1}
perPage={roadmapsResponse?.perPage || 0}
isDisabled={isLoading}
totalCount={roadmapsResponse?.totalCount || 0}
onPageChange={(page) => {
setPageState({
...pageState,
currentPage: page,
});
}}
/>
</>
);
return (
<section className="container mx-auto py-3 sm:py-6">
<AIRoadmapAlert isListing />
<div className="my-3.5 flex items-stretch justify-between gap-2.5">
<ExploreAISearch
total={roadmapsResponse?.totalCount || 0}
isLoading={isLoading}
value={pageState.searchTerm}
onSubmit={(term: string) => {
setPageState({
...pageState,
searchTerm: term,
currentPage: 1,
});
}}
/>
<ExploreAISorting
sortBy={pageState.sortBy}
onSortChange={(sortBy) => {
setPageState({
...pageState,
sortBy,
currentPage: 1,
});
}}
/>
</div>
{loadingIndicator}
{emptyRoadmaps}
{roadmapsList}
</section>
);
}