Skip to content

Commit

Permalink
(PC-19516)[PRO] feat: add price categories form
Browse files Browse the repository at this point in the history
  • Loading branch information
AlbericTrancart committed Jan 23, 2023
1 parent 1c9ffc5 commit a0740f6
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const validationSchema = {
.string()
.oneOf(
Object.values(WithdrawalTypeEnum),
'Vous devez cocher l’une des options ci-dessuss'
'Vous devez cocher l’une des options ci-dessus'
)
.required('Vous devez cocher l’une des options ci-dessus'),
otherwise: yup.string(),
Expand Down
37 changes: 15 additions & 22 deletions pro/src/screens/OfferIndividual/PriceCategories/PriceCategories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* istanbul ignore: DEBT, TO FIX */
import { FormikProvider, useFormik } from 'formik'
import { FormikProvider } from 'formik'
import React from 'react'

import FormLayout from 'components/FormLayout'
Expand All @@ -10,23 +9,17 @@ import { useNavigate, useOfferWizardMode } from 'hooks'

import { ActionBar } from '../ActionBar'

import { usePriceCategoriesForm } from './form/useForm'
import { PriceCategoriesForm } from './PriceCategoriesForm'

export interface IPriceCategories {
offer: IOfferIndividual
}

const PriceCategories = ({ offer }: IPriceCategories): JSX.Element => {
const navigate = useNavigate()
const mode = useOfferWizardMode()

const onSubmit = async (formValues: Record<string, any>) => {
/* eslint-disable-next-line */
console.log('submit !', formValues)
}

const formik = useFormik({
initialValues: {},
onSubmit,
})
const formik = usePriceCategoriesForm()

const handlePreviousStep = () => {
navigate(
Expand All @@ -41,16 +34,16 @@ const PriceCategories = ({ offer }: IPriceCategories): JSX.Element => {
return (
<FormikProvider value={formik}>
<FormLayout>
<FormLayout.Section title="Tarifs">
<form onSubmit={formik.handleSubmit}>
<ActionBar
onClickPrevious={handlePreviousStep}
step={OFFER_WIZARD_STEP_IDS.STOCKS}
isDisabled={formik.isSubmitting}
offerId={offer.id}
/>
</form>
</FormLayout.Section>
<form onSubmit={formik.handleSubmit}>
<PriceCategoriesForm values={formik.values} />

<ActionBar
onClickPrevious={handlePreviousStep}
step={OFFER_WIZARD_STEP_IDS.STOCKS}
isDisabled={formik.isSubmitting}
offerId={offer.id}
/>
</form>
</FormLayout>
</FormikProvider>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@use "styles/mixins/_rem.scss" as rem;

.label-input {
width: rem.torem(320px);
}

.price-input {
width: rem.torem(180px);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { FieldArray } from 'formik'
import React from 'react'

import FormLayout from 'components/FormLayout'
import { IcoEuro } from 'icons'
import { TextInput } from 'ui-kit'

import {
PRICE_CATEGORY_LABEL_MAX_LENGTH,
PRICE_CATEGORY_PRICE_MAX,
} from './form/constants'
import { PriceCategoriesFormValues } from './form/types'
import styles from './PriceCategoriesForm.module.scss'

type PriceCategoriesFormProps = {
values: PriceCategoriesFormValues
}

export const PriceCategoriesForm = ({
values,
}: PriceCategoriesFormProps): JSX.Element => {
return (
<FieldArray
name="priceCategories"
render={() => (
<FormLayout.Section title="Tarifs">
{values.priceCategories.map((priceCategory, index) => (
<FormLayout.Row key={index} inline>
<TextInput
name={`priceCategories[${index}].label`}
label="Intitulé du tarif"
placeholder="Ex : catégorie 1, orchestre..."
maxLength={PRICE_CATEGORY_LABEL_MAX_LENGTH}
countCharacters
className={styles['label-input']}
/>
<TextInput
name={`priceCategories[${index}].price`}
label="Tarif par personne"
placeholder="Ex : 25€"
type="number"
step="0.01"
max={PRICE_CATEGORY_PRICE_MAX}
rightIcon={() => <IcoEuro />}
className={styles['price-input']}
/>
</FormLayout.Row>
))}
</FormLayout.Section>
)}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { render, screen } from '@testing-library/react'
import React from 'react'
import { Provider } from 'react-redux'
import { MemoryRouter } from 'react-router'

import { configureTestStore } from 'store/testUtils'
import { individualOfferFactory } from 'utils/individualApiFactories'

import PriceCategories, { IPriceCategories } from '../PriceCategories'

const renderPriceCategories = (props: IPriceCategories) => {
const store = configureTestStore()

return render(
<Provider store={store}>
<MemoryRouter>
<PriceCategories {...props} />
</MemoryRouter>
</Provider>
)
}

describe('PriceCategories', () => {
it('should render without error', () => {
renderPriceCategories({ offer: individualOfferFactory() })

screen.getByText('Tarifs')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { render, screen } from '@testing-library/react'
import { Formik } from 'formik'
import React from 'react'

import { priceCategoryFormFactory } from '../form/factories'
import { PriceCategoriesFormValues } from '../form/types'
import { PriceCategoriesForm } from '../PriceCategoriesForm'

describe('PriceCategories', () => {
it('should render without error', () => {
const values: PriceCategoriesFormValues = {
priceCategories: [
priceCategoryFormFactory(),
priceCategoryFormFactory(),
priceCategoryFormFactory(),
],
isDuo: false,
}

render(
<Formik initialValues={values} onSubmit={jest.fn()}>
<PriceCategoriesForm values={values} />
</Formik>
)

expect(screen.getAllByText('Intitulé du tarif')).toHaveLength(3)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { PriceCategoriesFormValues } from './types'

export const computeInitialValues = (): PriceCategoriesFormValues => {
return {
priceCategories: [
{
label: '',
price: '',
},
],
isDuo: true,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const PRICE_CATEGORY_LABEL_MAX_LENGTH = 20

export const PRICE_CATEGORY_PRICE_MAX = 300
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { PriceCategoryForm } from './types'

let priceCategoryFormId = 1
export const priceCategoryFormFactory = (): PriceCategoryForm => ({
label: `Tarif ${priceCategoryFormId++}`,
price: 20,
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { PriceCategoriesFormValues } from './types'

export const onSubmit = (values: PriceCategoriesFormValues) => {
// eslint-disable-next-line no-console
console.log('submit !', values)
}
15 changes: 15 additions & 0 deletions pro/src/screens/OfferIndividual/PriceCategories/form/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Don't know why but eslint doesn't like the import of FormikProps but it exists trust me
// eslint-disable-next-line import/named
import { FormikProps } from 'formik'

export type PriceCategoryForm = {
label: string
price: number | ''
}

export type PriceCategoriesFormValues = {
priceCategories: PriceCategoryForm[]
isDuo: boolean
}

export type PriceCategoriesFormType = FormikProps<PriceCategoriesFormValues>
18 changes: 18 additions & 0 deletions pro/src/screens/OfferIndividual/PriceCategories/form/useForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useFormik } from 'formik'

import { computeInitialValues } from './computeInitialValues'
import { onSubmit } from './onSubmit'
import { PriceCategoriesFormValues } from './types'
import { validationSchema } from './validationSchema'

export const usePriceCategoriesForm = () => {
const initialValues = computeInitialValues()

const form = useFormik<PriceCategoriesFormValues>({
initialValues,
validationSchema,
onSubmit,
})

return form
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as yup from 'yup'

import {
PRICE_CATEGORY_LABEL_MAX_LENGTH,
PRICE_CATEGORY_PRICE_MAX,
} from './constants'

export const priceCategoryValidationSchema = yup.object().shape({
label: yup
.string()
.required('Veuillez renseigner un intitulé de tarif')
.max(PRICE_CATEGORY_LABEL_MAX_LENGTH, 'Le nom du tarif est trop long'),
price: yup
.number()
.required('Veuillez renseigner un tarif')
.positive()
.max(
PRICE_CATEGORY_PRICE_MAX,
`Veuillez renseigner un tarif inférieur à ${PRICE_CATEGORY_PRICE_MAX}€`
),
})

export const validationSchema = yup.object().shape({
priceCategories: yup
.array()
.of(priceCategoryValidationSchema)
.required()
.min(1),
isDuo: yup.boolean(),
})

0 comments on commit a0740f6

Please sign in to comment.