Skip to content

Commit

Permalink
feat: create a campaign application stepper skeleton (Epic #1842) (#1859
Browse files Browse the repository at this point in the history
)

* 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
  • Loading branch information
teodorazhelyazkova authored Jun 21, 2024
1 parent a4ccc0c commit f3a5aea
Show file tree
Hide file tree
Showing 13 changed files with 305 additions and 2 deletions.
6 changes: 6 additions & 0 deletions public/locales/bg/campaign-application.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"cta": {
"next": "Запазете и продължете",
"back": "Назад"
}
}
Original file line number Diff line number Diff line change
@@ -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<string, string> = {}

const steps: StepType[] = [
{
title: 'campaign-application:steps.organizer.title',
component: <CampaignApplicationOrganizer />,
},
{
title: 'campaign-application:steps.campaign-application.title',
component: <CampaignApplication />,
},
{
title: 'campaign-application:steps.campaign-application-details.title',
component: <CampaignApplicationDetails />,
},
]

export default function CampaignApplicationForm() {
const [activeStep, setActiveStep] = useState<Steps>(Steps.ORGANIZER)

const handleSubmit = () => {
stepsHandler({ activeStep, setActiveStep })
}

const handleBack = useCallback(() => {
setActiveStep((prevActiveStep) => prevActiveStep - 1)
}, [])

return (
<GenericForm<Record<string, string>> onSubmit={handleSubmit} initialValues={initialValues}>
<StyledCampaignApplicationStepper activeStep={activeStep} connector={<StyledStepConnector />}>
{steps.map((step) => (
<StyledCampaignApplicationStep key={step.title}>
<StepLabel StepIconComponent={CampaignApplicationStepperIcon} />
</StyledCampaignApplicationStep>
))}
</StyledCampaignApplicationStepper>
<ActionsContainer container spacing={5}>
<Grid container item xs={12}>
{activeStep < steps.length && steps[activeStep].component}
</Grid>
<Grid container item spacing={3}>
<CampaignApplicationFormActions activeStep={activeStep} onBack={handleBack} />
</Grid>
</ActionsContainer>
</GenericForm>
)
}
Original file line number Diff line number Diff line change
@@ -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 (
<Root container item xs={12} spacing={3} justifyContent="space-between">
<Grid item sx={{ textAlign: 'left' }}>
{activeStep === 0 ? (
<ActionLinkButton
href=""
variant="outlined"
startIcon={<ArrowBackIosIcon fontSize="small" />}>
{t('cta.back')}
</ActionLinkButton>
) : (
<ActionButton onClick={onBack} startIcon={<ArrowBackIosIcon fontSize="small" />}>
{t('cta.back')}
</ActionButton>
)}
</Grid>
<Grid item>
<ActionSubmitButton
label={t('cta.next')}
endIcon={<ArrowForwardIosIcon fontSize="small" />}
/>
</Grid>
</Root>
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import Layout from '../layout/Layout'
import CampaignApplicationForm from './CampaignApplicationForm'

export default function CampaignApplicationPage() {
return <Layout />
return (
<Layout maxWidth="md">
<CampaignApplicationForm />
</Layout>
)
}
Original file line number Diff line number Diff line change
@@ -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: <span>1</span>,
2: <span>2</span>,
3: <span>3</span>,
}

return (
<StyledCampaignApplicationStepperIcon>
{icons[String(props.icon)]}
</StyledCampaignApplicationStepperIcon>
)
}
Original file line number Diff line number Diff line change
@@ -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),
}))
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export type Step = {
title: string
component: JSX.Element
}

export enum Steps {
NONE = -1,
ORGANIZER = 0,
CAMPAIGN = 1,
CAMPAIGN_DETAILS = 2,
}
Original file line number Diff line number Diff line change
@@ -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,
}))
30 changes: 30 additions & 0 deletions src/components/client/campaign-application/helpers/stepsHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { SetStateAction } from 'react'

import { Steps } from './campaignApplication.types'

interface stepsHandlerProps {
activeStep: Steps
setActiveStep: (value: SetStateAction<Steps>) => 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'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function CampaignApplication() {
return <div>Campaign Application</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function CampaignApplicationDetails() {
return <div>Campaign Application Details</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function CampaignApplicationOrganizer() {
return <div>Campaign Application Organizer</div>
}
2 changes: 1 addition & 1 deletion src/pages/campaigns/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)

Expand Down

0 comments on commit f3a5aea

Please sign in to comment.