From 608c9c3a2af6f0138843cb35f1c98ee5226464a8 Mon Sep 17 00:00:00 2001 From: Nikita Olizarenko Date: Wed, 6 Oct 2021 19:28:01 +0200 Subject: [PATCH] Handle summary and banner step for announce candidacy --- .../AnnounceCandidacyModal.tsx | 11 +++++ .../components/SummaryAndBannerStep.tsx | 44 +++++++++++++++++++ .../components/TitleAndBulletPointsStep.tsx | 2 +- .../modals/AnnounceCandidacy/machine.ts | 30 ++++++++++--- .../modals/AnnounceCandidacyModal.test.tsx | 39 +++++++++++++++- 5 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 packages/ui/src/council/modals/AnnounceCandidacy/components/SummaryAndBannerStep.tsx diff --git a/packages/ui/src/council/modals/AnnounceCandidacy/AnnounceCandidacyModal.tsx b/packages/ui/src/council/modals/AnnounceCandidacy/AnnounceCandidacyModal.tsx index 118cf81805..5a4fa8c438 100644 --- a/packages/ui/src/council/modals/AnnounceCandidacy/AnnounceCandidacyModal.tsx +++ b/packages/ui/src/council/modals/AnnounceCandidacy/AnnounceCandidacyModal.tsx @@ -19,6 +19,7 @@ import { useCouncilConstants } from '@/council/hooks/useCouncilConstants' import { AnnounceCandidacyConstantsWrapper } from '@/council/modals/AnnounceCandidacy/components/AnnounceCandidacyConstantsWrapper' import { RewardAccountStep } from '@/council/modals/AnnounceCandidacy/components/RewardAccountStep' import { StakingStep } from '@/council/modals/AnnounceCandidacy/components/StakingStep' +import { SummaryAndBannerStep } from '@/council/modals/AnnounceCandidacy/components/SummaryAndBannerStep' import { TitleAndBulletPointsStep } from '@/council/modals/AnnounceCandidacy/components/TitleAndBulletPointsStep' import { announceCandidacyMachine } from '@/council/modals/AnnounceCandidacy/machine' import { useMyMemberships } from '@/memberships/hooks/useMyMemberships' @@ -81,6 +82,8 @@ export const AnnounceCandidacyModal = () => { state.context.bulletPoints.length ) { setValidNext(true) + } else if (state.matches('candidateProfile.summaryAndBanner') && state.context.summary) { + setValidNext(true) } else { setValidNext(false) } @@ -147,6 +150,14 @@ export const AnnounceCandidacyModal = () => { setBulletPoints={(bulletPoints) => send('SET_BULLET_POINTS', { bulletPoints })} /> )} + {state.matches('candidateProfile.summaryAndBanner') && ( + send('SET_SUMMARY', { summary })} + banner={state.context.banner} + setBanner={(banner) => send('SET_BANNER', { banner })} + /> + )} diff --git a/packages/ui/src/council/modals/AnnounceCandidacy/components/SummaryAndBannerStep.tsx b/packages/ui/src/council/modals/AnnounceCandidacy/components/SummaryAndBannerStep.tsx new file mode 100644 index 0000000000..1b057bf997 --- /dev/null +++ b/packages/ui/src/council/modals/AnnounceCandidacy/components/SummaryAndBannerStep.tsx @@ -0,0 +1,44 @@ +import React from 'react' + +import { CKEditor } from '@/common/components/CKEditor' +import { InputComponent, InputText } from '@/common/components/forms' +import { Row } from '@/common/components/Modal' +import { RowGapBlock } from '@/common/components/page/PageContent' + +interface SummaryAndBannerStepProps { + summary?: string + banner?: string + setSummary: (summary?: string) => void + setBanner: (banner?: string) => void +} + +export const SummaryAndBannerStep = ({ summary, banner, setSummary, setBanner }: SummaryAndBannerStepProps) => { + return ( + + + +

Candidate profile

+
+
+ + + + setSummary(editor.getData())} + onReady={(editor) => editor.setData(summary || '')} + /> + + + setBanner(event.target.value)} + /> + + + +
+ ) +} diff --git a/packages/ui/src/council/modals/AnnounceCandidacy/components/TitleAndBulletPointsStep.tsx b/packages/ui/src/council/modals/AnnounceCandidacy/components/TitleAndBulletPointsStep.tsx index 76f802643e..18b7fb3589 100644 --- a/packages/ui/src/council/modals/AnnounceCandidacy/components/TitleAndBulletPointsStep.tsx +++ b/packages/ui/src/council/modals/AnnounceCandidacy/components/TitleAndBulletPointsStep.tsx @@ -41,7 +41,7 @@ export const TitleAndBulletPointsStep = ({ setBulletPoints, }: TitleAndBulletPointsStepProps) => { const formInitializer: FormFields = { - title, + title: title || '', bulletPoint1: bulletPoints[0] || '', bulletPoint2: bulletPoints[1] || '', bulletPoint3: bulletPoints[2] || '', diff --git a/packages/ui/src/council/modals/AnnounceCandidacy/machine.ts b/packages/ui/src/council/modals/AnnounceCandidacy/machine.ts index c4f250e2eb..55bd5cdd66 100644 --- a/packages/ui/src/council/modals/AnnounceCandidacy/machine.ts +++ b/packages/ui/src/council/modals/AnnounceCandidacy/machine.ts @@ -18,7 +18,14 @@ interface TitleAndBulletPointsContext extends Required { bulletPoints: string[] } -export type AnnounceCandidacyContext = Partial +interface SummaryAndBannerContext extends Required { + summary?: string + banner?: string +} + +export type AnnounceCandidacyContext = Partial< + StakingContext & RewardAccountContext & TitleAndBulletPointsContext & SummaryAndBannerContext +> export type AnnounceCandidacyState = | { value: 'requirementsVerification'; context: EmptyObject } @@ -29,15 +36,17 @@ export type AnnounceCandidacyState = | { value: 'rewardAccount'; context: Required } | { value: 'candidateProfile'; context: Required } | { value: 'candidateProfile.titleAndBulletPoints'; context: Required } - | { value: 'candidateProfile.summaryAndBanner'; context: Required } - | { value: 'candidateProfile.finishCandidateProfile'; context: Required } - | { value: 'success'; context: Required } + | { value: 'candidateProfile.summaryAndBanner'; context: Required } + | { value: 'candidateProfile.finishCandidateProfile'; context: Required } + | { value: 'success'; context: Required } | { value: 'error'; context: AnnounceCandidacyContext } type SetAccountEvent = { type: 'SET_ACCOUNT'; account: Account } type SetAmountEvent = { type: 'SET_AMOUNT'; amount: BN } type SetTitleEvent = { type: 'SET_TITLE'; title: string } type SetBulletPointsEvent = { type: 'SET_BULLET_POINTS'; bulletPoints: string[] } +type SetSummaryEvent = { type: 'SET_SUMMARY'; summary: string } +type SetBannerEvent = { type: 'SET_BANNER'; banner: string } type AnnounceCandidacyEvent = | { type: 'FAIL' } @@ -47,6 +56,8 @@ type AnnounceCandidacyEvent = | SetAmountEvent | SetTitleEvent | SetBulletPointsEvent + | SetSummaryEvent + | SetBannerEvent export const announceCandidacyMachine = createMachine< AnnounceCandidacyContext, @@ -55,7 +66,6 @@ export const announceCandidacyMachine = createMachine< >({ initial: 'requirementsVerification', context: { - title: '', bulletPoints: [], }, states: { @@ -139,6 +149,16 @@ export const announceCandidacyMachine = createMachine< NEXT: { target: 'finishCandidateProfile', }, + SET_SUMMARY: { + actions: assign({ + summary: (context, event) => event.summary, + }), + }, + SET_BANNER: { + actions: assign({ + banner: (context, event) => event.banner, + }), + }, }, }, finishCandidateProfile: { diff --git a/packages/ui/test/council/modals/AnnounceCandidacyModal.test.tsx b/packages/ui/test/council/modals/AnnounceCandidacyModal.test.tsx index 10b022a8ac..49a688edaf 100644 --- a/packages/ui/test/council/modals/AnnounceCandidacyModal.test.tsx +++ b/packages/ui/test/council/modals/AnnounceCandidacyModal.test.tsx @@ -7,6 +7,7 @@ import { interpret } from 'xstate' import { AccountsContext } from '@/accounts/providers/accounts/context' import { UseAccounts } from '@/accounts/providers/accounts/provider' +import { CKEditorProps } from '@/common/components/CKEditor' import { BalancesContextProvider } from '@/accounts/providers/balances/provider' import { getSteps } from '@/common/model/machines/getSteps' import { ApiContext } from '@/common/providers/api/context' @@ -21,6 +22,7 @@ import { seedMembers } from '@/mocks/data' import { getButton } from '../../_helpers/getButton' import { includesTextWithMarkup } from '../../_helpers/includesTextWithMarkup' import { selectFromDropdown } from '../../_helpers/selectFromDropdown' +import { mockCKEditor } from '../../_mocks/components/CKEditor' import { alice, bob } from '../../_mocks/keyring' import { getMember } from '../../_mocks/members' import { MockKeyringProvider, MockQueryNodeProviders } from '../../_mocks/providers' @@ -35,6 +37,10 @@ import { configure({ testIdAttribute: 'id' }) +jest.mock('@/common/components/CKEditor', () => ({ + CKEditor: (props: CKEditorProps) => mockCKEditor(props), +})) + describe('UI: Announce Candidacy Modal', () => { const api = stubApi() const useModal: UseModal = { @@ -233,6 +239,25 @@ describe('UI: Announce Candidacy Modal', () => { }) }) + describe('Summary and Banner', () => { + beforeEach(async () => { + renderModal() + await fillStakingStep('alice', 15, true) + await fillRewardAccountStep('alice', true) + await fillTitleAndBulletPointsStep('Some title', 'Some bullet point', true) + }) + + it('Default', async () => { + expect(await getNextStepButton()).toBeDisabled() + }) + + it('Summary filled', async () => { + await fillSummary() + + expect(await getNextStepButton()).not.toBeDisabled() + }) + }) + async function fillStakingAmount(value: number) { const amountInput = await screen.getByTestId('stakingAmount') @@ -286,8 +311,20 @@ describe('UI: Announce Candidacy Modal', () => { } } + async function fillSummary(goNext?: boolean) { + const summaryInput = await screen.findByLabelText(/Summary/i) + + act(() => { + fireEvent.change(summaryInput, { target: { value: 'Some summary' } }) + }) + + if (goNext) { + await clickNextButton() + } + } + async function getNextStepButton() { - return getButton(/Next step/i) + return getButton(/(Next step|Announce candidacy)/i) } async function clickNextButton() {