mirror of https://github.com/Duxez/PteroPack.git
#5 - add pagination
This commit is contained in:
parent
6746f0f78b
commit
e1ec05a30d
|
|
@ -4,6 +4,7 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers\CurseForge;
|
|||
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Nette\NotImplementedException;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
|
|
@ -31,8 +32,13 @@ class ModpackController extends ClientApiController {
|
|||
$this->modpack_class_id = config('curseforge.minecraft_modpack_class_id');
|
||||
}
|
||||
|
||||
public function index() {
|
||||
$result = $this->http_client->get("mods/search?gameid=$this->minecraft_game_id&classid=$this->modpack_class_id&sortField=2");
|
||||
public function index(Request $request) {
|
||||
$index = 0;
|
||||
if($request->has('pageindex')) {
|
||||
$index = $request->get('pageindex');
|
||||
}
|
||||
|
||||
$result = $this->http_client->get("mods/search?gameid=$this->minecraft_game_id&classid=$this->modpack_class_id&sortField=2&sortorder=desc&index=$index");
|
||||
|
||||
if($result->getStatusCode() !== 200) {
|
||||
throw new DisplayException('Failed to fetch modpacks from CurseForge.');
|
||||
|
|
|
|||
|
|
@ -1,14 +1,26 @@
|
|||
import http from '@/api/http'
|
||||
import http, { PaginationDataSet } from '@/api/http'
|
||||
import { Modpack } from './Modpack';
|
||||
|
||||
export default (uuid: string): Promise<any> => {
|
||||
export default (uuid: string, pageIndex: number = 0): Promise<any> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/client/servers/${uuid}/modpacks`)
|
||||
.then((response) =>
|
||||
resolve((response.data.data || []).map((item: any) => rawDataToModpackData(item))))
|
||||
http.get(`/api/client/servers/${uuid}/modpacks?pageindex=${pageIndex}`)
|
||||
.then((response) => {
|
||||
|
||||
console.log(rawDataToModpackPaginationData(response.data.pagination), response.data.pagination);
|
||||
resolve([(response.data.data || []).map((item: any) => rawDataToModpackData(item)), rawDataToModpackPaginationData(response.data.pagination)])
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
export const rawDataToModpackPaginationData = (data: any): PaginationDataSet => ({
|
||||
total: data.totalCount,
|
||||
count: data.resultCount,
|
||||
perPage: data.pageSize,
|
||||
currentPage: Math.ceil((data.index + data.pageSize) / data.pageSize) == 0 ? 1 : Math.ceil((data.index + data.pageSize) / data.pageSize),
|
||||
totalPages: Math.ceil(data.totalCount / data.pageSize) + 1
|
||||
});
|
||||
|
||||
export const rawDataToModpackData = (data: any): Modpack => ({
|
||||
id: data.id,
|
||||
gameId: data.gameId,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
import React from 'react';
|
||||
import { PaginatedResult } from '@/api/http';
|
||||
import tw from 'twin.macro';
|
||||
import styled from 'styled-components/macro';
|
||||
import Button from '@/components/elements/Button';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faAngleDoubleLeft, faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
interface RenderFuncProps<T> {
|
||||
items: T[];
|
||||
isLastPage: boolean;
|
||||
isFirstPage: boolean;
|
||||
}
|
||||
|
||||
interface Props<T> {
|
||||
data: PaginatedResult<T>;
|
||||
showGoToLast?: boolean;
|
||||
showGoToFirst?: boolean;
|
||||
onPageSelect: (page: number) => void;
|
||||
children: (props: RenderFuncProps<T>) => React.ReactNode;
|
||||
paginationButtonsClassNames?: string;
|
||||
}
|
||||
|
||||
const Block = styled(Button)`
|
||||
${tw`p-0 w-10 h-10`}
|
||||
|
||||
&:not(:last-of-type) {
|
||||
${tw`mr-2`};
|
||||
}
|
||||
`;
|
||||
|
||||
function Pagination<T>({ data: { items, pagination }, onPageSelect, children, paginationButtonsClassNames}: Props<T>) {
|
||||
const isFirstPage = pagination.currentPage === 1;
|
||||
const isLastPage = pagination.currentPage >= pagination.totalPages;
|
||||
|
||||
const pages = [];
|
||||
|
||||
// Start two spaces before the current page. If that puts us before the starting page default
|
||||
// to the first page as the starting point.
|
||||
const start = Math.max(pagination.currentPage - 2, 1);
|
||||
const end = Math.min(pagination.totalPages, pagination.currentPage + 5);
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{children({ items, isFirstPage, isLastPage })}
|
||||
<div className={paginationButtonsClassNames}>
|
||||
{pages.length > 1 && (
|
||||
<div css={tw`mt-4 flex justify-center`}>
|
||||
{pages[0] > 1 && !isFirstPage && (
|
||||
<Block isSecondary color={'primary'} onClick={() => onPageSelect(1)}>
|
||||
<FontAwesomeIcon icon={faAngleDoubleLeft} />
|
||||
</Block>
|
||||
)}
|
||||
{pages.map((i) => (
|
||||
<Block
|
||||
isSecondary={pagination.currentPage !== i}
|
||||
color={'primary'}
|
||||
key={`block_page_${i}`}
|
||||
onClick={() => onPageSelect(i)}
|
||||
>
|
||||
{i}
|
||||
</Block>
|
||||
))}
|
||||
{pages[4] < pagination.totalPages && !isLastPage && (
|
||||
<Block isSecondary color={'primary'} onClick={() => onPageSelect(pagination.totalPages)}>
|
||||
<FontAwesomeIcon icon={faAngleDoubleRight} />
|
||||
</Block>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Pagination;
|
||||
|
|
@ -12,30 +12,54 @@ import databases from '@/state/server/databases';
|
|||
import Spinner from '@/components/elements/Spinner';
|
||||
import Fade from '@/components/elements/Fade';
|
||||
import { Modpack } from '@/api/server/modpacks/Modpack';
|
||||
import Pagination from '@/components/elements/Pagination';
|
||||
import { PaginatedResult } from '@/api/http';
|
||||
|
||||
export default() => {
|
||||
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [page, setPage] = useState(1);
|
||||
|
||||
const [modpacks, setModpacks] = useState<Modpack[]>([]);
|
||||
const [modpacks, setModpacks] = useState<PaginatedResult<Modpack>>();
|
||||
|
||||
const changePage = (newPage: number) => {
|
||||
setPage(newPage);
|
||||
setLoading(true);
|
||||
|
||||
let pageIndex = 0;
|
||||
if(modpacks?.pagination.perPage != undefined) {
|
||||
pageIndex = (modpacks.pagination.perPage * newPage) - modpacks.pagination.perPage;
|
||||
console.log(pageIndex, modpacks.pagination.perPage, newPage);
|
||||
}
|
||||
|
||||
getModpacks(uuid, pageIndex)
|
||||
.then((modpacksResult) => {
|
||||
setModpacks({items: modpacksResult[0], pagination: modpacksResult[1]});
|
||||
setLoading(false);
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(!modpacks.length);
|
||||
setLoading(!modpacks?.items.length);
|
||||
|
||||
getModpacks(uuid)
|
||||
.then((modpacks) => setModpacks(modpacks))
|
||||
.then((modpacksResult) => {
|
||||
setModpacks({items: modpacksResult[0], pagination: modpacksResult[1]});
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ServerContentBlock title="Modpacks">
|
||||
<FlashMessageRender byKey={'modpacks'} css={tw`mb-4`} />
|
||||
{!modpacks.length && loading ? (
|
||||
{(modpacks == undefined || !modpacks?.items.length) && loading ? (
|
||||
<Spinner size={'large'} centered />
|
||||
) : (
|
||||
<Fade timeout={150}>
|
||||
<div className='grid grid-cols-3 gap-4'>
|
||||
{modpacks.length > 0 ? (
|
||||
modpacks.map((modpack, index) => (
|
||||
<Pagination data={modpacks as PaginatedResult<Modpack>} onPageSelect={changePage} paginationButtonsClassNames='col-span-3'>
|
||||
{({ items }) => (
|
||||
items.length > 0 ? (
|
||||
modpacks?.items.map((modpack, index) => (
|
||||
<ModpackItem
|
||||
key={modpack.id}
|
||||
modpack={modpack}
|
||||
|
|
@ -45,7 +69,8 @@ export default() => {
|
|||
<p css={tw`text-center text-sm text-neutral-300`}>
|
||||
Couldn't fetch modpacks.
|
||||
</p>
|
||||
)}
|
||||
))}
|
||||
</Pagination>
|
||||
</div>
|
||||
</Fade>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Reference in New Issue