Skip to content

Commit

Permalink
Merge pull request #13 from appwrite/pagination
Browse files Browse the repository at this point in the history
Pagination
  • Loading branch information
TorstenDittmann committed May 20, 2022
2 parents bfc43f8 + f712bff commit f573024
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 54 deletions.
112 changes: 77 additions & 35 deletions src/lib/components/pagination.svelte
Original file line number Diff line number Diff line change
@@ -1,54 +1,96 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
export let sum: number;
export let limit: number;
export let offset: number;
export let sum: number;
const dispatch = createEventDispatcher();
const totalPages = Math.ceil(sum / limit);
let currentPage = Math.floor(offset / limit + 1);
function handleOptionClick(page: number) {
if (currentPage !== page) {
offset = limit * (page - 1);
currentPage = page;
dispatch('change');
}
}
const next = () => {
if (offset + limit > sum) {
offset = sum;
} else {
offset += limit;
function handleButtonPage(direction: string) {
if (direction === 'next' && currentPage < totalPages) {
currentPage += 1;
offset = limit * (currentPage - 1);
dispatch('change');
} else if (direction === 'prev' && currentPage > 1) {
currentPage -= 1;
offset = limit * (currentPage - 1);
dispatch('change');
}
dispatch('change');
};
const prev = () => {
if (offset - limit < 0) {
offset = 0;
} else {
offset -= limit;
}
let pages = pagination(currentPage, totalPages);
function pagination(current: number, total: number) {
let delta = 2,
left = current - delta,
right = current + delta + 1,
range = [],
rangeWithDots = [];
for (let i = 1; i <= total; i++) {
if (i == 1 || i == total || (i >= left && i < right)) {
range.push(i);
}
}
dispatch('change');
};
$: noPrev = offset === 0;
$: noNext = sum - limit < offset;
$: currentPage = offset / limit + 1;
$: totalPages = Math.ceil(sum / limit);
rangeWithDots = range.reduce((prev, current, index) => {
if (current - prev[index - 1] > delta) {
prev.push('...');
}
prev.push(current);
return prev;
}, []);
return rangeWithDots;
}
</script>

{#if sum >= limit}
<nav class="pagination is-center">
{#if totalPages > 1}
<nav class="pagination">
<button
on:click={prev}
disabled={noPrev}
class:is-disabled={noPrev}
class="button is-only-icon"
aria-label="previous page">
<span class="icon-left-open" aria-hidden="true" />
on:click={() => handleButtonPage('prev')}
class:is-disabled={currentPage <= 1}
class="button is-text"
aria-label="prev page">
<span class="icon-cheveron-left" aria-hidden="true" />
<span class="text">Prev</span>
</button>
<span class="pagination-info">{currentPage} / {totalPages}</span>
<ol class="pagination-list is-only-desktop">
{#each pages as page}
{#if typeof page === 'number'}
<li class="pagination-item">
<button
class="button"
on:click={() => handleOptionClick(page)}
class:is-disabled={currentPage === page}
class:is-text={currentPage !== page}
aria-label="page">
<span class="text">{page}</span>
</button>
</li>
{:else}
<li class="li is-text">
<span class="icon">...</span>
</li>
{/if}
{/each}
</ol>
<button
on:click={next}
disabled={noNext}
class:is-disabled={noNext}
class="button is-only-icon"
on:click={() => handleButtonPage('next')}
class:is-disabled={currentPage === totalPages}
class="button is-text"
aria-label="next page">
<span class="icon-right-open" aria-hidden="true" />
<span class="text">Next</span>
<span class="icon-cheveron-right" aria-hidden="true" />
</button>
</nav>
{/if}
4 changes: 2 additions & 2 deletions src/routes/console/[project]/users/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
let search = '';
let showCreate = false;
let offset = 0;
const limit = 25;
const limit = 5;
const project = $page.params.project;
const getAvatar = (name: string) => sdkForProject.avatars.getInitials(name, 30, 30).toString();
Expand Down Expand Up @@ -90,7 +90,7 @@
</Table>
<div class="u-flex common-section u-main-space-between">
<p class="text">Total results: {response.total}</p>
<Pagination {limit} bind:offset sum={response.total} />
<Pagination bind:offset {limit} sum={response.total} />
</div>
{:else if search}
<Empty>
Expand Down
65 changes: 48 additions & 17 deletions tests/unit/components/pagination.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { Pagination } from '../../../src/lib/components';

test('shows controls', () => {
const { getByLabelText } = render(Pagination, {
limit: 0,
limit: 100,
offset: 0,
sum: 100
sum: 150
});
expect(getByLabelText('previous page')).toBeInTheDocument();
expect(getByLabelText('prev page')).toBeInTheDocument();
expect(getByLabelText('next page')).toBeInTheDocument();
});

Expand All @@ -19,8 +19,8 @@ test('pagination - first page', () => {
sum: 100
});

expect(getByLabelText('previous page')).toBeDisabled();
expect(getByLabelText('next page')).not.toBeDisabled();
expect(getByLabelText('prev page')).toHaveClass('is-disabled');
expect(getByLabelText('next page')).not.toHaveClass('is-disabled');
});

test('pagination - last page', () => {
Expand All @@ -30,8 +30,8 @@ test('pagination - last page', () => {
sum: 30
});

expect(getByLabelText('previous page')).not.toBeDisabled();
expect(getByLabelText('next page')).toBeDisabled();
expect(getByLabelText('prev page')).not.toHaveClass('is-disabled');
expect(getByLabelText('next page')).toHaveClass('is-disabled');
});

test('pagination - forward', async () => {
Expand All @@ -41,9 +41,9 @@ test('pagination - forward', async () => {
sum: 60
});

const back = getByLabelText('previous page');
const back = getByLabelText('prev page');
const forth = getByLabelText('next page');
expect(back).toBeDisabled();
expect(back).toHaveClass('is-disabled');

await fireEvent.click(forth);
expect(component.offset).toEqual(25);
Expand All @@ -52,8 +52,8 @@ test('pagination - forward', async () => {
expect(component.offset).toEqual(50);

await fireEvent.click(forth);
expect(component.offset).toEqual(60);
expect(forth).toBeDisabled();
expect(component.offset).toEqual(50);
expect(forth).toHaveClass('is-disabled');
});

test('pagination - backwards', async () => {
Expand All @@ -63,19 +63,50 @@ test('pagination - backwards', async () => {
sum: 60
});

const back = getByLabelText('previous page');
const back = getByLabelText('prev page');
const forth = getByLabelText('next page');
expect(forth).toBeDisabled();
expect(forth).toHaveClass('is-disabled');

await fireEvent.click(back);
expect(component.offset).toEqual(30);
expect(component.offset).toEqual(25);

await fireEvent.click(back);
expect(component.offset).toEqual(5);
expect(component.offset).toEqual(0);

await fireEvent.click(back);
expect(component.offset).toEqual(0);
expect(back).toBeDisabled();
expect(back).toHaveClass('is-disabled');
});

test('pagination - number button click', async () => {
const { getByText, getAllByLabelText, component } = render(Pagination, {
limit: 25,
offset: 0,
sum: 60
});

const buttons = getAllByLabelText('page');
const [button1, button2, button3] = buttons;

const one = getByText('1');
const two = getByText('2');
const three = getByText('3');
expect(button1).toHaveClass('is-disabled');

await fireEvent.click(two);
expect(component.offset).toEqual(25);
expect(button1).not.toHaveClass('is-disabled');
expect(button2).toHaveClass('is-disabled');

await fireEvent.click(three);
expect(component.offset).toEqual(50);
expect(button2).not.toHaveClass('is-disabled');
expect(button3).toHaveClass('is-disabled');

await fireEvent.click(one);
expect(component.offset).toEqual(0);
expect(button1).toHaveClass('is-disabled');
expect(button3).not.toHaveClass('is-disabled');
});

test('shows no controls', () => {
Expand All @@ -85,6 +116,6 @@ test('shows no controls', () => {
sum: 10
});

expect(queryByLabelText('previous page')).not.toBeInTheDocument();
expect(queryByLabelText('prev page')).not.toBeInTheDocument();
expect(queryByLabelText('next page')).not.toBeInTheDocument();
});

1 comment on commit f573024

@vercel
Copy link

@vercel vercel bot commented on f573024 May 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.