Skip to content

Commit

Permalink
feat(condo) DOMA-7889 News cross posting frontend (#4830)
Browse files Browse the repository at this point in the history
* fix(condo) DOMA-7889: init news sharing integration

* feat(condo): DOMA-7888: proof of concept greendom integration app

* feat(condo): DOMA-7889: proof of concept frontend code

* feat(condo): DOMA-7889: remove telegram sharing submodule from the code

feat(condo): DOMA-7889: fix gitmodules

* fix(ui): DOMA-7889: make Card component grow with row && fix border on hover

* refactor(condo): DOMA-7889: introduce translations on SelectSharingAppControl.tsx

* refactor(condo): DOMA-7889: beautify news type markup

* feat(condo): DOMA-7889: add app skipping feature and fix card grids

* fix(condo): DOMA-7889: fix a few linter errors

* feat(condo): DOMA-7889: drop skipped steps on sharing app update

* refactor(condo): DOMA-7889: refactor settings page

* refactor(condo): DOMA-7889: refactor preview widget

* chore(condo): DOMA-7889: update submodules

* refactor(condo): DOMA-7889: implement cleaner form architecture – store form data in useState by steps

* refactor(condo): DOMA-7889: update migrations

* fix(condo): DOMA-7889: fix typescript errors

* fix(condo): DOMA-7889: add more useCallbacks

fix(condo): DOMA-7889: add more useCallbacks

* fix(condo): DOMA-7889: fix eslint errors

* chore(condo): DOMA-7889: update submodule to relevant version

* chore(condo): DOMA-7889: fix variable usage before declaration error

* feat(condo): DOMA-7889: add publish delayed shared news item task, handle new sendAt logic, add tests

* fix(condo): DOMA-7889: fix eslint errors and some warnings

fix(condo): DOMA-7889: fix eslint errors and some warnings

* fix(condo): DOMA-7889: upgrade tests

fix(condo): DOMA-7889: upgrade tests

* fix(condo): DOMA-7889: fix eslint errors

fix(condo): DOMA-7889: fix eslint errors

* fix(condo): DOMA-7889: remove greendom submodule

fix(condo): DOMA-7889: remove greendom submodule

* fix(condo): DOMA-7889: regenerate migrations

* fix(condo): DOMA-7889: regenerate migrations

* fix(ui): DOMA-7889: fix linter errors

* fix(condo): DOMA-7889: fixes on self-review

* fix(condo): DOMA-7889: fixes on self-review

* fix(condo): DOMA-7889: fixes on self-review

* fix(condo): DOMA-7889: fixes on self-review

* chore(condo): DOMA-7889: update lockfile

* chore(condo): DOMA-7889: update lockfile

* chore(condo): DOMA-7889: fixes on self-review

* chore(condo): DOMA-7889: fixes on self-review

* chore(condo): DOMA-7889: fixes on self-review

* refactor(condo): DOMA-7889: lower the amount of executed publishNewsItemSharing.js tasks

* chore(condo): DOMA-7889: regenerate migrations

* refactor(condo): DOMA-7888: implement fixes on review

* refactor(condo): DOMA-7888: add feature flags based form resolver

* refactor(condo): DOMA-7888: fixes on linter review

* refactor(condo): DOMA-7888: fixes on linter review

* refactor(condo): DOMA-7888: fixes on linter review

* refactor(condo): DOMA-7888: fixes on linter review

* refactor(condo): DOMA-7888: fixes on review

* refactor(condo): DOMA-7888: fixes on review

* refactor(condo): DOMA-7888: fixes on review

* refactor(condo): DOMA-7888: fixes on review
  • Loading branch information
toplenboren authored Jun 21, 2024
1 parent 126b1f6 commit 3578c3d
Show file tree
Hide file tree
Showing 41 changed files with 3,485 additions and 575 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export const GlobalAppsContainer: React.FC = () => {
}
}, [user, loading])

// // Global miniapps allowed only for authenticated users
// Global miniapps allowed only for authenticated users
if (!user) {
return null
}
Expand Down
10 changes: 5 additions & 5 deletions apps/condo/domains/miniapp/gql.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ const SEND_B2C_APP_PUSH_MESSAGE_MUTATION = gql`
}
`

const B2B_APP_FIELDS = `{ name logo { publicUrl } icon shortDescription detailedDescription developer partnerUrl appUrl category label gallery price features ${COMMON_FIELDS} }`
const B2B_APP_NEWS_SHARING_CONFIG_FIELDS = `{ publishUrl previewUrl customFormUrl getRecipientsUrl icon { publicUrl } previewPicture { publicUrl } name ${COMMON_FIELDS} }`
const B2BAppNewsSharingConfig = generateGqlQueries('B2BAppNewsSharingConfig', B2B_APP_NEWS_SHARING_CONFIG_FIELDS)

