Feat: Added Pagination for services page (#1334)

* change ui to support paging for services page

* fix count issue on tab change

* change pagine with load more btn with micro interaction

* made seprate component for load more pagination button

* make seprate type for loading status and miner fix

* miner fix
This commit is contained in:
Shailesh Parmar 2021-11-23 20:00:45 +05:30 committed by GitHub
parent 499c9c546f
commit f6dfc62a4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 150 additions and 8 deletions

View File

@ -0,0 +1,57 @@
import { LoadingState } from 'Models';
import React from 'react';
import { Button } from '../../buttons/Button/Button';
import Loader from '../../Loader/Loader';
type LoadMorePaginationProps = {
isLoading: boolean;
showLoadingText?: boolean;
status: LoadingState;
buttonText: string;
handleClick: () => void;
};
const LoadMorePagination = ({
isLoading,
status,
buttonText,
showLoadingText,
handleClick,
}: LoadMorePaginationProps) => {
return (
<>
{isLoading ? (
<Button
disabled
className="tw-h-10"
size="regular"
theme="primary"
variant="contained">
<Loader size="small" type="white" />
{showLoadingText && <span className="tw-pl-1.5">Loading</span>}
</Button>
) : status === 'success' ? (
<Button
disabled
className="tw-h-10 disabled:tw-opacity-100"
size="regular"
theme="primary"
variant="contained">
<i aria-hidden="true" className="fa fa-check" />
</Button>
) : (
<Button
className="tw-h-10"
data-testid="saveManageTab"
size="regular"
theme="primary"
variant="contained"
onClick={handleClick}>
<span>{buttonText}</span>
</Button>
)}
</>
);
};
export default LoadMorePagination;

View File

@ -118,8 +118,11 @@ declare module 'Models' {
export type Paging = { export type Paging = {
after: string; after: string;
before: string; before: string;
total?: number;
}; };
export type LoadingState = 'initial' | 'waiting' | 'success';
export type TableDetail = { export type TableDetail = {
description: string; description: string;
name: string; name: string;

View File

@ -17,8 +17,14 @@
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import classNames from 'classnames'; import classNames from 'classnames';
import { isNull, lowerCase } from 'lodash'; import { isNil, isNull, lowerCase } from 'lodash';
import { ServiceCollection, ServiceData, ServiceTypes } from 'Models'; import {
LoadingState,
Paging,
ServiceCollection,
ServiceData,
ServiceTypes,
} from 'Models';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { import {
@ -29,6 +35,7 @@ import {
updateService, updateService,
} from '../../axiosAPIs/serviceAPI'; } from '../../axiosAPIs/serviceAPI';
import { Button } from '../../components/buttons/Button/Button'; import { Button } from '../../components/buttons/Button/Button';
import LoadMorePagination from '../../components/common/LoadMorePagination/LoadMorePagination';
import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction'; import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction';
import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer'; import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer';
import Searchbar from '../../components/common/searchbar/Searchbar'; import Searchbar from '../../components/common/searchbar/Searchbar';
@ -43,6 +50,7 @@ import {
import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal'; import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal';
import { import {
getServiceDetailsPath, getServiceDetailsPath,
pagingObject,
TITLE_FOR_NON_ADMIN_ACTION, TITLE_FOR_NON_ADMIN_ACTION,
} from '../../constants/constants'; } from '../../constants/constants';
import { import {
@ -50,6 +58,7 @@ import {
NoDataFoundPlaceHolder, NoDataFoundPlaceHolder,
servicesDisplayName, servicesDisplayName,
} from '../../constants/services.const'; } from '../../constants/services.const';
import { CursorType } from '../../enums/pagination.enum';
import { ServiceCategory } from '../../enums/service.enum'; import { ServiceCategory } from '../../enums/service.enum';
import { import {
DashboardService, DashboardService,
@ -71,6 +80,13 @@ type ServiceRecord = {
pipelineServices: Array<PipelineService>; pipelineServices: Array<PipelineService>;
}; };
type ServicePagingRecord = {
databaseServices: Paging;
messagingServices: Paging;
dashboardServices: Paging;
pipelineServices: Paging;
};
export type ApiData = { export type ApiData = {
description: string; description: string;
href: string; href: string;
@ -92,6 +108,12 @@ const ServicesPage = () => {
}); });
const [serviceName, setServiceName] = const [serviceName, setServiceName] =
useState<ServiceTypes>('databaseServices'); useState<ServiceTypes>('databaseServices');
const [paging, setPaging] = useState<ServicePagingRecord>({
databaseServices: pagingObject,
messagingServices: pagingObject,
dashboardServices: pagingObject,
pipelineServices: pagingObject,
});
const [services, setServices] = useState<ServiceRecord>({ const [services, setServices] = useState<ServiceRecord>({
databaseServices: [], databaseServices: [],
messagingServices: [], messagingServices: [],
@ -102,6 +124,8 @@ const ServicesPage = () => {
const [editData, setEditData] = useState<ServiceDataObj>(); const [editData, setEditData] = useState<ServiceDataObj>();
const [isLoading, setIsLoading] = useState<boolean>(false); const [isLoading, setIsLoading] = useState<boolean>(false);
const [searchText, setSearchText] = useState(''); const [searchText, setSearchText] = useState('');
const [currentTabTotalCount, setCurrentTabTotalCount] = useState(0);
const [servicesCount, setServicesCount] = useState({ const [servicesCount, setServicesCount] = useState({
databaseServices: 0, databaseServices: 0,
messagingServices: 0, messagingServices: 0,
@ -109,6 +133,9 @@ const ServicesPage = () => {
pipelineServices: 0, pipelineServices: 0,
}); });
const [isLoadingMore, setIsLoadingMore] = useState<boolean>(false);
const [status, setStatus] = useState<LoadingState>('initial');
const updateServiceList = ( const updateServiceList = (
allServiceCollectionArr: Array<ServiceCollection> allServiceCollectionArr: Array<ServiceCollection>
) => { ) => {
@ -122,24 +149,34 @@ const ServicesPage = () => {
(result: PromiseSettledResult<AxiosResponse>[]) => { (result: PromiseSettledResult<AxiosResponse>[]) => {
if (result.length) { if (result.length) {
let serviceArr = []; let serviceArr = [];
let servicePagingArr = [];
const serviceRecord = {} as ServiceRecord; const serviceRecord = {} as ServiceRecord;
const servicePaging = {} as ServicePagingRecord;
serviceArr = result.map((service) => serviceArr = result.map((service) =>
service.status === 'fulfilled' ? service.value?.data?.data : [] service.status === 'fulfilled' ? service.value?.data?.data : []
); );
servicePagingArr = result.map((service) =>
service.status === 'fulfilled' ? service.value?.data?.paging : {}
);
for (let i = 0; i < serviceArr.length; i++) { for (let i = 0; i < serviceArr.length; i++) {
serviceRecord[allServiceCollectionArr[i].value as ServiceTypes] = serviceRecord[allServiceCollectionArr[i].value as ServiceTypes] =
serviceArr[i]; serviceArr[i];
servicePaging[allServiceCollectionArr[i].value as ServiceTypes] =
servicePagingArr[i];
} }
setServices(serviceRecord); setServices(serviceRecord);
setPaging(servicePaging);
setServicesCount({ setServicesCount({
databaseServices: serviceRecord.databaseServices.length, databaseServices: servicePaging.databaseServices.total || 0,
messagingServices: serviceRecord.messagingServices.length, messagingServices: servicePaging.messagingServices.total || 0,
dashboardServices: serviceRecord.dashboardServices.length, dashboardServices: servicePaging.dashboardServices.total || 0,
pipelineServices: serviceRecord.pipelineServices.length, pipelineServices: servicePaging.pipelineServices.total || 0,
}); });
setServiceList( setServiceList(
serviceRecord[serviceName] as unknown as Array<ServiceDataObj> serviceRecord[serviceName] as unknown as Array<ServiceDataObj>
); );
setCurrentTabTotalCount(servicePaging[serviceName].total || 0);
} }
setIsLoading(false); setIsLoading(false);
} }
@ -308,7 +345,7 @@ const ServicesPage = () => {
setSearchText(''); setSearchText('');
setServicesCount({ setServicesCount({
...servicesCount, ...servicesCount,
[serviceName]: services[serviceName].length, [serviceName]: currentTabTotalCount,
}); });
setServiceName(tabName); setServiceName(tabName);
setServiceList(services[tabName] as unknown as Array<ServiceDataObj>); setServiceList(services[tabName] as unknown as Array<ServiceDataObj>);
@ -382,6 +419,35 @@ const ServicesPage = () => {
} }
}; };
const pagingHandler = (cursorType: string) => {
setIsLoadingMore(true);
setStatus('waiting');
const currentServicePaging = paging[serviceName];
const pagingString = `${serviceName}?${cursorType}=${
currentServicePaging[cursorType as keyof Paging]
}`;
getServices(pagingString)
.then((result: AxiosResponse) => {
const currentServices = [...services[serviceName], ...result.data.data];
setServiceList(currentServices);
setServices({
...services,
[serviceName]: currentServices,
});
setPaging({
...paging,
[serviceName]: result.data.paging,
});
setStatus('success');
})
.finally(() => {
setIsLoadingMore(false);
setStatus('initial');
});
};
useEffect(() => { useEffect(() => {
// fetch all service collection // fetch all service collection
setIsLoading(true); setIsLoading(true);
@ -406,6 +472,10 @@ const ServicesPage = () => {
}); });
}, []); }, []);
useEffect(() => {
setCurrentTabTotalCount(servicesCount[serviceName]);
}, [serviceName]);
return ( return (
<> <>
{!isLoading ? ( {!isLoading ? (
@ -458,7 +528,7 @@ const ServicesPage = () => {
</div> </div>
{serviceList.length ? ( {serviceList.length ? (
<div <div
className="tw-grid tw-grid-cols-4 tw-gap-4" className="tw-grid tw-grid-cols-4 tw-gap-4 tw-mb-4"
data-testid="data-container"> data-testid="data-container">
{serviceList.map((service, index) => ( {serviceList.map((service, index) => (
<div <div
@ -589,6 +659,18 @@ const ServicesPage = () => {
</div> </div>
)} )}
{!isNil(paging[serviceName].after) && (
<div className="tw-my-4 tw-flex tw-justify-center tw-items-center">
<LoadMorePagination
showLoadingText
buttonText="Load more"
handleClick={() => pagingHandler(CursorType.AFTER)}
isLoading={isLoadingMore}
status={status}
/>
</div>
)}
{isModalOpen && ( {isModalOpen && (
<AddServiceModal <AddServiceModal
data={editData} data={editData}