Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the useInputResourceGroupOverlay hook #658

Merged
merged 3 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/app-elements/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ export {
useCoreApi,
useCoreSdkProvider
} from '#providers/CoreSdkProvider'
export { createApp, type ClAppKey, type ClAppProps } from '#providers/createApp'
export { ErrorBoundary } from '#providers/ErrorBoundary'
export { GTMProvider, useTagManager } from '#providers/GTMProvider'
export {
Expand All @@ -67,6 +66,7 @@ export {
type TokenProviderRolePermissions,
type TokenProviderTokenApplicationKind
} from '#providers/TokenProvider'
export { createApp, type ClAppKey, type ClAppProps } from '#providers/createApp'

// Atoms
export { A, type AProps } from '#ui/atoms/A'
Expand Down Expand Up @@ -229,6 +229,7 @@ export { InputReadonly, type InputReadonlyProps } from '#ui/forms/InputReadonly'
export {
HookedInputResourceGroup,
InputResourceGroup,
useInputResourceGroupOverlay,
type HookedInputResourceGroupProps,
type InputResourceGroupProps
} from '#ui/forms/InputResourceGroup'
Expand Down
1 change: 1 addition & 0 deletions packages/app-elements/src/ui/atoms/Icon/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const iconMapping = {
cloudArrowUp: phosphor.CloudArrowUp,
creditCard: phosphor.CreditCard,
currencyEur: phosphor.CurrencyEur,
dotsSixVertical: phosphor.DotsSixVertical,
dotsThree: phosphor.DotsThree,
download: phosphor.Download,
envelopeSimple: phosphor.EnvelopeSimple,
Expand Down
150 changes: 94 additions & 56 deletions packages/app-elements/src/ui/forms/InputResourceGroup/FullList.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { useOverlay } from '#hooks/useOverlay'
import { AvatarLetter } from '#ui/atoms/AvatarLetter'
import { Card } from '#ui/atoms/Card'
import { SkeletonTemplate } from '#ui/atoms/SkeletonTemplate'
import { Spacer } from '#ui/atoms/Spacer'
import { Text } from '#ui/atoms/Text'
import { SearchBar } from '#ui/composite/SearchBar'
import { InputCheckboxGroupItem } from '#ui/forms/InputCheckboxGroup/InputCheckboxGroupItem'
import { InputWrapper } from '#ui/internals/InputWrapper'
import { type OverlayProps } from '#ui/internals/Overlay'
import { ResourceList } from '#ui/resources/ResourceList'
import { type ListableResourceType, type QueryFilter } from '@commercelayer/sdk'
import isEmpty from 'lodash/isEmpty'
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { InputCheckboxGroupItem } from '../InputCheckboxGroup/InputCheckboxGroupItem'
import {
computeLabelWithSelected,
prepareCheckboxItemOrMock,
Expand Down Expand Up @@ -67,14 +67,14 @@ export interface FullListProps {
* It will be automatically computed with the number of selected items.
*/
title: string
/**
* Total count of pre-fetched items.
*/
totalCount?: number
/**
* Show icon in checkbox selectors
*/
showCheckboxIcon?: boolean
/**
* Hide selected items
*/
hideSelected?: boolean
}

export function FullList({
Expand All @@ -86,12 +86,15 @@ export function FullList({
searchBy,
sortBy,
title,
totalCount,
showCheckboxIcon = true
showCheckboxIcon = true,
hideSelected = false
}: FullListProps): JSX.Element {
const { values, toggleValue } = useToggleCheckboxValues(defaultValues)
const [filters, setFilters] = useState<QueryFilter>({})
const [search, setSearch] = useState<string>('')

const initialValues = useMemo(() => defaultValues, [])

const selectedCount = values.length

useEffect(() => {
Expand Down Expand Up @@ -127,54 +130,89 @@ export function FullList({
</Spacer>
)}

<SkeletonTemplate isLoading={totalCount == null || totalCount === 0}>
<InputWrapper
fieldset
label={computeLabelWithSelected({
label: title,
selectedCount,
totalCount
})}
>
<Card gap='1' overflow='hidden'>
<ResourceList
type={resource}
emptyState={<div>No items found</div>}
query={{
pageSize: 25,
filters,
sort: {
[sortBy.attribute]: sortBy.direction
<SkeletonTemplate>
<ResourceList
type={resource}
title={(totalCount) => (
<Text weight='semibold'>
{computeLabelWithSelected({
label: title,
selectedCount: hideSelected
? selectedCount - initialValues.length
: selectedCount,
totalCount:
hideSelected && totalCount != null
? totalCount - initialValues.length
: totalCount
})}
</Text>
)}
variant='boxed'
emptyState={<div>No items found</div>}
query={{
pageSize: 25,
filters,
sort: {
[sortBy.attribute]: sortBy.direction
}
}}
ItemTemplate={({ isLoading, resource }) => {
const item = prepareCheckboxItemOrMock({
resource,
isLoading,
fieldForLabel,
fieldForValue
})

if (hideSelected && initialValues.includes(item.value)) {
return null
}

return (
<InputCheckboxGroupItem
isLoading={isLoading}
checked={values.includes(item.value)}
onChange={() => {
toggleValue(item.value)
}}
icon={
showCheckboxIcon ? (
<AvatarLetter text={item.label} />
) : undefined
}
}}
ItemTemplate={({ isLoading, resource }) => {
const item = prepareCheckboxItemOrMock({
resource,
isLoading,
fieldForLabel,
fieldForValue
})
return (
<InputCheckboxGroupItem
isLoading={isLoading}
checked={values.includes(item.value)}
onChange={() => {
toggleValue(item.value)
}}
icon={
showCheckboxIcon ? (
<AvatarLetter text={item.label} />
) : undefined
}
content={<Text weight='semibold'>{item.label}</Text>}
value={item.value}
/>
)
}}
/>
</Card>
</InputWrapper>
content={<Text weight='semibold'>{item.label}</Text>}
value={item.value}
/>
)
}}
/>
</SkeletonTemplate>
</div>
)
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export const useInputResourceGroupOverlay = () => {
const { Overlay, close, open } = useOverlay()

const InputResourceGroupOverlay = useCallback(
({
footer,
backgroundColor,
...props
}: FullListProps & Omit<OverlayProps, 'children'>) => (
<Overlay backgroundColor={backgroundColor} footer={footer}>
<div className='pt-5'>
<FullList {...props} />
</div>
</Overlay>
),
[Overlay]
)

return {
InputResourceGroupOverlay,
openInputResourceGroupOverlay: open,
closeInputResourceGroupOverlay: close
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { formatResourceName } from '#helpers/resources'
import { useOverlay } from '#hooks/useOverlay'
import { useCoreApi } from '#providers/CoreSdkProvider'
import { AvatarLetter } from '#ui/atoms/AvatarLetter'
import { Button } from '#ui/atoms/Button'
Expand All @@ -16,7 +15,11 @@ import {
} from '@commercelayer/sdk'
import uniqBy from 'lodash/uniqBy'
import { useEffect, useState } from 'react'
import { FullList, type FullListProps, type SortBy } from './FullList'
import {
useInputResourceGroupOverlay,
type FullListProps,
type SortBy
} from './FullList'
import {
computeLabelWithSelected,
prepareCheckboxItemOrMock,
Expand Down Expand Up @@ -61,10 +64,9 @@ export const InputResourceGroup: React.FC<InputResourceGroupProps> = ({
filters = {},
hideWhenSingleItem,
showCheckboxIcon = true,
hideSelected = false,
title
}) => {
const { Overlay, close, open } = useOverlay()

const { values, toggleValue, setValues } =
useToggleCheckboxValues(defaultValues)
const selectedCount = values.length
Expand All @@ -90,6 +92,12 @@ export const InputResourceGroup: React.FC<InputResourceGroupProps> = ({
[values]
)

const {
InputResourceGroupOverlay,
closeInputResourceGroupOverlay,
openInputResourceGroupOverlay
} = useInputResourceGroupOverlay()

const isEmptyList = !isLoading && list.length === 0
const isHidden =
hideWhenSingleItem === true &&
Expand Down Expand Up @@ -136,7 +144,7 @@ export const InputResourceGroup: React.FC<InputResourceGroupProps> = ({
<button
type='button'
onClick={() => {
open()
openInputResourceGroupOverlay()
}}
>
<Text variant='primary' weight='bold'>
Expand All @@ -149,35 +157,30 @@ export const InputResourceGroup: React.FC<InputResourceGroupProps> = ({
</button>
</Spacer>
) : null}
<Overlay
<InputResourceGroupOverlay
footer={
<Button
fullWidth
type='button'
onClick={() => {
close()
closeInputResourceGroupOverlay()
setSelectedValuesForPreview(values)
}}
>
Apply
</Button>
}
>
<div className='pt-5'>
<FullList
defaultValues={values}
fieldForLabel={fieldForLabel}
fieldForValue={fieldForValue}
onChange={setValues}
resource={resource}
searchBy={searchBy}
sortBy={sortBy}
title={title}
totalCount={totalCount}
showCheckboxIcon={showCheckboxIcon}
/>
</div>
</Overlay>
defaultValues={values}
fieldForLabel={fieldForLabel}
fieldForValue={fieldForValue}
onChange={setValues}
resource={resource}
searchBy={searchBy}
sortBy={sortBy}
title={title}
hideSelected={hideSelected}
showCheckboxIcon={showCheckboxIcon}
/>
</InputWrapper>
</SkeletonTemplate>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { useInputResourceGroupOverlay } from './FullList'
export {
HookedInputResourceGroup,
type HookedInputResourceGroupProps
Expand Down
Loading