Skip to content

Commit 7a963c0

Browse files
committed
feat(condo): DOMA-13196 review fixes
1 parent fcec4ce commit 7a963c0

4 files changed

Lines changed: 73 additions & 44 deletions

File tree

apps/condo/domains/billing/access/BillingReceipt.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
const { throwAuthenticationError } = require('@open-condo/keystone/apolloErrorFormatter')
6-
const { find, getById } = require('@open-condo/keystone/schema')
6+
const { find } = require('@open-condo/keystone/schema')
77

88
const { canManageBillingEntityWithContext } = require('@condo/domains/billing/utils/accessSchema')
99
const { canReadObjectsAsB2BAppServiceUser } = require('@condo/domains/miniapp/utils/b2bAppServiceUserAccess')
@@ -71,7 +71,7 @@ const isSoftDeleteInput = (data) => {
7171
const target = data?.data || data
7272
if (typeof target !== 'object' || target === null) return false
7373

74-
return Object.hasOwn(target, 'deletedAt') &&
74+
return !!target?.deletedAt &&
7575
Object.keys(target).every(key => SOFT_DELETE_ALLOWED_UPDATE_FIELDS.has(key))
7676
}
7777

apps/condo/domains/billing/components/BillingPageContent/ReceiptsTable.tsx

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,56 @@ const FILTERS_GUTTER: RowProps['gutter'] = [16, 20]
5050
const ASC = 'ASC'
5151
const DESC = 'DESC'
5252

