Skip to content

Commit

Permalink
Fixes for Customers page #1209, #1225 (#1226)
Browse files Browse the repository at this point in the history
  • Loading branch information
olemp authored Mar 21, 2024
1 parent abc1f35 commit 5ef0465
Show file tree
Hide file tree
Showing 15 changed files with 119 additions and 93 deletions.
5 changes: 3 additions & 2 deletions client/components/FormControl/SwitchControl/SwitchControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import _ from 'underscore'
import { Field } from '../Field'
import { FormInputControlComponent } from '../types'
import styles from './SwitchControl.module.scss'
import { useSwitchControlChange } from './useSwitchControlChange'
import { useSwitchControl } from './useSwitchControl'

/**
* Text field based on `<Switch />` from `@fluentui/react-components`
Expand All @@ -13,13 +13,14 @@ import { useSwitchControlChange } from './useSwitchControlChange'
* @category Reusable Component
*/
export const SwitchControl: FormInputControlComponent = (props) => {
const onChange = useSwitchControlChange(props)
const { value, onChange } = useSwitchControl(props)
return (
<Field
className={SwitchControl.className}
{..._.pick(props, 'name', 'label', 'description', 'required', 'hidden')}
>
<Switch
checked={value}
onChange={(event, data) => onChange(event, data.checked)}
defaultChecked={props.model?.value<boolean>(props.name)}
/>
Expand Down
23 changes: 23 additions & 0 deletions client/components/FormControl/SwitchControl/useSwitchControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useCallback } from 'react'
import { FormInputControlBase } from '../types'

/**
* Custom hook for handling switch control logic.
*
* @param props - The props for the switch control.
* @returns An object containing the `onChange` function.
*/
export function useSwitchControl(props: FormInputControlBase) {
const value = props.model?.value<boolean>(props.name)

const onChange = useCallback(
(_event, value: boolean) => {
// eslint-disable-next-line no-console
console.log('onChange', props.name, value)
props.model.set(props.name, value)
},
[props.model]
)

return { value, onChange }
}

This file was deleted.

File renamed without changes.
1 change: 1 addition & 0 deletions client/components/List/ListHeader/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ListHeader'
32 changes: 17 additions & 15 deletions client/components/List/ListToolbar/useListToolbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,23 @@ export function useListToolbar() {
[context.props.commandBar]
)

const menuItems = useMemo(
() =>
_.isEmpty(context.props.menuItems)
? ListMenuItem.convert([
...commandBarProps.items,
...commandBarProps.farItems
])
: [
searchBoxMenuItem,
...context.props.menuItems,
filterCommands.toggle?.menuItem,
excelExportCommands?.menuItem
].filter(Boolean),
[context.props.menuItems]
)
const menuItemsFromProps = _.isFunction(context.props.menuItems)
? context.props.menuItems(context)
: context.props.menuItems

const menuItems = useMemo(() => {
return _.isEmpty(menuItemsFromProps)
? ListMenuItem.convert([
...commandBarProps.items,
...commandBarProps.farItems
])
: [
searchBoxMenuItem,
...menuItemsFromProps,
filterCommands.toggle?.menuItem,
excelExportCommands?.menuItem
].filter(Boolean)
}, [menuItemsFromProps])

const menuItemGroups = useMemo<{ [key: string]: ListMenuItem[] }>(
() =>
Expand Down
46 changes: 31 additions & 15 deletions client/components/List/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,32 @@ export const FILTERS_UPDATED = createAction<{ filters: IFilter[] }>(
'FILTERS_UPDATED'
)

/**
* Applies filters to an array of items based on the provided filter values.
*
* @param items The array of items to filter.
* @param filterValues The filter values to apply.
*/
function applyFilters<T = any>(
items: T[],
filterValues: IListState['filterValues'] = {}
) {
return items.filter(
(item) =>
_.filter(Object.keys(filterValues), (key) => {
const value = get(item as any, key, '')
switch (typeof value) {
case 'boolean': {
return filterValues[key] === value
}
default: {
return filterValues[key].includes(value)
}
}
}).length === Object.keys(filterValues).length
)
}

/**
* Reducer for Timesheet
*
Expand All @@ -42,28 +68,18 @@ export default (initialState: IListState) => {
builder
.addCase(PROPS_UPDATED, (state, { payload }) => {
state.origItems = payload.items ?? []
state.items = state.origItems
.filter((item) =>
searchObject({
item,
searchTerm: state.searchTerm
})
)
.filter((item) => {
return (
_.filter(Object.keys(payload.filterValues), (key) => {
return payload.filterValues[key].includes(get(item, key, ''))
}).length === Object.keys(payload.filterValues).length
)
})
state.itemsPreFilter = state.origItems
state.filterValues = payload.filterValues ?? {}
state.items = applyFilters(state.itemsPreFilter, state.filterValues)
})
.addCase(EXECUTE_SEARCH, (state, { payload }) => {
state.items = current(state).origItems.filter((item) =>
state.itemsPreFilter = current(state).origItems.filter((item) =>
searchObject({
item,
searchTerm: payload.searchTerm
})
)
state.items = applyFilters(state.itemsPreFilter, state.filterValues)
state.searchTerm = payload.searchTerm
})
.addCase(INIT_COLUMN_HEADER_CONTEXT_MENU, (state, { payload }) => {
Expand Down
4 changes: 3 additions & 1 deletion client/components/List/types/IListProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { IListColumn } from './IListColumn'
import { IListGroupProps } from './IListGroupProps'
import { ListFilterState } from './ListFilterState'
import { IFilterPanelProps } from 'components/FilterPanel'
import { IListContext } from '../context'

/**
* @category List
Expand Down Expand Up @@ -109,8 +110,9 @@ export interface IListProps<T = any>

/**
* Menu items to show in `<Toolbar />` if using the preview mode.
* This can also be a function that returns the menu items.
*/
menuItems?: ListMenuItem[]
menuItems?: ListMenuItem[] | ((context: IListContext) => ListMenuItem[])

/**
* Hide the toolbar
Expand Down
11 changes: 11 additions & 0 deletions client/components/List/types/IListState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ export interface IListState<T = any> {
*/
searchTerm?: string

/**
* Filter values
*/
filterValues?: Record<string, any>

/**
* Original items
*/
Expand All @@ -22,6 +27,12 @@ export interface IListState<T = any> {
*/
items?: T[]

/**
* Items before filters are applied,
* but after search term is applied.
*/
itemsPreFilter?: T[]

/**
* Current filters
*/
Expand Down
1 change: 1 addition & 0 deletions client/components/List/useList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function useList(props: IListProps) {
const [state, dispatch] = useListReducer({
origItems: props.items,
items: props.items,
itemsPreFilter: props.items,
searchTerm: ''
})

Expand Down
2 changes: 1 addition & 1 deletion client/components/List/useListProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import _ from 'underscore'
import { IListContext } from './context'
import { ItemColumn } from './ItemColumn'
import { ListGroupHeader } from './ListGroupHeader'
import { ListHeader } from './ListHeader'
import { ListHeader } from './ListHeader/ListHeader'
import { INIT_COLUMN_HEADER_CONTEXT_MENU } from './reducer'
import { IListColumn, IListProps } from './types'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ export const CustomerInformation: StyledComponent = () => {

return (
<div className={CustomerInformation.className}>
<UserMessage
hidden={!context.state.selected?.inactive}
text={t('customers.inactiveText')}
intent='warning'
/>
<InformationProperty
hidden={!context.state.selected?.description}
title={t('common.descriptionFieldLabel')}
Expand All @@ -47,6 +42,11 @@ export const CustomerInformation: StyledComponent = () => {
))}
</InformationProperty>
)}
<UserMessage
hidden={!context.state.selected?.inactive}
text={t('customers.inactiveText')}
intent='warning'
/>
</div>
)
}
Expand Down
36 changes: 23 additions & 13 deletions client/pages/Customers/CustomerList/CustomerList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,38 @@ import { useCustomerList } from './useCustomerList'
export const CustomerList: TabComponent = (props) => {
const { t } = useTranslation()
const context = useCustomersContext()
const { customers, inactiveCustomers, columns, showInactive } =
useCustomerList()

const { columns, showInactive } = useCustomerList()
return (
<>
<List
searchBox={{ placeholder: t('common.searchPlaceholder') }}
enableShimmer={context.loading}
items={customers}
items={context.state.customers}
columns={columns}
menuItems={[
inactiveCustomers.length > 0 &&
InactiveCheckboxMenuItem(
t('customers.toggleInactive', {
count: inactiveCustomers.length
}),
showInactive.toggle
)
]}
menuItems={(_context) => {
return context.state.customers.some((c) => c.inactive)
? [
InactiveCheckboxMenuItem(
t('customers.toggleInactive', {
count: _context.state.itemsPreFilter.filter(
(c) => c.inactive
).length
}),
showInactive.toggle
)
]
: []
}}
getColumnStyle={(customer) => ({
opacity: customer.inactive ? 0.4 : 1
})}
filterValues={
showInactive.value
? {}
: {
inactive: false
}
}
/>
{props.children}
</>
Expand Down
20 changes: 0 additions & 20 deletions client/pages/Customers/CustomerList/useCustomerList.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { useContext, useEffect, useState } from 'react'
import { useBoolean } from 'usehooks-ts'
import { CustomersContext } from '../context'
import { useColumns } from './useColumns'

/**
Expand All @@ -13,28 +11,10 @@ import { useColumns } from './useColumns'
* @category Customers
*/
export const useCustomerList = () => {
const context = useContext(CustomersContext)
const [customers, setCustomers] = useState([...context.state.customers])
const showInactive = useBoolean(false)
const columns = useColumns()

useEffect(
() =>
setCustomers(
[...context.state.customers].filter(
(p) => showInactive.value || !p.inactive
)
),
[context.state.customers, showInactive.value]
)

const inactiveCustomers = context.state.customers.filter(
({ inactive }) => inactive
)

return {
customers,
inactiveCustomers,
columns,
showInactive
}
Expand Down
2 changes: 0 additions & 2 deletions client/pages/Projects/ProjectForm/ProjectForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ export const ProjectForm: TabComponent<IProjectFormProps> = (props) => {
model.value('customerKey'),
!props.edit
)
// eslint-disable-next-line no-console
console.log(formControlProps.model.value())
return (
<FormControl {...formControlProps}>
<Pivot
Expand Down

0 comments on commit 5ef0465

Please sign in to comment.