From 656c94e64897ede7ef25f3dfaa660892aea9027a Mon Sep 17 00:00:00 2001 From: Pavel <52532264+nomerdvadcatpyat@users.noreply.github.com> Date: Wed, 27 Mar 2024 18:52:51 +0500 Subject: [PATCH] feat(condo): DOMA-8414 tour page (#4462) * feat(condo): DOMA-8414 added tour icon to side bar * feat(condo): DOMA-8414 added basic tour page * feat(condo): DOMA-8414 added basic ticket flow * feat(condo): DOMA-8414 added tour flow for ticket and meter * feat(condo): DOMA-8414 added billing step * feat(condo): DOMA-8414 tour mobile screen * feat(condo): DOMA-8414 added sync steps mutation * feat(condo): DOMA-8414 sync organization steps * feat(condo): DOMA-8414 disabled step tooltips * fix(condo): DOMA-8414 open complete modal when createNews step completed * feat(condo): DOMA-8414 added modals in technic app card * feat(condo): DOMA-8414 added accesses and tests for SyncTourSteps mutation * fix(condo): DOMA-8414 remove second step from active step from storage * feat(condo): DOMA-8414 refactor code * fix(condo): DOMA-8414 added useCompletedTourStepsData hook * fix(condo): DOMA-8414 removed hook to useCompletedTourModals and returns modals from it * fix(condo): DOMA-8414 added translations * fix(condo): DOMA-8414 refactor useCompletedTourModals modals data getters * fix(condo): DOMA-8414 added translations * feat(condo): DOMA-8414 update SyncTourStepsService tests * fix(condo): DOMA-8414 fix semgrep issues * feat(condo): DOMA-8618 added analytics to tour events * feat(condo): DOMA-8414 disable all iner todo steps instead first todo step * feat(condo): DOMA-8414 added videos to tour page and moved links to env * fix(condo): DOMA-8414 fixes after review * feat(condo): DOMA-8626 new property form * feat(condo): DOMA-8414 added video to map creation form * feat(condo): DOMA-8312 added tour step to ticket and property form * feat(condo): DOMA-8312 added hints on property map create * feat(condo): DOMA-8414 update redirects after organization created * feat(condo): DOMA-8414 redirect to tour after create organization * feat(condo): DOMA-8414 added no address modal * feat(condo): DOMA-8414 fixes after review * chore(condo): DOMA-8414 recreate migration * fix(condo): DOMA-8414 update tour video env * feat(condo): DOMA-8414 added notFound content for property address search select and unit select * chore(condo): DOMA-8414 recreate migration * feat(condo): DOMA-8414 add README.md * feat(condo): DOMA-8414 rename control room to tickets in side bar * chore(condo): DOMA-8414 recreate migration * feat(condo): DOMA-8644 added pics for technic card * fix(condo): DOMA-8414 remove size value 32 from space props * fix(condo): DOMA-8414 fix initial notFoundContent in AddressSuggestionsSearchInput * fix(condo): DOMA-8414 fix link with icon spacing * fix(condo): DOMA-8669 update base search input styles * fix(condo): DOMA-8414 fixed technic app card images * fix(condo): DOMA-8414 fix ticket empty list view * fix(condo): DOMA-8414 fix translations * fix(condo): DOMA-8414 fix redirect routes * fix(condo): DOMA-8414 fix tooltip and focus --- .helm | 2 +- .../BillingPageContent/ReceiptsTable.tsx | 15 +- .../components/BaseSearchInput/index.tsx | 36 +- .../domains/common/components/CardVideo.tsx | 47 ++ .../Form/FormItemTooltipWrapper.tsx | 13 + .../common/components/Import/Index.tsx | 19 +- .../common/components/LinkWithIcon.tsx | 49 ++ apps/condo/domains/common/constants/emoji.js | 3 + .../common/constants/menuCategories.js | 3 + .../BaseMeterModal/BaseMeterModalForm.tsx | 4 +- .../CreateMeterReadingsActionBar.tsx | 31 +- .../components/CreateMeterReadingsForm.tsx | 45 +- .../meter/hooks/useCreateMeterModal.tsx | 7 +- .../meter/hooks/useMeterTableColumns.tsx | 50 ++- .../domains/meter/utils/clientSchema/Meter.ts | 2 + apps/condo/domains/onboarding/README.md | 28 ++ .../onboarding/access/SyncTourStepsService.js | 22 + .../domains/onboarding/components/.gitkeep | 0 .../components/OnBoardingContext.tsx | 11 +- .../components/TourPage/AppCards.tsx | 207 +++++++++ .../components/TourPage/TourStepCard.tsx | 142 ++++++ .../domains/onboarding/constants/errors.js | 12 + .../domains/onboarding/constants/steps.js | 55 ++- .../onboarding/contexts/TourContext.tsx | 216 +++++++++ apps/condo/domains/onboarding/gql.js | 7 + .../TourContext/useCompletedTourModals.tsx | 423 ++++++++++++++++++ .../hooks/TourContext/useSyncSteps.tsx | 36 ++ .../hooks/TourPage/useTourPageData.tsx | 48 ++ .../onboarding/schema/SyncTourStepsService.js | 100 +++++ .../schema/SyncTourStepsService.test.js | 149 ++++++ .../domains/onboarding/schema/TourStep.js | 1 + .../onboarding/schema/TourStep.test.js | 20 +- apps/condo/domains/onboarding/schema/index.js | 2 + .../utils/clientSchema/constants.ts | 87 ++++ .../onboarding/utils/serverSchema/index.js | 16 + .../onboarding/utils/testSchema/index.js | 16 + .../components/OrganizationRequired.tsx | 22 +- .../components/OrganizationSelect.tsx | 16 +- .../organization/integrations/sbbol/routes.js | 9 + .../schema/RegisterNewOrganizationService.js | 8 +- .../property/PropertyFormItemTooltip.tsx | 30 ++ .../AddressSuggestionsSearchInput.tsx | 118 ++++- .../components/BasePropertyForm/index.tsx | 163 ++++--- .../components/PropertyAddressSearchInput.tsx | 35 +- .../PropertyForm/CreatePropertyForm.tsx | 23 +- .../components/PropertyForm/index.tsx | 2 +- .../domains/property/components/UnitInfo.tsx | 42 +- .../panels/Builder/BuildingPanelCommon.tsx | 31 +- .../panels/Builder/BuildingPanelEdit.tsx | 37 +- .../BaseTicketForm/TicketAssignments.tsx | 21 +- .../BaseTicketForm/TicketDeadlineField.tsx | 41 +- .../BaseTicketForm/TicketSubmitButton.tsx | 2 + .../components/BaseTicketForm/index.tsx | 41 +- .../TicketForm/CreateTicketForm.tsx | 85 ++-- .../domains/user/components/UnitNameInput.tsx | 18 +- .../user/integration/appleid/utils/helper.js | 7 + .../domains/user/integration/sberid/routes.js | 7 + apps/condo/lang/en/en.json | 263 ++++++++++- apps/condo/lang/ru/ru.json | 265 ++++++++++- ...20240318173552-0376_alter_tourstep_type.js | 68 +++ apps/condo/next.config.js | 8 + apps/condo/pages/_app.tsx | 68 +-- apps/condo/pages/auth/register.tsx | 19 +- apps/condo/pages/index.tsx | 11 +- apps/condo/pages/meter/create.tsx | 12 +- apps/condo/pages/property/[id]/map/update.tsx | 6 +- apps/condo/pages/property/create.tsx | 5 +- apps/condo/pages/ticket/index.tsx | 106 +++-- apps/condo/pages/tour/index.tsx | 279 ++++++++++++ .../onboarding/technic-app-card/admin.webp | Bin 0 -> 161834 bytes .../qr-technic-app/AppGalery.svg | 9 + .../qr-technic-app/AppStore.svg | 9 + .../qr-technic-app/GooglePlay.svg | 9 + .../onboarding/technic-app-card/security.webp | Bin 0 -> 205796 bytes .../onboarding/technic-app-card/technic.webp | Bin 0 -> 121616 bytes .../public/onboarding/tourResidentCard.webp | Bin 0 -> 27704 bytes .../public/onboarding/tourTechnicCard.webp | Bin 0 -> 35598 bytes apps/condo/schema.graphql | 14 +- apps/condo/schema.ts | 20 +- packages/next/_useEmitterMutation.ts | 4 +- packages/ui/src/components/Button/button.tsx | 4 +- packages/ui/src/components/Button/style.less | 40 +- .../ui/src/components/Card/_utils/index.tsx | 20 +- .../src/components/Card/button/cardButton.tsx | 30 +- .../components/Card/checkbox/cardCheckbox.tsx | 5 +- packages/ui/src/components/Input/input.tsx | 23 +- packages/ui/src/components/Input/style.less | 21 + packages/ui/src/components/Modal/modal.tsx | 2 +- .../ProgressIndicator/progressIndicator.tsx | 11 +- .../ui/src/components/Tooltip/tooltip.tsx | 4 +- packages/ui/src/components/Tour/tourStep.tsx | 28 +- .../ui/src/components/_utils/analytics.ts | 5 +- packages/ui/src/stories/Button.stories.tsx | 2 + .../ui/src/stories/Input/Input.stories.tsx | 1 + .../src/stories/ProgressIndicator.stories.tsx | 4 +- 95 files changed, 3641 insertions(+), 416 deletions(-) create mode 100644 apps/condo/domains/common/components/CardVideo.tsx create mode 100644 apps/condo/domains/common/components/Form/FormItemTooltipWrapper.tsx create mode 100644 apps/condo/domains/common/components/LinkWithIcon.tsx create mode 100644 apps/condo/domains/onboarding/README.md create mode 100644 apps/condo/domains/onboarding/access/SyncTourStepsService.js delete mode 100644 apps/condo/domains/onboarding/components/.gitkeep create mode 100644 apps/condo/domains/onboarding/components/TourPage/AppCards.tsx create mode 100644 apps/condo/domains/onboarding/components/TourPage/TourStepCard.tsx create mode 100644 apps/condo/domains/onboarding/contexts/TourContext.tsx create mode 100644 apps/condo/domains/onboarding/hooks/TourContext/useCompletedTourModals.tsx create mode 100644 apps/condo/domains/onboarding/hooks/TourContext/useSyncSteps.tsx create mode 100644 apps/condo/domains/onboarding/hooks/TourPage/useTourPageData.tsx create mode 100644 apps/condo/domains/onboarding/schema/SyncTourStepsService.js create mode 100644 apps/condo/domains/onboarding/schema/SyncTourStepsService.test.js create mode 100644 apps/condo/domains/onboarding/utils/clientSchema/constants.ts create mode 100644 apps/condo/domains/property/PropertyFormItemTooltip.tsx create mode 100644 apps/condo/migrations/20240318173552-0376_alter_tourstep_type.js create mode 100644 apps/condo/pages/tour/index.tsx create mode 100644 apps/condo/public/onboarding/technic-app-card/admin.webp create mode 100644 apps/condo/public/onboarding/technic-app-card/qr-technic-app/AppGalery.svg create mode 100644 apps/condo/public/onboarding/technic-app-card/qr-technic-app/AppStore.svg create mode 100644 apps/condo/public/onboarding/technic-app-card/qr-technic-app/GooglePlay.svg create mode 100644 apps/condo/public/onboarding/technic-app-card/security.webp create mode 100644 apps/condo/public/onboarding/technic-app-card/technic.webp create mode 100644 apps/condo/public/onboarding/tourResidentCard.webp create mode 100644 apps/condo/public/onboarding/tourTechnicCard.webp diff --git a/.helm b/.helm index d8e8d1acf86..cf5513cfb7b 160000 --- a/.helm +++ b/.helm @@ -1 +1 @@ -Subproject commit d8e8d1acf86975ce04fdc96be43d29197b077c01 +Subproject commit cf5513cfb7bca69691a6e988b9838d19246dc0a7 diff --git a/apps/condo/domains/billing/components/BillingPageContent/ReceiptsTable.tsx b/apps/condo/domains/billing/components/BillingPageContent/ReceiptsTable.tsx index c8254616580..2ac8af2dfe0 100644 --- a/apps/condo/domains/billing/components/BillingPageContent/ReceiptsTable.tsx +++ b/apps/condo/domains/billing/components/BillingPageContent/ReceiptsTable.tsx @@ -1,4 +1,4 @@ -import { SortBillingReceiptsBy, BillingReceipt as BillingReceiptType } from '@app/condo/schema' +import { SortBillingReceiptsBy, BillingReceipt as BillingReceiptType, TourStepTypeType } from '@app/condo/schema' import { Row, Col, Typography, Space } from 'antd' import dayjs from 'dayjs' import get from 'lodash/get' @@ -6,6 +6,7 @@ import { useRouter } from 'next/router' import React, { useCallback, useMemo, useState, CSSProperties } from 'react' import { useDeepCompareEffect } from '@open-condo/codegen/utils/useDeepCompareEffect' +import { useFeatureFlags } from '@open-condo/featureflags/FeatureFlagsContext' import { useIntl } from '@open-condo/next/intl' import { ServicesModal } from '@condo/domains/billing/components/BillingPageContent/ServicesModal' @@ -16,6 +17,7 @@ import Input from '@condo/domains/common/components/antd/Input' import { BasicEmptyListView } from '@condo/domains/common/components/EmptyListView' import DatePicker from '@condo/domains/common/components/Pickers/DatePicker' import { Table, DEFAULT_PAGE_SIZE } from '@condo/domains/common/components/Table/Index' +import { ORGANIZATION_TOUR } from '@condo/domains/common/constants/featureflags' import { useQueryMappers } from '@condo/domains/common/hooks/useQueryMappers' import { useSearch } from '@condo/domains/common/hooks/useSearch' import { getFiltersQueryData } from '@condo/domains/common/utils/filters.utils' @@ -25,9 +27,11 @@ import { getPageIndexFromOffset, parseQuery, } from '@condo/domains/common/utils/tables.utils' +import { useTourContext } from '@condo/domains/onboarding/contexts/TourContext' import { useBillingAndAcquiringContexts } from './ContextProvider' + const SORTABLE_PROPERTIES = ['toPay'] const INPUT_STYLE: CSSProperties = { width: '18em' } @@ -71,6 +75,15 @@ export const ReceiptsTable: React.FC = () => { skip: (currentPageIndex - 1) * DEFAULT_PAGE_SIZE, }) + const { updateStepIfNotCompleted } = useTourContext() + const { useFlag } = useFeatureFlags() + const isTourEnabled = useFlag(ORGANIZATION_TOUR) + useDeepCompareEffect(() => { + if (isTourEnabled && receipts.length > 0) { + updateStepIfNotCompleted(TourStepTypeType.UploadReceipts) + } + }, [receipts, isTourEnabled]) + const mainTableColumns = useReceiptTableColumns(filterMetas, hasToPayDetails, currencyCode) const [modalIsVisible, setModalIsVisible] = useState(false) diff --git a/apps/condo/domains/common/components/BaseSearchInput/index.tsx b/apps/condo/domains/common/components/BaseSearchInput/index.tsx index 30c87728bb3..49d85ab15fe 100644 --- a/apps/condo/domains/common/components/BaseSearchInput/index.tsx +++ b/apps/condo/domains/common/components/BaseSearchInput/index.tsx @@ -1,11 +1,15 @@ +import styled from '@emotion/styled' import { isEmpty } from 'lodash' import debounce from 'lodash/debounce' +import get from 'lodash/get' import isFunction from 'lodash/isFunction' import throttle from 'lodash/throttle' import uniqBy from 'lodash/uniqBy' import React, { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react' +import { Close } from '@open-condo/icons' import { useIntl } from '@open-condo/next/intl' +import { colors } from '@open-condo/ui/dist/colors' import Select, { CustomSelectProps } from '@condo/domains/common/components/antd/Select' import { Loader } from '@condo/domains/common/components/Loader' @@ -15,6 +19,7 @@ import { isNeedToLoadNewElements } from '@condo/domains/common/utils/select.util import { InitialValuesGetter, useInitialValueGetter } from './useInitialValueGetter' import { useSelectCareeteControls } from './useSelectCareeteControls' + const { Option } = Select const DEBOUNCE_TIMEOUT = 800 @@ -32,6 +37,18 @@ interface ISearchInput extends Omit, 'onSelect'> { setIsMatchSelectedProperty?: Dispatch> } +const StyledSelect = styled(Select)` + .ant-select-selection-placeholder { + color: ${colors.gray[7]}; + opacity: 0.6; + } + + .ant-select-clear { + right: 16px; + color: ${colors.black}; + } +` + const SELECT_LOADER_STYLE = { display: 'flex', justifyContent: 'center', padding: '10px 0' } export const BaseSearchInput = (props: ISearchInput) => { @@ -49,7 +66,7 @@ export const BaseSearchInput = (props: ISearchInput) => { renderOption, initialValueGetter, loadOptionsOnFocus = true, - notFoundContent = NotFoundMessage, + notFoundContent: propsNotFoundContent = NotFoundMessage, setIsMatchSelectedProperty, style, infinityScroll, @@ -68,12 +85,14 @@ export const BaseSearchInput = (props: ISearchInput) => { const [initialOptionsLoaded, setInitialOptionsLoaded] = useState(false) const [initialValue, isInitialValueFetching] = useInitialValueGetter(value, initialValueGetter) const [scrollInputCaretToEnd, setSelectRef, selectInputNode] = useSelectCareeteControls(restSelectProps.id) + const [isEmptyDataFetched, setIsEmptyDataFetched] = useState(false) const searchSuggestions = useCallback( async (value) => { setIsAllDataLoaded(false) setFetching(true) const data = await search(value) + setIsEmptyDataFetched(value && get(data, 'length', 0) === 0) setFetching(false) setData(data) }, @@ -200,11 +219,20 @@ export const BaseSearchInput = (props: ISearchInput) => { [data, fetching, loading, renderOption, value], ) + const notFoundContent = useMemo(() => { + if (fetching || loading) return + + if (isEmptyDataFetched) { + return propsNotFoundContent + } + }, [fetching, isEmptyDataFetched, loading, propsNotFoundContent]) + return ( - + ) } diff --git a/apps/condo/domains/common/components/CardVideo.tsx b/apps/condo/domains/common/components/CardVideo.tsx new file mode 100644 index 00000000000..69f76700bed --- /dev/null +++ b/apps/condo/domains/common/components/CardVideo.tsx @@ -0,0 +1,47 @@ +import React, { CSSProperties, useEffect, useState } from 'react' + +import { Card, Space, Typography } from '@open-condo/ui' + +import { Loader } from './Loader' + + +const CARD_VIDEO_WRAPPER_STYLES: CSSProperties = { + borderRadius: '12px', + overflow: 'hidden', + height: '260px', + width: '100%', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', +} + +export const CardVideo = ({ src, title, description }) => { + const [loading, setLoading] = useState(true) + + useEffect(() => { + setLoading(true) + }, [src]) + + return ( + + +
+