Skip to content

Commit

Permalink
feat(condo): DOMA-8321 updated form when sending news if one property (
Browse files Browse the repository at this point in the history
…#4341)

* feat(condo): DOMA-8321 updated form when sending news if one property

* refactor(condo): DOMA-8321 refactored after review

* fix(condo): DOMA-8321 simplify news k6 test

* fix(condo): DOMA-8403 fixed validation of property field

---------

Co-authored-by: Sitnikov Ivan <[email protected]>
  • Loading branch information
Alllex202 and sitozzz authored Feb 9, 2024
1 parent 39b318a commit 91049e2
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 45 deletions.
71 changes: 59 additions & 12 deletions apps/condo/domains/news/components/NewsForm/BaseNewsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Property as IProperty,
QueryAllNewsItemsArgs as IQueryAllNewsItemsArgs,
} from '@app/condo/schema'
import styled from '@emotion/styled'
import { Col, Form, FormInstance, notification, Row } from 'antd'
import { Gutter } from 'antd/es/grid/row'
import { ArgsProps } from 'antd/lib/notification'
Expand All @@ -20,6 +21,7 @@ import flattenDeep from 'lodash/flattenDeep'
import get from 'lodash/get'
import has from 'lodash/has'
import includes from 'lodash/includes'
import isArray from 'lodash/isArray'
import isEmpty from 'lodash/isEmpty'
import isFunction from 'lodash/isFunction'
import isNull from 'lodash/isNull'
Expand All @@ -37,6 +39,7 @@ import { colors } from '@open-condo/ui/dist/colors'

import Input from '@condo/domains/common/components/antd/Input'
import { FormWithAction } from '@condo/domains/common/components/containers/FormList'
import { GraphQlSearchInput } from '@condo/domains/common/components/GraphQlSearchInput'
import {
GraphQlSearchInputWithCheckAll,
InputWithCheckAllProps,
Expand All @@ -60,6 +63,7 @@ import { searchOrganizationProperty } from '@condo/domains/ticket/utils/clientSc
import { SectionNameInput } from '@condo/domains/user/components/SectionNameInput'
import { UnitNameInput, UnitNameInputOption } from '@condo/domains/user/components/UnitNameInput'


type FormWithActionChildrenProps = ComponentProps<ComponentProps<typeof FormWithAction>['children']>

type ActionBarProps = Pick<FormWithActionChildrenProps, 'handleSave' | 'isLoading' | 'form'>
Expand Down Expand Up @@ -87,8 +91,13 @@ export type BaseNewsFormProps = {
OnCompletedMsg: (INewsItem) => ArgsProps | null,
allNews: INewsItem[],
actionName: ActionNameProps,
totalProperties: number
}

const HiddenBlock = styled.div<{ hide?: boolean }>`
${({ hide }) => hide ? 'display: none;' : ''}
`

//TODO(DOMA-6846) wrap form label with 0 margin and use default spacing (details in 6613 pr)
const NO_RESIZE_STYLE: React.CSSProperties = { resize: 'none' }
const FLEX_START_STYLE: React.CSSProperties = { alignItems: 'flex-start' }
Expand Down Expand Up @@ -284,6 +293,7 @@ export const BaseNewsForm: React.FC<BaseNewsFormProps> = ({
OnCompletedMsg,
allNews,
actionName,
totalProperties,
}) => {
const intl = useIntl()
const TypeLabel = intl.formatMessage({ id: 'news.fields.type.label' })
Expand Down Expand Up @@ -524,7 +534,7 @@ export const BaseNewsForm: React.FC<BaseNewsFormProps> = ({
const propertyCheckboxChange = (form) => {
return (value) => {
if (value) setSelectedPropertiesId(selectedPropertiesId => {
if (countPropertiesAvaliableToSelect.current === 1 && selectedPropertiesId.length === 1)
if (countPropertiesAvaliableToSelect.current === 1 && selectedPropertiesId.length === 1)
return selectedPropertiesId
if (countPropertiesAvaliableToSelect.current === 1 && selectedPropertiesId.length === 0 && has(onlyPropertyThatCanBeSelected, 'current.value')) {
return [onlyPropertyThatCanBeSelected.current.value]
Expand All @@ -551,7 +561,7 @@ export const BaseNewsForm: React.FC<BaseNewsFormProps> = ({
required: true,
placeholder: SelectAddressPlaceholder,
onChange: (propIds: string[]) => {
setSelectedPropertiesId(propIds)
setSelectedPropertiesId(!isArray(propIds) ? [propIds].filter(Boolean) : propIds)
form.setFieldsValue({ 'unitNames': [] })
form.setFieldsValue({ 'sectionIds': [] })
setSelectedUnitNameKeys([])
Expand Down Expand Up @@ -594,6 +604,7 @@ export const BaseNewsForm: React.FC<BaseNewsFormProps> = ({
title: selectedTitle,
body: selectedBody,
properties: selectedPropertiesId,
...(totalProperties === 1 && selectedPropertiesId.length === 1 ? { property: selectedPropertiesId[0] } : undefined),
validBefore: initialValidBefore ? dayjs(initialValidBefore) : null,
sendAt: initialSendAt ? dayjs(initialSendAt) : null,
}
Expand Down Expand Up @@ -848,6 +859,26 @@ export const BaseNewsForm: React.FC<BaseNewsFormProps> = ({
},
}), [ProfanityInBody, ProfanityInTitle])

const newsItemForOneProperty = totalProperties === 1 && initialPropertyIds.length < 2
const propertyIsAutoFilled = useRef(false)
const handleAllPropertiesLoading = useCallback((form: FormInstance) => (data) => {
if (!isEmpty(initialValues)) return
if (!newsItemForOneProperty) return
if (data.length !== 1) return
if (propertyIsAutoFilled.current) return

propertyIsAutoFilled.current = true
const propertyId = get(data, '0.value')
if (propertyId) {
setSelectedPropertiesId([propertyId])
form.setFieldsValue({
property: propertyId,
'properties': [propertyId],
hasAllProperties: true,
})
}
}, [initialValues, newsItemForOneProperty])

return (
<Row gutter={BIG_HORIZONTAL_GUTTER}>
<Col span={24} flex='auto'>
Expand Down Expand Up @@ -1034,16 +1065,32 @@ export const BaseNewsForm: React.FC<BaseNewsFormProps> = ({
<Typography.Title level={2}>{SelectAddressLabel}</Typography.Title>
</Col>
<Col span={24} data-cy='news__create-property-search'>
<GraphQlSearchInputWithCheckAll
checkAllFieldName='hasAllProperties'
checkAllInitialValue={get(initialValues, 'hasAllProperties', false)}
selectFormItemProps={propertySelectFormItemProps}
selectProps={propertySelectProps(form)}
onCheckBoxChange={propertyCheckboxChange(form)}
CheckAllMessage={CheckAllLabel}
onDataLoaded={handleAllPropertiesDataLoading}
form={form}
/>
{
newsItemForOneProperty && (
<Form.Item
{...propertySelectFormItemProps}
name='property'
rules={[requiredValidator]}
>
<GraphQlSearchInput
{...propertySelectProps(form)}
onAllDataLoading={handleAllPropertiesLoading(form)}
/>
</Form.Item>
)
}
<HiddenBlock hide={newsItemForOneProperty}>
<GraphQlSearchInputWithCheckAll
checkAllFieldName='hasAllProperties'
checkAllInitialValue={get(initialValues, 'hasAllProperties', false)}
selectFormItemProps={propertySelectFormItemProps}
selectProps={propertySelectProps(form)}
onCheckBoxChange={propertyCheckboxChange(form)}
CheckAllMessage={CheckAllLabel}
onDataLoaded={handleAllPropertiesDataLoading}
form={form}
/>
</HiddenBlock>
</Col>
{
isOnlyOnePropertySelected && (
Expand Down
14 changes: 12 additions & 2 deletions apps/condo/domains/news/components/NewsForm/CreateNewsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ActionBar, Button, Typography } from '@open-condo/ui'

import LoadingOrErrorPage from '@condo/domains/common/components/containers/LoadingOrErrorPage'
import { NewsItem, NewsItemTemplate } from '@condo/domains/news/utils/clientSchema'
import { Property } from '@condo/domains/property/utils/clientSchema'

import { BaseNewsForm, BaseNewsFormProps } from './BaseNewsForm'

Expand Down Expand Up @@ -138,6 +139,14 @@ export const CreateNewsForm: React.FC = () => {
},
})

const {
loading: totalPropertiesLoading,
count: totalProperties,
error: totalPropertiesError,
} = Property.useCount({
where: { organization: { id: organizationId } },
})

const dateStart = dayjs().startOf('day')
const {
loading: isNewsFetching,
Expand Down Expand Up @@ -173,8 +182,8 @@ export const CreateNewsForm: React.FC = () => {
)
}, [intl, softDeleteNewsItem])

const error = useMemo(() => newsItemTemplatesError || allNewsError, [allNewsError, newsItemTemplatesError])
const loading = isNewsFetching || isNewsItemTemplatesFetching
const error = useMemo(() => newsItemTemplatesError || allNewsError || totalPropertiesError, [allNewsError, newsItemTemplatesError, totalPropertiesError])
const loading = isNewsFetching || isNewsItemTemplatesFetching || totalPropertiesLoading

if (loading || error) {
return (
Expand All @@ -194,6 +203,7 @@ export const CreateNewsForm: React.FC = () => {
OnCompletedMsg={OnCompletedMsg}
allNews={allNews}
actionName='create'
totalProperties={totalProperties}
/>
)
}
55 changes: 32 additions & 23 deletions apps/condo/domains/news/components/NewsForm/ResendNewsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ export const ResendNewsForm: React.FC<IResendNewsForm> = ({ id }) => {
}, [createNewsItem])

const {
loading: newsItemLoading,
obj: newsItem,
error: newsItemError,
} = NewsItem.useObject({
where: { id },
loading: totalPropertiesLoading,
count: totalProperties,
error: totalPropertiesError,
} = Property.useCount({
where: { organization: { id: organizationId } },
})

const {
Expand All @@ -51,6 +51,14 @@ export const ResendNewsForm: React.FC<IResendNewsForm> = ({ id }) => {
},
})

const {
loading: newsItemLoading,
obj: newsItem,
error: newsItemError,
} = NewsItem.useObject({
where: { id },
})

const selectedPropertiesId = useMemo(() => {
return uniq(newsItemScopes.filter(item => has(item, ['property', 'id'])).map(item => item.property.id))
}, [newsItemScopes])
Expand All @@ -61,11 +69,11 @@ export const ResendNewsForm: React.FC<IResendNewsForm> = ({ id }) => {
const sendPeriod: SendPeriodType = useMemo(() => {
return get(newsItem, 'sendAt', null) ? 'later' : 'now'
}, [newsItem])
const sendAt = useMemo(() => get(newsItem, 'sendAt', null), [newsItem])
const validBefore = useMemo(() => get(newsItem, 'validBefore', null), [newsItem])
const hasAllProperties = useMemo(() => {
return newsItemScopes.filter((scope) => scope.property === null && scope.unitType === null && scope.unitName === null).length > 0
}, [newsItemScopes])
const sendAt = useMemo(() => get(newsItem, 'sendAt', null), [newsItem])
const validBefore = useMemo(() => get(newsItem, 'validBefore', null), [newsItem])
const initialValues = useMemo(() => ({
...newsItem,
newsItemScopes: newsItemScopes,
Expand All @@ -76,6 +84,18 @@ export const ResendNewsForm: React.FC<IResendNewsForm> = ({ id }) => {
validBefore: validBefore ? validBefore : null,
}), [hasAllProperties, newsItem, newsItemScopes, properties, sendAt, sendPeriod, validBefore])

const dateStart = dayjs().startOf('day')
const {
loading: isNewsFetching,
objs: allNews,
error: allNewsError,
} = NewsItem.useAllObjects({
where: {
organization: { id: organizationId },
createdAt_gte: dateStart.toISOString(),
},
})

const {
loading: isNewsItemTemplatesFetching,
objs: newsItemTemplates,
Expand All @@ -89,18 +109,6 @@ export const ResendNewsForm: React.FC<IResendNewsForm> = ({ id }) => {
},
})

const dateStart = dayjs().startOf('day')
const {
loading: isNewsFetching,
objs: allNews,
error: allNewsError,
} = NewsItem.useAllObjects({
where: {
organization: { id: organizationId },
createdAt_gte: dateStart.toISOString(),
},
})

const templates = isNewsItemTemplatesFetching ? null : newsItemTemplates
.reduce((acc, template) => {
acc[template.id] = {
Expand All @@ -117,11 +125,11 @@ export const ResendNewsForm: React.FC<IResendNewsForm> = ({ id }) => {
}, [intl, softDeleteNewsItem])

const error = useMemo(
() => newsItemError || newsItemScopeError || newsItemTemplatesError || allNewsError,
[allNewsError, newsItemError, newsItemScopeError, newsItemTemplatesError])
() => newsItemError || newsItemScopeError || newsItemTemplatesError || allNewsError || totalPropertiesError,
[allNewsError, newsItemError, newsItemScopeError, newsItemTemplatesError, totalPropertiesError])
const loading = useMemo(
() => propertiesLoading || newsItemLoading || !newsItemScopeAllDataLoaded || isNewsFetching || isNewsItemTemplatesFetching,
[isNewsFetching, isNewsItemTemplatesFetching, newsItemLoading, newsItemScopeAllDataLoaded, propertiesLoading])
() => propertiesLoading || newsItemLoading || !newsItemScopeAllDataLoaded || isNewsFetching || isNewsItemTemplatesFetching || totalPropertiesLoading,
[isNewsFetching, isNewsItemTemplatesFetching, newsItemLoading, newsItemScopeAllDataLoaded, propertiesLoading, totalPropertiesLoading])

if (loading || error) {
return (
Expand All @@ -143,6 +151,7 @@ export const ResendNewsForm: React.FC<IResendNewsForm> = ({ id }) => {
OnCompletedMsg={OnCompletedMsg}
allNews={allNews}
actionName='create'
totalProperties={totalProperties}
/>
)
}
17 changes: 13 additions & 4 deletions apps/condo/domains/news/components/NewsForm/UpdateNewsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ export const UpdateNewsForm: React.FC<IUpdateNewsForm> = ({ id }) => {

const organizationId = useMemo(() => get(newsItem, 'organization.id', null), [newsItem])

const {
loading: totalPropertiesLoading,
count: totalProperties,
error: totalPropertiesError,
} = Property.useCount({
where: { organization: { id: organizationId } },
})

const {
loading: isNewsItemTemplatesFetching,
objs: NewsItemTemplates,
Expand Down Expand Up @@ -138,11 +146,11 @@ export const UpdateNewsForm: React.FC<IUpdateNewsForm> = ({ id }) => {
}, { emptyTemplate: { title: EmptyTemplateTitle, body: '', type: null } })

const error = useMemo(
() => newsItemError || newsItemScopeError || allNewsError || newsItemTemplatesError,
[allNewsError, newsItemError, newsItemScopeError, newsItemTemplatesError])
() => newsItemError || newsItemScopeError || allNewsError || newsItemTemplatesError || totalPropertiesError,
[allNewsError, newsItemError, newsItemScopeError, newsItemTemplatesError, totalPropertiesError])
const loading = useMemo(
() => propertiesLoading || newsItemLoading || !newsItemScopeAllDataLoaded || isNewsFetching || isNewsItemTemplatesFetching,
[isNewsFetching, isNewsItemTemplatesFetching, newsItemLoading, newsItemScopeAllDataLoaded, propertiesLoading])
() => propertiesLoading || newsItemLoading || !newsItemScopeAllDataLoaded || isNewsFetching || isNewsItemTemplatesFetching || totalPropertiesLoading,
[isNewsFetching, isNewsItemTemplatesFetching, newsItemLoading, newsItemScopeAllDataLoaded, propertiesLoading, totalPropertiesLoading])

if (loading || error) {
return (
Expand All @@ -165,6 +173,7 @@ export const UpdateNewsForm: React.FC<IUpdateNewsForm> = ({ id }) => {
OnCompletedMsg={null}
allNews={allNews}
actionName='update'
totalProperties={totalProperties}
/>
)
}
7 changes: 3 additions & 4 deletions apps/condo/k6/src/news.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,17 @@ export async function createNewsViaBrowser (data) {
page.locator('[data-cy="news__create-title-input"] textarea').type('Some title here')
page.locator('[data-cy="news__create-body-input"] textarea').type('Some long description here')

await page.locator('[data-cy="news__create-property-search"] .ant-select').click()
page.waitForSelector('[data-cy="search-input--option"]').isVisible()
await page.locator('[data-cy="search-input--option"]').click()
page.waitForSelector('[data-cy="news__create-property-section-search"] .ant-select-selector').isVisible()
await page.locator('[data-cy="news__create-property-section-search"] .ant-select-selector').click()
page.keyboard.down('Enter')

for (let i = 0; i < 7; i++) {
for (let i = 0; i < 3; i++) {
page.keyboard.down('ArrowDown')
page.keyboard.down('Enter')
}

page.waitForSelector('button.condo-btn.condo-btn-primary').isVisible()

await page.locator('button.condo-btn.condo-btn-primary').click()

await page.waitForNavigation()
Expand Down

0 comments on commit 91049e2

Please sign in to comment.