53+
const getSortQueryValue = (sortState: FullTableState['sortState']): string | undefined => {
54+
if (!sortState?.length) return undefined
55+
56+
const firstSort = sortState[0]
57+
const sortOrder = firstSort.desc ? DESC : ASC
58+
return `${firstSort.id}_${sortOrder}`
59+
}
60+
61+
const getFiltersWithGlobalSearch = (filterState: FullTableState['filterState'], globalFilter?: string): FullTableState['filterState'] => {
62+
const nextFilters = { ...filterState }
63+
64+
if (globalFilter && globalFilter.trim() !== '') {
65+
nextFilters.search = globalFilter
66+
} else {
67+
delete nextFilters.search
68+
}
69+
70+
return nextFilters
71+
}
72+
73+
const setQueryParam = (query: Record<string, string | string[]>, key: string, value: string | undefined): void => {
74+
if (value) {
75+
query[key] = value
76+
return
77+
}
78+
79+
delete query[key]
80+
}
81+
82+
const buildNextTableQuery = (
83+
currentQuery: Record<string, string | string[]>,
84+
params: FullTableState
85+
): Record<string, string | string[]> => {
86+
const { startRow, filterState, sortState, rowSelectionState, globalFilter } = params
87+
const nextFilters = getFiltersWithGlobalSearch(filterState, globalFilter)
88+
const nextQuery = { ...currentQuery }
89+
90+
const nextOffset = startRow > 0 ? String(startRow) : undefined
91+
const nextFiltersValue = Object.keys(nextFilters).length > 0 ? JSON.stringify(nextFilters) : undefined
92+
const nextSortValue = getSortQueryValue(sortState)
93+
const nextSelectedRows = rowSelectionState?.length > 0 ? JSON.stringify(rowSelectionState) : undefined
94+
95+
setQueryParam(nextQuery, 'offset', nextOffset)
96+
setQueryParam(nextQuery, 'filters', nextFiltersValue)
97+
setQueryParam(nextQuery, 'sort', nextSortValue)
98+
setQueryParam(nextQuery, 'selectedRows', nextSelectedRows)
99+
100+
return nextQuery
101+
}
102+
53103
export const ReceiptsTable: React.FC = () => {
54104
const intl = useIntl()
55105
const SearchPlaceholder = intl.formatMessage({ id: 'filters.FullSearch' })
@@ -64,7 +114,7 @@ export const ReceiptsTable: React.FC = () => {
64114
const billingContext = billingContexts.length > 0 ? billingContexts[0] : null
65115
const currencyCode = get(billingContext, ['integration', 'currencyCode'], defaultCurrencyCode)
66116
const reportPeriod = get(billingContexts.find(({ lastReport }) => !!lastReport), ['lastReport', 'period'], null)
67-
const contextIdsKey = useMemo(() => billingContexts.map(({ id }) => id).sort().join(','), [billingContexts])
117+
const contextIdsKey = useMemo(() => billingContexts.map(({ id }) => id).sort((left, right) => left.localeCompare(right)).join(','), [billingContexts])
68118
const contextIds = useMemo(() => contextIdsKey ? contextIdsKey.split(',') : [], [contextIdsKey])
69119
const hasToPayDetails = get(billingContext, ['integration', 'dataFormat', 'hasToPayDetails'], false)
70120
const hasServices = get(billingContext, ['integration', 'dataFormat', 'hasServices'], false)
@@ -85,43 +135,15 @@ export const ReceiptsTable: React.FC = () => {
85135
const columnLabels = useTableTranslations()
86136
const initialTableState = useMemo(() => defaultParseUrlQuery(router.query, DEFAULT_PAGE_SIZE), [router.query])
87137
const updateUrlQuery = useCallback((params: FullTableState) => {
88-
const { startRow, filterState, sortState, rowSelectionState, globalFilter } = params
89-
90-
const nextFilters = { ...filterState }
91-
if (globalFilter && globalFilter.trim() !== '') {
92-
nextFilters.search = globalFilter
93-
} else {
94-
delete nextFilters.search
95-
}
96-
97-
const sort = sortState?.length
98-
? `${sortState[0].id}_${sortState[0].desc ? DESC : ASC}`
99-
: null
100-
101-
const nextQuery: Record<string, string | string[]> = { ...router.query } as Record<string, string | string[]>
102-
const nextOffset = startRow > 0 ? String(startRow) : undefined
103-
const nextFiltersValue = Object.keys(nextFilters).length > 0 ? JSON.stringify(nextFilters) : undefined
104-
const nextSortValue = sort ?? undefined
105-
const nextSelectedRows = rowSelectionState?.length > 0 ? JSON.stringify(rowSelectionState) : undefined
106-
107-
if (nextOffset) nextQuery.offset = nextOffset
108-
else delete nextQuery.offset
109-
110-
if (nextFiltersValue) nextQuery.filters = nextFiltersValue
111-
else delete nextQuery.filters
112-
113-
if (nextSortValue) nextQuery.sort = nextSortValue
114-
else delete nextQuery.sort
115-
116-
if (nextSelectedRows) nextQuery.selectedRows = nextSelectedRows
117-
else delete nextQuery.selectedRows
118-
138+
const nextQuery = buildNextTableQuery(router.query as Record<string, string | string[]>, params)
119139
if (isEqual(router.query, nextQuery)) return
120140

121-
void router.replace({
141+
router.replace({
122142
pathname: router.pathname,
123143
query: nextQuery,
124-
}, undefined, { shallow: true })
144+
}, undefined, { shallow: true }).catch((error) => {
145+
console.error('Failed to update billing receipts table query params', error)
146+
})
125147
}, [router])
126148

127149
const { updateStepIfNotCompleted } = useTourContext()
@@ -154,7 +176,7 @@ export const ReceiptsTable: React.FC = () => {
154176
}, [reportPeriod])
155177

156178
const onRowClick = useCallback((record: BillingReceiptType) => {
157-
const hasSelectedText = typeof window !== 'undefined' && window.getSelection?.()?.toString().trim()
179+
const hasSelectedText = typeof globalThis.window !== 'undefined' && globalThis.window.getSelection?.()?.toString().trim()
158180
if (hasSelectedText) return
159181

160182
if (hasServices) {
@@ -202,6 +224,7 @@ export const ReceiptsTable: React.FC = () => {
202224
rowCount,
203225
}
204226
} catch (error) {
227+
console.error('Failed to fetch billing receipts', error)
205228
setLoadingError(true)
206229
return {
207230
rowData: [],
@@ -273,7 +296,12 @@ export const ReceiptsTable: React.FC = () => {
273296
setSelectedRowIds(initialTableState.rowSelectionState)
274297

275298
const tablePeriod = get(nextTableRef.api.getFilterState(), 'period')
276-
const nextPeriod = tablePeriod ? dayjs(String(tablePeriod), 'YYYY-MM-DD') : (reportPeriod ? dayjs(reportPeriod, 'YYYY-MM-DD') : null)
299+
let nextPeriod: Dayjs | null = null
300+
if (tablePeriod) {
301+
nextPeriod = dayjs(String(tablePeriod), 'YYYY-MM-DD')
302+
} else if (reportPeriod) {
303+
nextPeriod = dayjs(reportPeriod, 'YYYY-MM-DD')
304+
}
277305
setPeriod(nextPeriod)
278306
}, [initialTableState.rowSelectionState, reportPeriod, setSearch])
279307

apps/condo/domains/billing/components/BillingPageContent/ServicesModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export const ServicesModal: React.FC<IServicesModalProps> = ({
138138
)
139139
}
140140

141-
if (!visible || !services || !services.length) return null
141+
if (!visible || !services?.length) return null
142142

143143
// TODO (savelevMatthew): Move modal to common width-expandable component?
144144
return (

apps/condo/domains/billing/hooks/useReceiptTableFilters.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@ import { BillingCategory } from '@condo/domains/billing/utils/clientSchema'
1010
import { ISearchInputProps } from '@condo/domains/common/components/GraphQlSearchInput'
1111
import { ComponentType, convertToOptions, FilterComponentSize, TableFiltersMeta } from '@condo/domains/common/utils/filters.utils'
1212
import { getAddressDetails, ObjectWithAddressInfo } from '@condo/domains/common/utils/helpers'
13-
import { categoryToSearchQuery, FilterType, getFilter, getStringContainsFilter, QueryArgType, WhereType } from '@condo/domains/common/utils/tables.utils'
13+
import { categoryToSearchQuery, getFilter, getStringContainsFilter, QueryArgType, WhereType } from '@condo/domains/common/utils/tables.utils'
1414

15-
const addressFilter: FilterType<BillingReceiptWhereInput> = (search: QueryArgType) => {
16-
if (!search) return undefined as unknown as BillingReceiptWhereInput
15+
const addressFilter = (search: QueryArgType) => {
16+
if (!search) return
1717

1818
const addressKeys = (Array.isArray(search) ? search : [search])
1919
.filter(Boolean)
2020
.map((value) => String(value).trim())
2121
.filter(Boolean)
2222

23-
if (addressKeys.length === 0) return undefined as unknown as BillingReceiptWhereInput
23+
if (addressKeys.length === 0) return
2424
if (addressKeys.length === 1) return { property: { addressKey: addressKeys[0] } }
2525

2626
return {
@@ -44,8 +44,9 @@ const searchBillingPropertyByContextIds = (contextIds: string[]): ISearchInputPr
4444
return async function (client, searchText, query = {}, first = 10, skip = 0) {
4545
if (!contextIds?.length) return []
4646

47+
const addressSearchFilter = isEmpty(searchText) ? {} : { address_contains_i: searchText }
4748
const where = {
48-
...!isEmpty(searchText) ? { address_contains_i: searchText } : {},
49+
...addressSearchFilter,
4950
...query,
5051
context: { id_in: contextIds },
5152
}

0 commit comments

Comments
 (0)