From 6e1ffdcc72d78e7031d2696745d87c99cca30ab9 Mon Sep 17 00:00:00 2001 From: Deepak Singh <32263182+deepaksing@users.noreply.github.com> Date: Wed, 5 Jul 2023 19:20:36 +0530 Subject: [PATCH] feat: Skeleton loading #404 (#458) * feat: Skeleton loading #404 * fix: skeleton loading * fix: skeleton loading * feat: Skeleton loading #404 * fix: skeleton loading * fix: skeleton loading * Update CompanyPickerSkeleton.tsx * updated changes --- front/package.json | 1 + front/src/index.tsx | 1 + .../components/CompanyAccountOwnerPicker.tsx | 1 + .../people/components/PeopleCompanyPicker.tsx | 1 + .../components/SingleEntitySelect.tsx | 1 + .../components/SingleEntitySelectBase.tsx | 42 ++++++----- .../skeletons/CompanyPickerSkeleton.tsx | 31 ++++++++ .../DropdownMenuItemContainerSkeleton.tsx | 20 ++++++ .../hooks/useFilteredSearchEntityQuery.ts | 71 +++++++++++-------- front/yarn.lock | 5 ++ 10 files changed, 126 insertions(+), 48 deletions(-) create mode 100644 front/src/modules/relation-picker/components/skeletons/CompanyPickerSkeleton.tsx create mode 100644 front/src/modules/relation-picker/components/skeletons/DropdownMenuItemContainerSkeleton.tsx diff --git a/front/package.json b/front/package.json index de66b1df4..c49c90d42 100644 --- a/front/package.json +++ b/front/package.json @@ -30,6 +30,7 @@ "react-datepicker": "^4.11.0", "react-dom": "^18.2.0", "react-hotkeys-hook": "^4.4.0", + "react-loading-skeleton": "^3.3.1", "react-modal": "^3.16.1", "react-router-dom": "^6.4.4", "react-textarea-autosize": "^8.4.1", diff --git a/front/src/index.tsx b/front/src/index.tsx index 79c55f635..d42099078 100644 --- a/front/src/index.tsx +++ b/front/src/index.tsx @@ -14,6 +14,7 @@ import { UserProvider } from './providers/user/UserProvider'; import { App } from './App'; import './index.css'; +import 'react-loading-skeleton/dist/skeleton.css'; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement, diff --git a/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx b/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx index 116c83f6c..cae334ded 100644 --- a/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx +++ b/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx @@ -59,6 +59,7 @@ export function CompanyAccountOwnerPicker({ company }: OwnProps) { ); diff --git a/front/src/modules/relation-picker/components/SingleEntitySelect.tsx b/front/src/modules/relation-picker/components/SingleEntitySelect.tsx index ddfbd5ac5..b8f49fe35 100644 --- a/front/src/modules/relation-picker/components/SingleEntitySelect.tsx +++ b/front/src/modules/relation-picker/components/SingleEntitySelect.tsx @@ -16,6 +16,7 @@ import { SingleEntitySelectBase } from './SingleEntitySelectBase'; export type EntitiesForSingleEntitySelect< CustomEntityForSelect extends EntityForSelect, > = { + loading: boolean; selectedEntity: CustomEntityForSelect; entitiesToSelect: CustomEntityForSelect[]; }; diff --git a/front/src/modules/relation-picker/components/SingleEntitySelectBase.tsx b/front/src/modules/relation-picker/components/SingleEntitySelectBase.tsx index e7b8b361b..70b2b8d46 100644 --- a/front/src/modules/relation-picker/components/SingleEntitySelectBase.tsx +++ b/front/src/modules/relation-picker/components/SingleEntitySelectBase.tsx @@ -10,6 +10,9 @@ import { isDefined } from '@/utils/type-guards/isDefined'; import { useEntitySelectScroll } from '../hooks/useEntitySelectScroll'; +import { CompanyPickerSkeleton } from './skeletons/CompanyPickerSkeleton'; +import { DropdownMenuItemContainerSkeleton } from './skeletons/DropdownMenuItemContainerSkeleton'; + export type EntitiesForSingleEntitySelect< CustomEntityForSelect extends EntityForSelect, > = { @@ -50,24 +53,29 @@ export function SingleEntitySelectBase< return ( - {entitiesInDropdown?.map((entity, index) => ( - onEntitySelected(entity)} - > - - {entity.name} - - ))} - {entitiesInDropdown?.length === 0 && ( + {entities.loading ? ( + + + + ) : entitiesInDropdown.length === 0 ? ( No result + ) : ( + entitiesInDropdown?.map((entity, index) => ( + onEntitySelected(entity)} + > + + {entity.name} + + )) )} ); diff --git a/front/src/modules/relation-picker/components/skeletons/CompanyPickerSkeleton.tsx b/front/src/modules/relation-picker/components/skeletons/CompanyPickerSkeleton.tsx new file mode 100644 index 000000000..dac861bdb --- /dev/null +++ b/front/src/modules/relation-picker/components/skeletons/CompanyPickerSkeleton.tsx @@ -0,0 +1,31 @@ +import Skeleton from 'react-loading-skeleton'; +import styled from '@emotion/styled'; + +type OwnProps = { + count: number; +}; + +export const SkeletonContainer = styled.div` + align-items: center; + display: inline-flex; + margin-bottom: ${({ theme }) => theme.spacing(1)}; + position: relative; + width: 100%; +`; + +export const SkeletonEntityName = styled.div` + margin-left: ${({ theme }) => theme.spacing(2)}; + width: 100%; +`; + +export function CompanyPickerSkeleton({ count }: OwnProps) { + const loadSkeletons = Array(count).fill(1); + return loadSkeletons.map((_, i) => ( + + + + + + + )); +} diff --git a/front/src/modules/relation-picker/components/skeletons/DropdownMenuItemContainerSkeleton.tsx b/front/src/modules/relation-picker/components/skeletons/DropdownMenuItemContainerSkeleton.tsx new file mode 100644 index 000000000..f84ce98b0 --- /dev/null +++ b/front/src/modules/relation-picker/components/skeletons/DropdownMenuItemContainerSkeleton.tsx @@ -0,0 +1,20 @@ +import styled from '@emotion/styled'; + +export const DropdownMenuItemContainerSkeleton = styled.div` + --horizontal-padding: ${({ theme }) => theme.spacing(1.5)}; + --vertical-padding: ${({ theme }) => theme.spacing(2)}; + + align-items: center; + + border-radius: ${({ theme }) => theme.border.radius.sm}; + color: ${({ theme }) => theme.font.color.secondary}; + + font-size: ${({ theme }) => theme.font.size.sm}; + + gap: ${({ theme }) => theme.spacing(2)}; + + height: calc(100% - 2 * var(--vertical-padding)); + + padding: var(--vertical-padding) var(--horizontal-padding); + width: calc(100% - 2 * var(--horizontal-padding)); +`; diff --git a/front/src/modules/relation-picker/hooks/useFilteredSearchEntityQuery.ts b/front/src/modules/relation-picker/hooks/useFilteredSearchEntityQuery.ts index dffd1b2db..13c0986fc 100644 --- a/front/src/modules/relation-picker/hooks/useFilteredSearchEntityQuery.ts +++ b/front/src/modules/relation-picker/hooks/useFilteredSearchEntityQuery.ts @@ -71,18 +71,19 @@ export function useFilteredSearchEntityQuery< limit?: number; searchFilter: string; }): EntitiesForMultipleEntitySelect { - const { data: selectedEntitiesData } = queryHook({ - variables: { - where: { - id: { - in: selectedIds, + const { loading: selectedEntitiesLoading, data: selectedEntitiesData } = + queryHook({ + variables: { + where: { + id: { + in: selectedIds, + }, }, - }, - orderBy: { - [orderByField]: sortOrder, - }, - } as QueryVariables, - }); + orderBy: { + [orderByField]: sortOrder, + }, + } as QueryVariables, + }); const searchFilterByField = searchOnFields.map((field) => ({ [field]: { @@ -91,7 +92,10 @@ export function useFilteredSearchEntityQuery< }, })); - const { data: filteredSelectedEntitiesData } = queryHook({ + const { + loading: filteredSelectedEntitiesLoading, + data: filteredSelectedEntitiesData, + } = queryHook({ variables: { where: { AND: [ @@ -111,26 +115,27 @@ export function useFilteredSearchEntityQuery< } as QueryVariables, }); - const { data: entitiesToSelectData } = queryHook({ - variables: { - where: { - AND: [ - { - OR: searchFilterByField, - }, - { - id: { - notIn: selectedIds, + const { loading: entitiesToSelectLoading, data: entitiesToSelectData } = + queryHook({ + variables: { + where: { + AND: [ + { + OR: searchFilterByField, }, - }, - ], - }, - limit: limit ?? DEFAULT_SEARCH_REQUEST_LIMIT, - orderBy: { - [orderByField]: sortOrder, - }, - } as QueryVariables, - }); + { + id: { + notIn: selectedIds, + }, + }, + ], + }, + limit: limit ?? DEFAULT_SEARCH_REQUEST_LIMIT, + orderBy: { + [orderByField]: sortOrder, + }, + } as QueryVariables, + }); return { selectedEntities: (selectedEntitiesData?.searchResults ?? []).map( @@ -142,5 +147,9 @@ export function useFilteredSearchEntityQuery< entitiesToSelect: (entitiesToSelectData?.searchResults ?? []).map( mappingFunction, ), + loading: + entitiesToSelectLoading || + filteredSelectedEntitiesLoading || + selectedEntitiesLoading, }; } diff --git a/front/yarn.lock b/front/yarn.lock index 94352b3ce..ad6acc968 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -14507,6 +14507,11 @@ react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-loading-skeleton@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/react-loading-skeleton/-/react-loading-skeleton-3.3.1.tgz#cd6e3a626ee86c76a46c14e2379243f2f8834e1b" + integrity sha512-NilqqwMh2v9omN7LteiDloEVpFyMIa0VGqF+ukqp0ncVlYu1sKYbYGX9JEl+GtOT9TKsh04zCHAbavnQ2USldA== + react-modal@^3.16.1: version "3.16.1" resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.1.tgz#34018528fc206561b1a5467fc3beeaddafb39b2b"