From 806614d697d011ba3a689ec57fd868cf15bccb63 Mon Sep 17 00:00:00 2001 From: Adam Rybinski Date: Tue, 2 Nov 2021 09:22:06 +0100 Subject: [PATCH] Update paginationMachine.js --- paginationMachine.js | 182 +++++++++++++++++++++++++++---------------- 1 file changed, 117 insertions(+), 65 deletions(-) diff --git a/paginationMachine.js b/paginationMachine.js index a82fe53..c977adc 100644 --- a/paginationMachine.js +++ b/paginationMachine.js @@ -1,71 +1,123 @@ -import { assign, createMachine } from './deps.js'; +import { assign, createMachine } from 'xstate'; +import { choose } from 'xstate/lib/actions'; -const infiniteScrollMachine = createMachine({ - id: 'infiniteScroll', - initial: 'fetchingRowOfData', - context: { - totalEntries: Infinity, - data: [] - }, - states: { - fetchingRowOfData: { - on: { - RECEIVED_DATA: { - target: 'checkingIfThereIsMoreData', - actions: ['assignDataToContext'] - } - }, - invoke: { - src: 'fetchRowOfData', - onError: { - target: 'idle', - actions: 'assignErrorMessageToContext' - } - } +export interface PaginationMachineContext { + totalPages?: number; + /** + * This page is 1-indexed, not 0-indexed + */ + currentPage: number; +} + +export type PaginationMachineEvent = + | { + type: 'UPDATE_TOTAL_PAGES'; + totalPages: number; + } + | { + type: 'NEXT_PAGE'; + } + | { + type: 'PREV_PAGE'; + } + | { + type: 'GO_TO_TARGET_PAGE'; + targetPage: number; + }; + +const paginationMachine = createMachine< + PaginationMachineContext, + PaginationMachineEvent +>( + { + id: 'pagination', + initial: 'awaitingTotalPages', + context: { + currentPage: 1, }, - idle: { - exit: ['clearErrorMessage'], - on: { - SCROLL_TO_BOTTOM: 'fetchingRowOfData' - } + on: { + UPDATE_TOTAL_PAGES: { + cond: 'newTotalPagesIsValidValue', + actions: choose([ + { + cond: 'currentPageIsAboveNewTotalPages', + actions: ['assignTotalPagesToContext', 'goToFirstPage'], + }, + { + actions: ['assignTotalPagesToContext'], + }, + ]), + target: 'idle', + }, }, - checkingIfThereIsMoreData: { - always: [{ - cond: 'thereIsMoreData', - target: 'idle' - }, { - target: 'noMoreDataToFetch' - }] + states: { + awaitingTotalPages: {}, + idle: { + on: { + NEXT_PAGE: { + cond: 'canGoToNextPage', + actions: 'goToNextPage', + }, + PREV_PAGE: { + cond: 'canGoToPrevPage', + actions: 'goToPrevPage', + }, + GO_TO_TARGET_PAGE: { + actions: 'goToTargetPage', + cond: 'targetPageIsWithinBounds', + }, + }, + }, }, - noMoreDataToFetch: { - type: 'final' - } - } -}, { - guards: { - thereIsMoreData: context => { - return context.totalEntries > context.data.length; - } }, - services: { - fetchRowOfData: () => send => {} + { + guards: { + newTotalPagesIsValidValue: (context, event) => { + if (event.type !== 'UPDATE_TOTAL_PAGES') return false; + + return event.totalPages > 0; + }, + currentPageIsAboveNewTotalPages: (context, event) => { + if (event.type !== 'UPDATE_TOTAL_PAGES') return false; + + return context.currentPage > event.totalPages; + }, + canGoToNextPage: (context) => { + return context.currentPage < context.totalPages; + }, + canGoToPrevPage: (context) => { + return context.currentPage > 1; + }, + targetPageIsWithinBounds: (context, event) => { + if (event.type !== 'GO_TO_TARGET_PAGE') return false; + return event.targetPage >= 1 && event.targetPage <= context.totalPages; + }, + }, + actions: { + goToFirstPage: assign({ + currentPage: 1, + }), + goToPrevPage: assign({ + currentPage: (context) => context.currentPage - 1, + }), + goToNextPage: assign({ + currentPage: (context) => context.currentPage + 1, + }), + goToTargetPage: assign((context, event) => { + if (event.type !== 'GO_TO_TARGET_PAGE') return {}; + + return { + currentPage: event.targetPage, + }; + }), + assignTotalPagesToContext: assign((context, event) => { + if (event.type !== 'UPDATE_TOTAL_PAGES') return {}; + return { + totalPages: event.totalPages, + }; + }), + }, }, - actions: { - assignDataToContext: assign((context, event) => { - if (event.type !== 'RECEIVED_DATA') return {}; - return { - data: [...context.data, ...event.data], - totalEntries: event.totalEntries - }; - }), - clearErrorMessage: assign(context => ({ - errorMessage: undefined - })), - assignErrorMessageToContext: assign((context, event) => { - return { - errorMessage: event.data?.message || 'An unknown error occurred' - }; - }) - } -}); -export default infiniteScrollMachine; +); + +export default paginationMachine;