From f3a5aea90b0605ca55fdf43670157d3bc884afb5 Mon Sep 17 00:00:00 2001 From: Teodora Zhelyazkova Date: Fri, 21 Jun 2024 10:33:02 +0300 Subject: [PATCH] feat: create a campaign application stepper skeleton (Epic #1842) (#1859) * create a protected route for campaign applications * feat: create campaign-application steps components * feat: create campaign-application stepper component * feat: create stepper icon component * feat: render the stepper in the campaign application page * fix: adjust Stepper styles according to Figma design * feat: add actions buttons for the stepper * feat: add translations for the stepper action buttons * fix: adjust action buttons styles and functionality * lint: remove empty type --- public/locales/bg/campaign-application.json | 6 ++ .../CampaignApplicationForm.tsx | 69 +++++++++++++++++++ .../CampaignApplicationFormActions.tsx | 51 ++++++++++++++ .../CampaignApplicationPage.tsx | 7 +- .../CampaignApplicationStepperIcon.tsx | 16 +++++ .../helpers/campaignApplication.styled.tsx | 61 ++++++++++++++++ .../helpers/campaignApplication.types.ts | 11 +++ .../campaignApplicationFormActions.styled.tsx | 45 ++++++++++++ .../helpers/stepsHandler.ts | 30 ++++++++ .../steps/CampaignApplication.tsx | 3 + .../steps/CampaignApplicationDetails.tsx | 3 + .../steps/CampaignApplicationOrganizer.tsx | 3 + src/pages/campaigns/application.tsx | 2 +- 13 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 public/locales/bg/campaign-application.json create mode 100644 src/components/client/campaign-application/CampaignApplicationForm.tsx create mode 100644 src/components/client/campaign-application/CampaignApplicationFormActions.tsx create mode 100644 src/components/client/campaign-application/CampaignApplicationStepperIcon.tsx create mode 100644 src/components/client/campaign-application/helpers/campaignApplication.styled.tsx create mode 100644 src/components/client/campaign-application/helpers/campaignApplication.types.ts create mode 100644 src/components/client/campaign-application/helpers/campaignApplicationFormActions.styled.tsx create mode 100644 src/components/client/campaign-application/helpers/stepsHandler.ts create mode 100644 src/components/client/campaign-application/steps/CampaignApplication.tsx create mode 100644 src/components/client/campaign-application/steps/CampaignApplicationDetails.tsx create mode 100644 src/components/client/campaign-application/steps/CampaignApplicationOrganizer.tsx diff --git a/public/locales/bg/campaign-application.json b/public/locales/bg/campaign-application.json new file mode 100644 index 000000000..4d10e1170 --- /dev/null +++ b/public/locales/bg/campaign-application.json @@ -0,0 +1,6 @@ +{ + "cta": { + "next": "Запазете и продължете", + "back": "Назад" + } +} diff --git a/src/components/client/campaign-application/CampaignApplicationForm.tsx b/src/components/client/campaign-application/CampaignApplicationForm.tsx new file mode 100644 index 000000000..d24a6c0d9 --- /dev/null +++ b/src/components/client/campaign-application/CampaignApplicationForm.tsx @@ -0,0 +1,69 @@ +import { useCallback, useState } from 'react' + +import { Grid, StepLabel } from '@mui/material' + +import { Step as StepType, Steps } from './helpers/campaignApplication.types' + +import GenericForm from 'components/common/form/GenericForm' +import CampaignApplicationStepperIcon from './CampaignApplicationStepperIcon' +import CampaignApplicationOrganizer from './steps/CampaignApplicationOrganizer' +import CampaignApplicationDetails from './steps/CampaignApplicationDetails' +import CampaignApplication from './steps/CampaignApplication' +import CampaignApplicationFormActions from './CampaignApplicationFormActions' +import stepsHandler from './helpers/stepsHandler' + +import { + ActionsContainer, + StyledCampaignApplicationStep, + StyledCampaignApplicationStepper, + StyledStepConnector, +} from './helpers/campaignApplication.styled' + +const initialValues: Record = {} + +const steps: StepType[] = [ + { + title: 'campaign-application:steps.organizer.title', + component: , + }, + { + title: 'campaign-application:steps.campaign-application.title', + component: , + }, + { + title: 'campaign-application:steps.campaign-application-details.title', + component: , + }, +] + +export default function CampaignApplicationForm() { + const [activeStep, setActiveStep] = useState(Steps.ORGANIZER) + + const handleSubmit = () => { + stepsHandler({ activeStep, setActiveStep }) + } + + const handleBack = useCallback(() => { + setActiveStep((prevActiveStep) => prevActiveStep - 1) + }, []) + + return ( + > onSubmit={handleSubmit} initialValues={initialValues}> + }> + {steps.map((step) => ( + + + + ))} + + + + {activeStep < steps.length && steps[activeStep].component} + + + + + + + ) +} diff --git a/src/components/client/campaign-application/CampaignApplicationFormActions.tsx b/src/components/client/campaign-application/CampaignApplicationFormActions.tsx new file mode 100644 index 000000000..acab02d31 --- /dev/null +++ b/src/components/client/campaign-application/CampaignApplicationFormActions.tsx @@ -0,0 +1,51 @@ +import { MouseEvent } from 'react' + +import { useTranslation } from 'next-i18next' + +import { Grid } from '@mui/material' +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos' +import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos' + +import { + ActionButton, + ActionLinkButton, + ActionSubmitButton, + Root, +} from './helpers/campaignApplicationFormActions.styled' + +type CampaignApplicationFormActionsProps = { + activeStep: number + onBack?: (event: MouseEvent) => void +} + +export default function CampaignApplicationFormActions({ + onBack, + activeStep, +}: CampaignApplicationFormActionsProps) { + const { t } = useTranslation('campaign-application') + + return ( + + + {activeStep === 0 ? ( + }> + {t('cta.back')} + + ) : ( + }> + {t('cta.back')} + + )} + + + } + /> + + + ) +} diff --git a/src/components/client/campaign-application/CampaignApplicationPage.tsx b/src/components/client/campaign-application/CampaignApplicationPage.tsx index 21eebdc60..c9b7cacd3 100644 --- a/src/components/client/campaign-application/CampaignApplicationPage.tsx +++ b/src/components/client/campaign-application/CampaignApplicationPage.tsx @@ -1,5 +1,10 @@ import Layout from '../layout/Layout' +import CampaignApplicationForm from './CampaignApplicationForm' export default function CampaignApplicationPage() { - return + return ( + + + + ) } diff --git a/src/components/client/campaign-application/CampaignApplicationStepperIcon.tsx b/src/components/client/campaign-application/CampaignApplicationStepperIcon.tsx new file mode 100644 index 000000000..930065e59 --- /dev/null +++ b/src/components/client/campaign-application/CampaignApplicationStepperIcon.tsx @@ -0,0 +1,16 @@ +import { StepIconProps } from '@mui/material/StepIcon' +import { StyledCampaignApplicationStepperIcon } from './helpers/campaignApplication.styled' + +export default function CampaignApplicationStepperIcon(props: StepIconProps) { + const icons: { [index: string]: React.ReactElement } = { + 1: 1, + 2: 2, + 3: 3, + } + + return ( + + {icons[String(props.icon)]} + + ) +} diff --git a/src/components/client/campaign-application/helpers/campaignApplication.styled.tsx b/src/components/client/campaign-application/helpers/campaignApplication.styled.tsx new file mode 100644 index 000000000..c4f5d7b16 --- /dev/null +++ b/src/components/client/campaign-application/helpers/campaignApplication.styled.tsx @@ -0,0 +1,61 @@ +import { styled } from '@mui/material/styles' +import { Grid, Step, StepConnector, Stepper } from '@mui/material' + +import theme from 'common/theme' + +export const StyledCampaignApplicationStep = styled(Step)(() => ({ + padding: 0, + + '& span': { + padding: 0, + }, + + '& .Mui-active': { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: theme.palette.primary.main, + height: '70px', + width: '70px', + borderRadius: theme.borders.round, + + '& span': { + color: theme.palette.common.white, + fontSize: theme.typography.pxToRem(48), + }, + }, +})) + +export const StyledCampaignApplicationStepper = styled(Stepper)(() => ({ + backgroundColor: 'transparent', + margin: '20px auto', + maxWidth: '530px', +})) + +export const StyledStepConnector = styled(StepConnector)(() => ({ + height: 5, + backgroundColor: theme.palette.primary.main, + + '& span': { + border: 'none', + }, +})) + +export const StyledCampaignApplicationStepperIcon = styled(Grid)(() => ({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: theme.palette.common.black, + height: '52.05px', + width: '52.05px', + border: `5px solid ${theme.palette.primary.main}`, + borderRadius: theme.borders.round, + zIndex: 1, + fontSize: theme.typography.pxToRem(36), +})) + +export const ActionsContainer = styled(Grid)(() => ({ + display: 'flex', + justifyContent: 'center', + marginTop: theme.spacing(1), +})) diff --git a/src/components/client/campaign-application/helpers/campaignApplication.types.ts b/src/components/client/campaign-application/helpers/campaignApplication.types.ts new file mode 100644 index 000000000..bd03de13d --- /dev/null +++ b/src/components/client/campaign-application/helpers/campaignApplication.types.ts @@ -0,0 +1,11 @@ +export type Step = { + title: string + component: JSX.Element +} + +export enum Steps { + NONE = -1, + ORGANIZER = 0, + CAMPAIGN = 1, + CAMPAIGN_DETAILS = 2, +} diff --git a/src/components/client/campaign-application/helpers/campaignApplicationFormActions.styled.tsx b/src/components/client/campaign-application/helpers/campaignApplicationFormActions.styled.tsx new file mode 100644 index 000000000..4fea44c25 --- /dev/null +++ b/src/components/client/campaign-application/helpers/campaignApplicationFormActions.styled.tsx @@ -0,0 +1,45 @@ +import { styled } from '@mui/material/styles' +import { Button, Grid } from '@mui/material' + +import LinkButton from 'components/common/LinkButton' +import SubmitButton from 'components/common/form/SubmitButton' + +import theme from 'common/theme' + +export const Root = styled(Grid)(() => ({ + marginTop: theme.spacing(15), + textAlign: 'center', +})) + +export const ActionLinkButton = styled(LinkButton)(() => ({ + backgroundColor: theme.palette.common.white, + border: `1px solid ${theme.palette.common.black}`, + padding: theme.spacing(1, 5), + borderRadius: theme.borders.round, + color: theme.palette.common.black, + fontSize: theme.typography.pxToRem(20), + width: theme.spacing(50), + fontWeight: 800, +})) + +export const ActionButton = styled(Button)(() => ({ + backgroundColor: theme.palette.common.white, + border: `1px solid ${theme.palette.common.black}`, + padding: theme.spacing(1, 5), + borderRadius: theme.borders.round, + color: theme.palette.common.black, + fontSize: theme.typography.pxToRem(20), + width: theme.spacing(50), + fontWeight: 800, +})) + +export const ActionSubmitButton = styled(SubmitButton)(() => ({ + backgroundColor: '#62C4FB', + border: `1px solid ${theme.palette.common.black}`, + padding: theme.spacing(1, 5), + borderRadius: theme.borders.round, + color: theme.palette.common.black, + fontSize: theme.typography.pxToRem(20), + width: theme.spacing(50), + fontWeight: 800, +})) diff --git a/src/components/client/campaign-application/helpers/stepsHandler.ts b/src/components/client/campaign-application/helpers/stepsHandler.ts new file mode 100644 index 000000000..f7c2cbedb --- /dev/null +++ b/src/components/client/campaign-application/helpers/stepsHandler.ts @@ -0,0 +1,30 @@ +import { SetStateAction } from 'react' + +import { Steps } from './campaignApplication.types' + +interface stepsHandlerProps { + activeStep: Steps + setActiveStep: (value: SetStateAction) => void +} + +export default function stepsHandler({ activeStep, setActiveStep }: stepsHandlerProps) { + switch (activeStep) { + case Steps.ORGANIZER: + { + setActiveStep((prevActiveStep) => prevActiveStep + 1) + } + break + case Steps.CAMPAIGN: + { + setActiveStep((prevActiveStep) => prevActiveStep + 1) + } + break + case Steps.CAMPAIGN_DETAILS: + { + setActiveStep((prevActiveStep) => prevActiveStep + 1) + } + break + default: + return 'Unknown step' + } +} diff --git a/src/components/client/campaign-application/steps/CampaignApplication.tsx b/src/components/client/campaign-application/steps/CampaignApplication.tsx new file mode 100644 index 000000000..756c39c32 --- /dev/null +++ b/src/components/client/campaign-application/steps/CampaignApplication.tsx @@ -0,0 +1,3 @@ +export default function CampaignApplication() { + return
Campaign Application
+} diff --git a/src/components/client/campaign-application/steps/CampaignApplicationDetails.tsx b/src/components/client/campaign-application/steps/CampaignApplicationDetails.tsx new file mode 100644 index 000000000..2953d14d5 --- /dev/null +++ b/src/components/client/campaign-application/steps/CampaignApplicationDetails.tsx @@ -0,0 +1,3 @@ +export default function CampaignApplicationDetails() { + return
Campaign Application Details
+} diff --git a/src/components/client/campaign-application/steps/CampaignApplicationOrganizer.tsx b/src/components/client/campaign-application/steps/CampaignApplicationOrganizer.tsx new file mode 100644 index 000000000..e533999c0 --- /dev/null +++ b/src/components/client/campaign-application/steps/CampaignApplicationOrganizer.tsx @@ -0,0 +1,3 @@ +export default function CampaignApplicationOrganizer() { + return
Campaign Application Organizer
+} diff --git a/src/pages/campaigns/application.tsx b/src/pages/campaigns/application.tsx index 5bd3013cd..607a2ff2c 100644 --- a/src/pages/campaigns/application.tsx +++ b/src/pages/campaigns/application.tsx @@ -4,7 +4,7 @@ import { routes } from 'common/routes' import CampaignApplicationPage from 'components/client/campaign-application/CampaignApplicationPage' export const getServerSideProps: GetServerSideProps = securedPropsWithTranslation( - ['common', 'auth', 'validation', 'campaigns'], + ['common', 'auth', 'validation', 'campaigns', 'campaign-application'], routes.campaigns.application, )