const B2B_APP_FIELDS = `{ name logo { publicUrl } icon shortDescription detailedDescription newsSharingConfig ${B2B_APP_NEWS_SHARING_CONFIG_FIELDS} developer partnerUrl appUrl category label gallery price features ${COMMON_FIELDS} }`
const B2BApp = generateGqlQueries('B2BApp', B2B_APP_FIELDS)

const B2B_APP_CONTEXT_FIELDS = `{ app { id name appUrl icon menuCategory hasDynamicTitle } organization { id } status ${COMMON_FIELDS} }`
const B2B_APP_CONTEXT_FIELDS = `{ app { id name appUrl icon menuCategory hasDynamicTitle newsSharingConfig ${B2B_APP_NEWS_SHARING_CONFIG_FIELDS} } organization { id } status ${COMMON_FIELDS} }`
const B2BAppContext = generateGqlQueries('B2BAppContext', B2B_APP_CONTEXT_FIELDS)

const B2B_ACCESSES_LISTS_FIELDS = Object.keys(B2B_APP_SERVICE_USER_ACCESS_AVAILABLE_SCHEMAS.lists)
Expand Down Expand Up @@ -73,9 +76,6 @@ const MessageAppBlackList = generateGqlQueries('MessageAppBlackList', MESSAGE_AP
const B2B_APP_ACCESS_RIGHT_SET_FIELDS = `{ app { id } ${B2B_ACCESSES_LISTS_FIELDS} ${B2B_ACCESSES_SERVICES_FIELDS} ${COMMON_FIELDS} }`
const B2BAppAccessRightSet = generateGqlQueries('B2BAppAccessRightSet', B2B_APP_ACCESS_RIGHT_SET_FIELDS)

const B2B_APP_NEWS_SHARING_CONFIG_FIELDS = `{ publishUrl previewUrl getRecipientsUrl name ${COMMON_FIELDS} }`
const B2BAppNewsSharingConfig = generateGqlQueries('B2BAppNewsSharingConfig', B2B_APP_NEWS_SHARING_CONFIG_FIELDS)

/* AUTOGENERATE MARKER <CONST> */

module.exports = {
Expand Down
8 changes: 8 additions & 0 deletions apps/condo/domains/miniapp/schema/B2BAppNewsSharingConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const B2BAppNewsSharingConfig = new GQLListSchema('B2BAppNewsSharingConfig', {

icon: { ...LOGO_FIELD, schemaDoc: 'Icon of the app: Telegram Icon / WhatsApp Icon' },

previewPicture: { ...LOGO_FIELD, schemaDoc: 'Preview picture: might be app screenshot' },

previewUrl: {
schemaDoc: 'URL that returns HTML preview NewsItem',
type: 'Url',
Expand All @@ -52,6 +54,12 @@ const B2BAppNewsSharingConfig = new GQLListSchema('B2BAppNewsSharingConfig', {
type: 'Url',
isRequired: true,
},

customFormUrl: {
schemaDoc: 'URL that implements customForm. If not filled, then app will use standard news form',
type: 'Url',
isRequired: false,
},
},
plugins: [uuided(), versioned(), tracked(), softDeleted(), dvAndSender(), historical()],
access: {
Expand Down
928 changes: 635 additions & 293 deletions apps/condo/domains/news/components/NewsForm/BaseNewsForm.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Condo currently supports two UIs for news sharing:
* 1. BaseNewsForm – ui with support of cross posting functionality
* 2. OldBaseNewsForm - legacy ui without support of cross posting functionality
* TODO (DOMA-9331) Remove this component and OldBaseNewsForm
*
* Note: OldBaseNewsForm was slightly modified to support new API of NewsPreview component, as well as few other minor changes
*/

import React from 'react'

import { useFeatureFlags } from '@open-condo/featureflags/FeatureFlagsContext'

import { NEWS_SHARING } from '@condo/domains/common/constants/featureflags'
import { BaseNewsFormProps, BaseNewsForm } from '@condo/domains/news/components/NewsForm/BaseNewsForm'
import { OldBaseNewsForm } from '@condo/domains/news/components/NewsForm/OldBaseNewsForm'

export const BaseNewsFormByFeatureFlag: React.FC<BaseNewsFormProps> = (
props
) => {
const { useFlag } = useFeatureFlags()
const isNewsSharingEnabled = useFlag(NEWS_SHARING)

if (isNewsSharingEnabled) {
return <BaseNewsForm
{...props}
/>
} else {
return <OldBaseNewsForm
{...props}
/>
}
}
35 changes: 26 additions & 9 deletions apps/condo/domains/news/components/NewsForm/CreateNewsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import { useOrganization } from '@open-condo/next/organization'
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 { B2BAppContext } from '@condo/domains/miniapp/utils/clientSchema'
import { NewsItem, NewsItemTemplate, NewsItemSharing } from '@condo/domains/news/utils/clientSchema'
import { Property } from '@condo/domains/property/utils/clientSchema'

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


const SMALL_VERTICAL_GUTTER: [Gutter, Gutter] = [0, 28]
Expand Down Expand Up @@ -125,9 +127,10 @@ export const CreateNewsForm: React.FC = () => {
const organizationId = useMemo(() => get(organization, 'id'), [organization])

const createNewsItem = NewsItem.useCreate({ organization: { connect: { id: organizationId } } })
const action: BaseNewsFormProps['action'] = useCallback(async (values) => {
return await createNewsItem(values)
}, [createNewsItem])
const createNewsItemSharing = NewsItemSharing.useCreate({})

const action: BaseNewsFormProps['newsItemAction'] = useCallback(async (values) => { return await createNewsItem(values) }, [createNewsItem])
const createNewsItemSharingAction: BaseNewsFormProps['newsItemSharingAction'] = useCallback(async (values) => { return await createNewsItemSharing(values) }, [createNewsItemSharing])

const {
loading: isNewsItemTemplatesFetching,
Expand All @@ -142,6 +145,18 @@ export const CreateNewsForm: React.FC = () => {
},
})

const {
loading: isSharingAppContextsFetching,
objs: sharingAppContexts,
error: sharingAppContextsError,
} = B2BAppContext.useObjects({
where: {
organization: { id: organizationId },
app: { newsSharingConfig_is_null: false, deletedAt: null },
deletedAt: null,
},
})

const {
loading: totalPropertiesLoading,
count: totalProperties,
Expand Down Expand Up @@ -191,8 +206,8 @@ export const CreateNewsForm: React.FC = () => {
)
}, [intl, softDeleteNewsItem])

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

const initialValues = useMemo(() => organizationNewsCount === 0 && ({
title: InitialOrganizationNewsItemTitle,
Expand All @@ -209,13 +224,15 @@ export const CreateNewsForm: React.FC = () => {
}

return (
<BaseNewsForm
<BaseNewsFormByFeatureFlag
autoFocusBody={organizationNewsCount === 0}
initialValues={initialValues}
action={action}
organizationId={organizationId}
newsItemAction={action}
ActionBar={CreateNewsActionBar}
templates={templates}
sharingAppContexts={sharingAppContexts}
newsItemSharingAction={createNewsItemSharingAction}
OnCompletedMsg={OnCompletedMsg}
allNews={allNews}
actionName='create'
Expand Down
52 changes: 52 additions & 0 deletions apps/condo/domains/news/components/NewsForm/NewsCardGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Row, Col } from 'antd'
import React from 'react'

import { useContainerSize } from '@open-condo/ui/dist/hooks'

import type { RowProps } from 'antd'

type NewsCardGridProps = {
children: React.ReactNode
minColWidth?: number
gap?: number,
minCols?: number,
maxCols?: number
}

const GAP = 32
const ROW_GUTTER: RowProps['gutter'] = [GAP, GAP]
const MIN_COL_WIDTH = 350
const MIN_COLS = 1
const MAX_COLS = 4

function getColsAmount (
width: number,
minColWidth: number = MIN_COL_WIDTH,
gap: number = GAP,
minCols: number = MIN_COLS,
maxCols: number = MAX_COLS,
): number {
const fitCols = Math.floor((width + gap) / (minColWidth + gap))
return Math.min(maxCols, Math.max(minCols, fitCols))
}

export const NewsCardGrid: React.FC<NewsCardGridProps> = ({
children,
minColWidth,
gap,
minCols,
maxCols,
}) => {
const [{ width }, setRef] = useContainerSize()
const cols = getColsAmount(width, minColWidth, gap, minCols, maxCols)
const colSpan = 24 / cols
return (
<Row gutter={ROW_GUTTER} ref={setRef}>
{React.Children.map(children, (child, index) => (
<Col span={colSpan} key={index}>
{child}
</Col>
))}
</Row>
)
}
Loading

0 comments on commit 3578c3d

Please sign in to comment.