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 GuzzleHttp\Client;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Nette\NotImplementedException;
|
use Nette\NotImplementedException;
|
||||||
use Pterodactyl\Exceptions\DisplayException;
|
use Pterodactyl\Exceptions\DisplayException;
|
||||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
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');
|
$this->modpack_class_id = config('curseforge.minecraft_modpack_class_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index() {
|
public function index(Request $request) {
|
||||||
$result = $this->http_client->get("mods/search?gameid=$this->minecraft_game_id&classid=$this->modpack_class_id&sortField=2");
|
$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) {
|
if($result->getStatusCode() !== 200) {
|
||||||
throw new DisplayException('Failed to fetch modpacks from CurseForge.');
|
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';
|
import { Modpack } from './Modpack';
|
||||||
|
|
||||||
export default (uuid: string): Promise<any> => {
|
export default (uuid: string, pageIndex: number = 0): Promise<any> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
http.get(`/api/client/servers/${uuid}/modpacks`)
|
http.get(`/api/client/servers/${uuid}/modpacks?pageindex=${pageIndex}`)
|
||||||
.then((response) =>
|
.then((response) => {
|
||||||
resolve((response.data.data || []).map((item: any) => rawDataToModpackData(item))))
|
|
||||||
|
console.log(rawDataToModpackPaginationData(response.data.pagination), response.data.pagination);
|
||||||
|
resolve([(response.data.data || []).map((item: any) => rawDataToModpackData(item)), rawDataToModpackPaginationData(response.data.pagination)])
|
||||||
|
})
|
||||||
.catch(reject);
|
.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 => ({
|
export const rawDataToModpackData = (data: any): Modpack => ({
|
||||||
id: data.id,
|
id: data.id,
|
||||||
gameId: data.gameId,
|
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 Spinner from '@/components/elements/Spinner';
|
||||||
import Fade from '@/components/elements/Fade';
|
import Fade from '@/components/elements/Fade';
|
||||||
import { Modpack } from '@/api/server/modpacks/Modpack';
|
import { Modpack } from '@/api/server/modpacks/Modpack';
|
||||||
|
import Pagination from '@/components/elements/Pagination';
|
||||||
|
import { PaginatedResult } from '@/api/http';
|
||||||
|
|
||||||
export default() => {
|
export default() => {
|
||||||
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
|
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
|
||||||
const [loading, setLoading] = useState(true);
|
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(() => {
|
useEffect(() => {
|
||||||
setLoading(!modpacks.length);
|
setLoading(!modpacks?.items.length);
|
||||||
|
|
||||||
getModpacks(uuid)
|
getModpacks(uuid)
|
||||||
.then((modpacks) => setModpacks(modpacks))
|
.then((modpacksResult) => {
|
||||||
|
setModpacks({items: modpacksResult[0], pagination: modpacksResult[1]});
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ServerContentBlock title="Modpacks">
|
<ServerContentBlock title="Modpacks">
|
||||||
<FlashMessageRender byKey={'modpacks'} css={tw`mb-4`} />
|
<FlashMessageRender byKey={'modpacks'} css={tw`mb-4`} />
|
||||||
{!modpacks.length && loading ? (
|
{(modpacks == undefined || !modpacks?.items.length) && loading ? (
|
||||||
<Spinner size={'large'} centered />
|
<Spinner size={'large'} centered />
|
||||||
) : (
|
) : (
|
||||||
<Fade timeout={150}>
|
<Fade timeout={150}>
|
||||||
<div className='grid grid-cols-3 gap-4'>
|
<div className='grid grid-cols-3 gap-4'>
|
||||||
{modpacks.length > 0 ? (
|
<Pagination data={modpacks as PaginatedResult<Modpack>} onPageSelect={changePage} paginationButtonsClassNames='col-span-3'>
|
||||||
modpacks.map((modpack, index) => (
|
{({ items }) => (
|
||||||
|
items.length > 0 ? (
|
||||||
|
modpacks?.items.map((modpack, index) => (
|
||||||
<ModpackItem
|
<ModpackItem
|
||||||
key={modpack.id}
|
key={modpack.id}
|
||||||
modpack={modpack}
|
modpack={modpack}
|
||||||
|
|
@ -45,7 +69,8 @@ export default() => {
|
||||||
<p css={tw`text-center text-sm text-neutral-300`}>
|
<p css={tw`text-center text-sm text-neutral-300`}>
|
||||||
Couldn't fetch modpacks.
|
Couldn't fetch modpacks.
|
||||||
</p>
|
</p>
|
||||||
)}
|
))}
|
||||||
|
</Pagination>
|
||||||
</div>
|
</div>
|
||||||
</Fade>
|
</Fade>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue