Skip to content

Commit

Permalink
feat(condo): DOMA-9988 add ux property gate before news item is creat…
Browse files Browse the repository at this point in the history
…ed (#5193)

* feat(condo): add ux property gate before news item is created

* fix(condo): remove console.log
  • Loading branch information
toplenboren authored Sep 11, 2024
1 parent ecb4aac commit f1001b3
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 26 deletions.
3 changes: 1 addition & 2 deletions apps/condo/domains/onboarding/contexts/TourContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const TourProvider = ({ children }) => {

const updateStepIfNotCompleted = useCallback(async (type: TourStepTypeType, nextRoute?: string) => {
if (organizationType !== MANAGING_COMPANY_TYPE) return

const fetchResult = await refetchSteps({
where: {
organization: { id: organizationId },
Expand Down Expand Up @@ -111,7 +111,6 @@ export const TourProvider = ({ children }) => {
switch (name) {
case 'createProperty': {
if (currentImport.current && isFirstSuccessImport.current) return

if (get(data, 'obj.map')) {
await updateStepIfNotCompleted(TourStepTypeType.CreateProperty)
await updateStepIfNotCompleted(TourStepTypeType.CreatePropertyMap)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export const useCompletedTourModals = ({ activeStep, setActiveTourStep, refetchS
const DownloadAppResidentFeatureMessage = intl.formatMessage({ id: 'tour.newFeatures.resident.downloadApp' })

const router = useRouter()

const { organization } = useOrganization()
const organizationId = useMemo(() => get(organization, 'id'), [organization])
const { logEvent } = useTracking()
Expand Down Expand Up @@ -288,6 +289,15 @@ export const useCompletedTourModals = ({ activeStep, setActiveTourStep, refetchS
const updateCompletedStepModalData = useCallback((type: TourStepTypeType | 'importProperties', nextRoute?: string) => {
if (activeStep !== TourStepTypeType.Resident && type === TourStepTypeType.CreateNews) return

const { query: { skipTourModal } } = router

if (skipTourModal) {
logEvent({ eventName: 'TourCompleteStepModalSkip', eventProperties: { activeStep } })
setActiveTourStep(null)
setCompletedStepModalData(null)
return
}

if (
activeStep !== TourStepTypeType.Resident && type === TourStepTypeType.ViewResidentsAppGuide ||
activeStep === TourStepTypeType.Resident && type === TourStepTypeType.CreateNews
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const BasePropertyForm: React.FC<IPropertyFormProps> = (props) => {
const PromptTitle = intl.formatMessage({ id: 'pages.condo.property.warning.modal.Title' })
const PromptHelpMessage = intl.formatMessage({ id: 'pages.condo.property.warning.modal.HelpMessage' })
const AddressValidationErrorMsg = intl.formatMessage({ id: 'pages.condo.property.warning.modal.AddressValidationErrorMsg' })
const OperationCompletedTitle = intl.formatMessage({ id: 'OperationCompleted' })

const { breakpoints } = useLayoutContext()
const { addressApi } = useAddressApi()
Expand Down Expand Up @@ -137,6 +138,12 @@ const BasePropertyForm: React.FC<IPropertyFormProps> = (props) => {
initialValues={initialValues}
validateTrigger={FORM_WITH_ACTION_VALIDATION_TRIGGERS}
formValuesToMutationDataPreprocessor={formValuesToMutationDataPreprocessor}
OnCompletedMsg={(property) => ({
message: <Typography.Text strong>{OperationCompletedTitle}</Typography.Text>,
description: <Typography.Text type='secondary'>
{intl.formatMessage({ id: 'pages.condo.property.form.SuccessNotification' }, { address: property.address })}
</Typography.Text>,
})}
{...formLayout}
>
{({ handleSave, isLoading, form }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import React from 'react'
import { useAuth } from '@open-condo/next/auth'
import { useIntl } from '@open-condo/next/intl'
import { useOrganization } from '@open-condo/next/organization'
import { Button, Tour } from '@open-condo/ui'
import { Button, Space, Tour } from '@open-condo/ui'

import { isSafeUrl } from '@condo/domains/common/utils/url.utils'
import BasePropertyForm from '@condo/domains/property/components/BasePropertyForm'
import { Property } from '@condo/domains/property/utils/clientSchema'

Expand All @@ -19,13 +20,22 @@ const FORM_DEPENDENCIES = ['address']
export const CreatePropertyForm: React.FC = () => {
const intl = useIntl()
const CreatePropertyMessage = intl.formatMessage({ id: 'pages.condo.property.index.CreatePropertyButtonLabel' })
const router = useRouter()
const { push, query: { next } } = useRouter()
const { organization, link } = useOrganization()
const { user } = useAuth()

const action = Property.useCreate({
organization: { connect: { id: organization.id } },
type: DEFAULT_PROPERTY_TYPE,
}, async (property) => { await router.push(`/property/${property.id}`) })
}, async (property) => {
let redirectUrl = `/property/${property.id}`

if (next && !Array.isArray(next) && isSafeUrl(next)) {
redirectUrl = next
}

await push(redirectUrl)
})

const initialValues = {
name: '',
Expand Down Expand Up @@ -55,16 +65,18 @@ export const CreatePropertyForm: React.FC = () => {
const { address } = getFieldsValue(['address'])

return (
<Button
key='submit'
onClick={handleSave}
type='primary'
loading={isLoading}
disabled={!canManageProperties || !address}
focus={count === 0 && currentStep === 1}
>
{CreatePropertyMessage}
</Button>
<Space size={24} direction='horizontal'>
<Button
key='submit'
onClick={handleSave}
type='primary'
loading={isLoading}
disabled={!canManageProperties || !address}
focus={count === 0 && currentStep === 1}
>
{CreatePropertyMessage}
</Button>
</Space>
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useOrganization } from '@open-condo/next/organization'

import { Button } from '@condo/domains/common/components/Button'
import { Loader } from '@condo/domains/common/components/Loader'
import { isSafeUrl } from '@condo/domains/common/utils/url.utils'
import { Property } from '@condo/domains/property/utils/clientSchema'

import BasePropertyForm from '../BasePropertyForm'
Expand All @@ -23,11 +24,19 @@ const FORM_DEPENDENCIES = ['address']
export const UpdatePropertyForm: React.FC<IUpdatePropertyForm> = ({ id }) => {
const intl = useIntl()
const ApplyChangesLabel = intl.formatMessage({ id: 'ApplyChanges' })
const { push } = useRouter()
const { push, query: { next } } = useRouter()
const { organization } = useOrganization()
const { refetch, obj: property, loading, error } = Property.useObject({ where: { id } })
const initialValues = Property.convertToFormState(property)
const action = Property.useUpdate({}, (property) => push(`/property/${property.id}`))
const action = Property.useUpdate({}, async (property) => {
let redirectUrl = `/property/${property.id}`

if (next && !Array.isArray(next) && isSafeUrl(next)) {
redirectUrl = next
}

await push(redirectUrl)
})
const updateAction = (value) => action(value, property)

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ interface IPropertyFormProps {
}

export const PropertyForm: React.FC<IPropertyFormProps> = ({ id }) => {
return (id ? <UpdatePropertyForm id={id}/> : <CreatePropertyForm/> )
return (id ? <UpdatePropertyForm id={id}/> : <CreatePropertyForm /> )
}
3 changes: 3 additions & 0 deletions apps/condo/lang/en/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@
"pages.condo.property.form.AreaSuffix": "sq. m.",
"pages.condo.property.form.YearPlaceholder": "2016",
"pages.condo.property.id.PageTitle": "Property",
"pages.condo.property.form.SuccessNotification": "Property {address} was added successfully",
"pages.condo.property.id.NotFound.PageTitle": "Property not found",
"pages.condo.property.id.NotFound.Message": "Property with this ID is not in your organization",
"pages.condo.property.id.Square": "Square",
Expand Down Expand Up @@ -1422,6 +1423,8 @@
"pages.condo.news.index.field.date.sending": "Sending",
"pages.condo.news.index.emptyList.header": "No news yet",
"pages.condo.news.index.emptyList.title": "Shall we add the first news right now?",
"pages.condo.news.index.propertyGate.header": "To create news you should add your properties",
"pages.condo.news.index.propertyGate.title": "Shall we add the first property now?",
"pages.condo.news.settings.pageTitle": "Settings",
"pages.condo.news.settings.sharingAppSettingsTitle": "Select sharing apps",
"pages.condo.news.settings.appCard.description": "Send your news to {sharingAppName}",
Expand Down
3 changes: 3 additions & 0 deletions apps/condo/lang/ru/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@
"pages.condo.property.form.AreaSuffix": "кв. м.",
"pages.condo.property.form.YearPlaceholder": "2016",
"pages.condo.property.id.PageTitle": "Объект",
"pages.condo.property.form.SuccessNotification": "Дом по адресу {address} был успешно добавлен",
"pages.condo.property.id.NotFound.PageTitle": "Дом не найден",
"pages.condo.property.id.NotFound.Message": "Дома с данным ID нет в вашей организации",
"pages.condo.property.id.Square": "Площадь",
Expand Down Expand Up @@ -1422,6 +1423,8 @@
"pages.condo.news.index.field.date.sending": "Отправляется",
"pages.condo.news.index.emptyList.header": "Пока новостей нет",
"pages.condo.news.index.emptyList.title": "Добавим первую новость прямо сейчас?",
"pages.condo.news.index.propertyGate.header": "Чтобы отправить новость нужно добавить хотя бы один дом",
"pages.condo.news.index.propertyGate.title": "Добавим первый дом сейчас?",
"pages.condo.news.settings.pageTitle": "Настройки",
"pages.condo.news.settings.sharingAppSettingsTitle": "Выберите каналы отправки",
"pages.condo.news.settings.appCard.description": "Отправка новостей в {sharingAppName}",
Expand Down
50 changes: 46 additions & 4 deletions apps/condo/pages/news/create.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
import get from 'lodash/get'
import Head from 'next/head'
import React from 'react'

import { useIntl } from '@open-condo/next/intl'
import { useOrganization } from '@open-condo/next/organization'
import { Typography } from '@open-condo/ui'

import { AccessDeniedPage } from '@condo/domains/common/components/containers/AccessDeniedPage'
import { PageHeader, PageWrapper, PageContent } from '@condo/domains/common/components/containers/BaseLayout'
import LoadingOrErrorPage from '@condo/domains/common/components/containers/LoadingOrErrorPage'
import { EmptyListContent } from '@condo/domains/common/components/EmptyListContent'
import { NewsForm } from '@condo/domains/news/components/NewsForm'
import { NewsReadAndManagePermissionRequired } from '@condo/domains/news/components/PageAccess'
import { useNewsItemsAccess } from '@condo/domains/news/hooks/useNewsItemsAccess'
import { Property } from '@condo/domains/property/utils/clientSchema'

export interface ICreateNewsPage extends React.FC {
headerAction?: JSX.Element
requiredAccess?: React.FC
}

const CreateNewsPageContent: React.FC = () => {
interface ICreateNewsPageContentProps {
propertiesCount?: number
canManage?: boolean
}

const CreateNewsPageContent: React.FC<ICreateNewsPageContentProps> = ({ propertiesCount, canManage }) => {
const intl = useIntl()
const PageTitle = intl.formatMessage({ id: 'news.create.title' })
const PropertyGateLabel = intl.formatMessage({ id: 'pages.condo.news.index.propertyGate.header' })
const PropertyGateMessage = intl.formatMessage({ id: 'pages.condo.news.index.propertyGate.title' })
const PropertyGateButtonLabel = intl.formatMessage({ id: 'pages.condo.property.index.CreatePropertyButtonLabel' })

return (
<>
Expand All @@ -28,7 +40,18 @@ const CreateNewsPageContent: React.FC = () => {
<PageWrapper>
<PageHeader title={<Typography.Title>{PageTitle}</Typography.Title>} spaced/>
<PageContent>
<NewsForm actionName='create'/>
{ propertiesCount !== 0 ?
<NewsForm actionName='create'/>
:
<EmptyListContent
image='/dino/[email protected]'
label={PropertyGateLabel}
message={PropertyGateMessage}
createRoute='/property/create?next=/news/create&skipTourModal=true'
createLabel={PropertyGateButtonLabel}
accessCheck={canManage}
/>
}
</PageContent>
</PageWrapper>
</>
Expand All @@ -38,15 +61,34 @@ const CreateNewsPageContent: React.FC = () => {
const CreateNewsPage: ICreateNewsPage = () => {
const { canManage, isLoading: isAccessLoading } = useNewsItemsAccess()

const intl = useIntl()
const ServerErrorMsg = intl.formatMessage({ id: 'ServerError' })

const { organization } = useOrganization()

const {
count: propertiesCount,
loading: propertiesLoading,
error: propertiesError,
} = Property.useCount({ where: { organization: { id: get(organization, 'id') } }, first: 1 })

const loading = isAccessLoading || propertiesLoading
const error = propertiesError

if (loading || error) {
const errorToPrint = error ? ServerErrorMsg : null
return <LoadingOrErrorPage loading={loading} error={errorToPrint}/>
}

if (isAccessLoading) {
return <LoadingOrErrorPage error='' loading={true}/>
}

if (!canManage) {
return <AccessDeniedPage/>
}

return <CreateNewsPageContent />
return <CreateNewsPageContent propertiesCount={propertiesCount} canManage={canManage} />
}

CreateNewsPage.requiredAccess = NewsReadAndManagePermissionRequired
Expand Down
31 changes: 29 additions & 2 deletions apps/condo/pages/news/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { useNewsItemsAccess } from '@condo/domains/news/hooks/useNewsItemsAccess
import { useTableColumns } from '@condo/domains/news/hooks/useTableColumns'
import { useTableFilters } from '@condo/domains/news/hooks/useTableFilters'
import { NewsItem } from '@condo/domains/news/utils/clientSchema'
import { Property } from '@condo/domains/property/utils/clientSchema'
import { IFilters } from '@condo/domains/ticket/utils/helpers'


Expand Down Expand Up @@ -127,6 +128,9 @@ const NewsPageContent = ({
const SearchPlaceholder = intl.formatMessage({ id: 'filters.FullSearch' })
const EmptyListLabel = intl.formatMessage({ id: 'pages.condo.news.index.emptyList.header' })
const EmptyListMessage = intl.formatMessage({ id: 'pages.condo.news.index.emptyList.title' })
const PropertyGateLabel = intl.formatMessage({ id: 'pages.condo.news.index.propertyGate.header' })
const PropertyGateMessage = intl.formatMessage({ id: 'pages.condo.news.index.propertyGate.title' })
const PropertyGateButtonLabel = intl.formatMessage({ id: 'pages.condo.property.index.CreatePropertyButtonLabel' })
const CreateNews = intl.formatMessage({ id: 'news.createNews' })
const ServerErrorMsg = intl.formatMessage({ id: 'ServerError' })

Expand All @@ -143,18 +147,41 @@ const NewsPageContent = ({
[baseNewsQuery, filters, filtersToWhere])
const { canManage } = useNewsItemsAccess()

const { organization } = useOrganization()

const {
count: propertiesCount,
loading: propertiesLoading,
error: propertiesError,
} = Property.useCount({ where: { organization: { id: get(organization, 'id') } }, first: 1 })

const {
count: newsWithoutFiltersCount,
loading: newsWithoutFiltersCountLoading,
error,
error: newsError,
} = NewsItem.useCount({ where: baseNewsQuery })
const loading = newsWithoutFiltersCountLoading

const loading = newsWithoutFiltersCountLoading || propertiesLoading
const error = newsError || propertiesError

if (loading || error) {
const errorToPrint = error ? ServerErrorMsg : null
return <LoadingOrErrorPage loading={loading} error={errorToPrint}/>
}

if (propertiesCount === 0 && newsWithoutFiltersCount === 0) {
return (
<EmptyListContent
image='/dino/[email protected]'
label={PropertyGateLabel}
message={PropertyGateMessage}
createRoute='/property/create?next=/news&skipTourModal=true'
createLabel={PropertyGateButtonLabel}
accessCheck={canManage}
/>
)
}

if (newsWithoutFiltersCount === 0) {
return (
<EmptyListContent
Expand Down
2 changes: 2 additions & 0 deletions apps/condo/pages/property/[id]/update.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React from 'react'
import { useIntl } from '@open-condo/next/intl'

import { PageContent, PageWrapper } from '@condo/domains/common/components/containers/BaseLayout'
import { isSafeUrl } from '@condo/domains/common/utils/url.utils'
import { OrganizationRequired } from '@condo/domains/organization/components/OrganizationRequired'
import { PropertyForm } from '@condo/domains/property/components/PropertyForm'

Expand All @@ -20,6 +21,7 @@ const UpdatePropertyPage: IUpdatePropertyPage = () => {
const intl = useIntl()
const PageTitleMsg = intl.formatMessage({ id:'pages.condo.property.index.UpdatePropertyTitle' })
const { query: { id } } = useRouter()

return (
<>
<Head>
Expand Down
4 changes: 2 additions & 2 deletions apps/condo/pages/property/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const PROPERTY_CREATE_PAGE_TITLE_STYLE: React.CSSProperties = { margin: 0 }
export default function CreatePropertyPage () {
const intl = useIntl()
const PageTitleMsg = intl.formatMessage({ id: 'pages.condo.property.index.CreatePropertyTitle' })

return (
<>
<Head>
Expand All @@ -30,7 +31,7 @@ export default function CreatePropertyPage () {
</Col>
<Col span={24}>
<Tour.Provider>
<PropertyForm />
<PropertyForm/>
</Tour.Provider>
</Col>
</Row>
Expand All @@ -41,4 +42,3 @@ export default function CreatePropertyPage () {
}

CreatePropertyPage.requiredAccess = OrganizationRequired

0 comments on commit f1001b3

Please sign in to comment.