From 98aab5008a017dd1b45dd0d8db70faae1333caa9 Mon Sep 17 00:00:00 2001
From: gmeigniez-pass <139768952+gmeigniez-pass@users.noreply.github.com>
Date: Fri, 31 Jan 2025 15:02:30 +0100
Subject: [PATCH 1/2] (PC-34043)[PRO] feat: Let users create a digital offer on
a physical venue.
---
.../commons/__specs__/utils.spec.tsx | 100 ++++++----------
.../IndividualOfferDetails/commons/utils.ts | 54 ++-------
.../components/DetailsForm/DetailsForm.tsx | 32 +++--
.../IndividualOfferDetailsScreen.spec.tsx | 37 +++++-
.../IndividualOfferDetailsScreen.tsx | 25 ++--
.../UsefulInformationForm.tsx | 2 +-
.../__specs__/getFilteredVenueList.spec.ts | 112 ------------------
.../commons/getFilteredVenueList.ts | 39 ------
8 files changed, 112 insertions(+), 289 deletions(-)
delete mode 100644 pro/src/pages/IndividualOffer/commons/__specs__/getFilteredVenueList.spec.ts
delete mode 100644 pro/src/pages/IndividualOffer/commons/getFilteredVenueList.ts
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferDetails/commons/__specs__/utils.spec.tsx b/pro/src/pages/IndividualOffer/IndividualOfferDetails/commons/__specs__/utils.spec.tsx
index b6e6791c7d7..3f0586ef258 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferDetails/commons/__specs__/utils.spec.tsx
+++ b/pro/src/pages/IndividualOffer/IndividualOfferDetails/commons/__specs__/utils.spec.tsx
@@ -12,10 +12,9 @@ import {
buildShowSubTypeOptions,
completeSubcategoryConditionalFields,
buildSubcategoryOptions,
- buildVenueOptions,
+ formatVenuesOptions,
deSerializeDurationMinutes,
serializeExtraData,
- setDefaultInitialValues,
setDefaultInitialValuesFromOffer,
setFormReadOnlyFields,
serializeDetailsPostData,
@@ -150,69 +149,46 @@ describe('buildSubcategoryFields', () => {
})
})
-describe('buildVenueOptions', () => {
- it('should build venues options', () => {
- expect(
- buildVenueOptions(
- [venueListItemFactory({}), venueListItemFactory({})],
- false,
- false
- )
- ).toStrictEqual([
- {
- label: 'Sélectionner le partenaire',
- value: '',
- },
- {
- label: 'Le nom du lieu 1',
- value: '1',
- },
- {
- label: 'Le nom du lieu 2',
- value: '2',
- },
- ])
+describe('formatVenuesOptions', () => {
+ it('should format venues as options', () => {
+ const formattedVenuesOptions = formatVenuesOptions(
+ [
+ venueListItemFactory({ isVirtual: false, id: 10 }),
+ venueListItemFactory({ isVirtual: false, id: 3 }),
+ ],
+ false
+ )
+ expect(formattedVenuesOptions).toEqual(
+ expect.arrayContaining([expect.objectContaining({ value: '10' })])
+ )
+
+ expect(formattedVenuesOptions).toEqual(
+ expect.arrayContaining([expect.objectContaining({ value: '3' })])
+ )
})
-})
-describe('setDefaultInitialValues', () => {
- it('should set default initial values', () => {
- expect(
- setDefaultInitialValues({
- filteredVenues: [venueListItemFactory({}), venueListItemFactory({})],
- areSuggestedSubcategoriesUsed: false,
- })
- ).toStrictEqual({
- author: '',
- categoryId: '',
- description: '',
- durationMinutes: '',
- ean: '',
- gtl_id: '',
- name: '',
- performer: '',
- showSubType: '',
- showType: '',
- speaker: '',
- stageDirector: '',
- subcategoryConditionalFields: [],
- suggestedSubcategory: '',
- subcategoryId: '',
- venueId: '',
- visa: '',
- productId: '',
- callId: '',
- })
+ it('should exclude digital venues if a physcal venue is available', () => {
+ const formattedVenuesOptions = formatVenuesOptions(
+ [
+ venueListItemFactory({ isVirtual: true, id: 10 }),
+ venueListItemFactory({ isVirtual: false, id: 3 }),
+ ],
+ false
+ )
+ expect(formattedVenuesOptions).not.toEqual(
+ expect.arrayContaining([expect.objectContaining({ value: '10' })])
+ )
- expect(
- setDefaultInitialValues({
- filteredVenues: [venueListItemFactory({ id: 666 })],
- areSuggestedSubcategoriesUsed: false,
- })
- ).toStrictEqual(
- expect.objectContaining({
- venueId: '666',
- })
+ expect(formattedVenuesOptions).toEqual(
+ expect.arrayContaining([expect.objectContaining({ value: '3' })])
+ )
+
+ const formattedDigitalVenuesOptions = formatVenuesOptions(
+ [venueListItemFactory({ isVirtual: true, id: 10 })],
+ true
+ )
+ expect(formattedDigitalVenuesOptions).toEqual(
+ expect.arrayContaining([expect.objectContaining({ value: '10' })])
)
})
})
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferDetails/commons/utils.ts b/pro/src/pages/IndividualOffer/IndividualOfferDetails/commons/utils.ts
index 58c551d5c90..dcb1b0365cb 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferDetails/commons/utils.ts
+++ b/pro/src/pages/IndividualOffer/IndividualOfferDetails/commons/utils.ts
@@ -179,58 +179,22 @@ export const onSubcategoryChange = async ({
})
}
-export const buildVenueOptions = (
+export const formatVenuesOptions = (
venues: VenueListItemResponseModel[],
- areSuggestedCategoriesEnabled: boolean,
- isOfferAddressEnabled: boolean
+ isOnline: boolean
) => {
- let venueOptions = venues
- .filter((venue) => !areSuggestedCategoriesEnabled || !venue.isVirtual)
+ // We want to display the virtual venues only if there are no physical venues available
+ // We also want to prevent selecting a virtual venue for a physical offer form
+ const hasAtLeastOnePhysicalVenue = venues.some((v) => !v.isVirtual)
+ return venues
+ .filter((venue) =>
+ hasAtLeastOnePhysicalVenue || !isOnline ? !venue.isVirtual : true
+ )
.map((venue) => ({
value: venue.id.toString(),
label: computeVenueDisplayName(venue),
}))
.sort((a, b) => a.label.localeCompare(b.label, 'fr'))
- if (venueOptions.length > 1) {
- venueOptions = [
- {
- value: '',
- label: isOfferAddressEnabled
- ? 'Sélectionner la structure'
- : 'Sélectionner le partenaire',
- },
- ...venueOptions,
- ]
- }
-
- return venueOptions
-}
-
-type SetDefaultInitialValuesProps = {
- filteredVenues: VenueListItemResponseModel[]
- areSuggestedSubcategoriesUsed: boolean
-}
-
-export function setDefaultInitialValues({
- filteredVenues,
- areSuggestedSubcategoriesUsed,
-}: SetDefaultInitialValuesProps): DetailsFormValues {
- let venueId = ''
-
- const venues = areSuggestedSubcategoriesUsed
- ? filteredVenues.filter((v) => !v.isVirtual)
- : filteredVenues
-
- if (venues.length === 1) {
- venueId = String(venues[0].id)
- } else if (venues.length === 0 && filteredVenues.length > 0) {
- venueId = String(filteredVenues[0].id)
- }
-
- return {
- ...DEFAULT_DETAILS_FORM_VALUES,
- venueId,
- }
}
type SetDefaultInitialValuesFromOfferProps = {
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/DetailsForm/DetailsForm.tsx b/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/DetailsForm/DetailsForm.tsx
index 681d904c888..3002cbcf0e6 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/DetailsForm/DetailsForm.tsx
+++ b/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/DetailsForm/DetailsForm.tsx
@@ -7,7 +7,6 @@ import {
CategoryResponseModel,
SubcategoryResponseModel,
SuggestedSubcategoriesResponseModel,
- VenueListItemResponseModel,
} from 'apiClient/v1'
import { useIndividualOfferContext } from 'commons/context/IndividualOfferContext/IndividualOfferContext'
import { CATEGORY_STATUS } from 'commons/core/Offers/constants'
@@ -19,10 +18,7 @@ import { OnImageUploadArgs } from 'components/ImageUploader/components/ButtonIma
import fullMoreIcon from 'icons/full-more.svg'
import { DEFAULT_DETAILS_FORM_VALUES } from 'pages/IndividualOffer/IndividualOfferDetails/commons/constants'
import { DetailsFormValues } from 'pages/IndividualOffer/IndividualOfferDetails/commons/types'
-import {
- buildVenueOptions,
- isSubCategoryCD,
-} from 'pages/IndividualOffer/IndividualOfferDetails/commons/utils'
+import { isSubCategoryCD } from 'pages/IndividualOffer/IndividualOfferDetails/commons/utils'
import { Callout } from 'ui-kit/Callout/Callout'
import { CalloutVariant } from 'ui-kit/Callout/types'
import { Select } from 'ui-kit/form/Select/Select'
@@ -38,7 +34,7 @@ const DEBOUNCE_TIME_BEFORE_REQUEST = 400
type DetailsFormProps = {
isEanSearchDisplayed: boolean
isProductBased: boolean
- filteredVenues: VenueListItemResponseModel[]
+ venuesOptions: { label: string; value: string }[]
filteredCategories: CategoryResponseModel[]
filteredSubcategories: SubcategoryResponseModel[]
readonlyFields: string[]
@@ -50,7 +46,7 @@ type DetailsFormProps = {
export const DetailsForm = ({
isEanSearchDisplayed,
isProductBased,
- filteredVenues,
+ venuesOptions,
filteredCategories,
filteredSubcategories,
readonlyFields: readOnlyFields,
@@ -71,12 +67,6 @@ export const DetailsForm = ({
const { offer, subCategories } = useIndividualOfferContext()
const offerAddressEnabled = useActiveFeature('WIP_ENABLE_OFFER_ADDRESS')
- const venueOptions = buildVenueOptions(
- filteredVenues,
- areSuggestedSubcategoriesUsed,
- offerAddressEnabled
- )
-
async function getSuggestedSubcategories() {
if (!areSuggestedSubcategoriesUsed && !offer) {
return
@@ -131,14 +121,14 @@ export const DetailsForm = ({
subcategoryId !== DEFAULT_DETAILS_FORM_VALUES.subcategoryId
const showAddVenueBanner =
- !areSuggestedSubcategoriesUsed && venueOptions.length === 0
+ !areSuggestedSubcategoriesUsed && venuesOptions.length === 0
const isSuggestedSubcategoryDisplayed =
areSuggestedSubcategoriesUsed && !offer && !isProductBased
const showOtherAddVenueBanner =
areSuggestedSubcategoriesUsed &&
- venueOptions.length === 0 &&
+ venuesOptions.length === 0 &&
subcategory?.onlineOfflinePlatform === CATEGORY_STATUS.OFFLINE
return (
@@ -166,12 +156,18 @@ export const DetailsForm = ({
)}
{!showAddVenueBanner && (
<>
- {venueOptions.length > 1 && (
+ {venuesOptions.length > 1 && (
+ {(categoryStatus === CATEGORY_STATUS.ONLINE ||
+ offer?.isDigital) && (
+
+ Lien vers lequel seront renvoyés les bénéficiaires ayant
+ réservé votre offre sur l’application pass Culture.
+
+ }
+ >
+
+
+ )}
>
)}
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/IndividualOfferDetailsScreen.spec.tsx b/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/IndividualOfferDetailsScreen.spec.tsx
index c74f06a821e..030a5e2ec64 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/IndividualOfferDetailsScreen.spec.tsx
+++ b/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/IndividualOfferDetailsScreen.spec.tsx
@@ -470,6 +470,7 @@ describe('IndividualOfferDetails', () => {
subcategoryId: 'physical',
venueId: 189,
callId: '',
+ url: null,
})
expect(mockNavigate).toHaveBeenCalledWith(
'/offre/individuelle/12/creation/details',
@@ -668,6 +669,7 @@ describe('IndividualOfferDetails', () => {
subcategoryId: 'physical',
venueId: 189,
callId: MOCK_DATA.suggestedSubcatCallId,
+ url: null,
})
})
})
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/IndividualOfferDetailsScreen.tsx b/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/IndividualOfferDetailsScreen.tsx
index da9b23cc321..ff165f6d98c 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/IndividualOfferDetailsScreen.tsx
+++ b/pro/src/pages/IndividualOffer/IndividualOfferDetails/components/IndividualOfferDetailsScreen.tsx
@@ -100,7 +100,7 @@ export const IndividualOfferDetailsScreen = ({
const availableVenuesOptions = formatVenuesOptions(
venues,
- categoryStatus === CATEGORY_STATUS.ONLINE
+ categoryStatus === CATEGORY_STATUS.ONLINE || Boolean(offer?.isDigital)
)
const areSuggestedSubcategoriesUsed = useSuggestedSubcategoriesAbTest()
@@ -194,10 +194,13 @@ export const IndividualOfferDetailsScreen = ({
formik.setStatus('apiError')
}
}
-
const formik = useFormik({
initialValues,
- validationSchema: getValidationSchema({ isOfferAddressEnabled }),
+ validationSchema: getValidationSchema({
+ isOfferAddressEnabled,
+ isDigitalOffer:
+ categoryStatus === CATEGORY_STATUS.ONLINE || Boolean(offer?.isDigital),
+ }),
onSubmit,
})
const handlePreviousStepOrBackToReadOnly = () => {
@@ -322,11 +325,12 @@ export const IndividualOfferDetailsScreen = ({
isProductBased={isProductBased}
filteredCategories={filteredCategories}
filteredSubcategories={filteredSubcategories}
- readonlyFields={readOnlyFields}
+ readOnlyFields={readOnlyFields}
onImageUpload={onImageUpload}
onImageDelete={onImageDelete}
imageOffer={imageOffer}
venuesOptions={availableVenuesOptions}
+ categoryStatus={categoryStatus}
/>
{
const expectedValues = {
isEvent: true,
isNational: false,
- isVenueVirtual: false,
withdrawalDetails: 'Detailed info',
withdrawalDelay: 3,
withdrawalType: WithdrawalTypeEnum.BY_EMAIL,
@@ -43,7 +42,6 @@ describe('setDefaultInitialValuesFromOffer', () => {
bookingEmail: 'test@example.com',
bookingContact: 'Contact Info',
receiveNotificationEmails: true,
- url: 'http://example.com',
}
const result = setDefaultInitialValuesFromOffer({ offer: mockOffer })
@@ -64,7 +62,6 @@ describe('setDefaultInitialValuesFromOffer', () => {
const expectedValues = {
isEvent: false,
isNational: true,
- isVenueVirtual: false,
withdrawalDetails:
DEFAULT_USEFUL_INFORMATION_INITIAL_VALUES['withdrawalDetails'],
withdrawalDelay: undefined,
@@ -79,7 +76,6 @@ describe('setDefaultInitialValuesFromOffer', () => {
bookingEmail: '',
bookingContact: undefined,
receiveNotificationEmails: false,
- url: DEFAULT_USEFUL_INFORMATION_INITIAL_VALUES['url'],
}
const result = setDefaultInitialValuesFromOffer({
@@ -102,7 +98,6 @@ describe('setDefaultInitialValuesFromOffer', () => {
const expectedValues = {
isEvent: false,
isNational: true,
- isVenueVirtual: false,
withdrawalDetails:
DEFAULT_USEFUL_INFORMATION_INITIAL_VALUES['withdrawalDetails'],
withdrawalDelay: undefined,
@@ -117,7 +112,6 @@ describe('setDefaultInitialValuesFromOffer', () => {
bookingEmail: '',
bookingContact: undefined,
receiveNotificationEmails: false,
- url: DEFAULT_USEFUL_INFORMATION_INITIAL_VALUES['url'],
}
const result = setDefaultInitialValuesFromOffer({
@@ -167,7 +161,6 @@ describe('setDefaultInitialValuesFromOffer', () => {
const expectedValues = {
isEvent: true,
isNational: false,
- isVenueVirtual: false,
withdrawalDetails: 'Detailed info',
withdrawalDelay: 3,
withdrawalType: WithdrawalTypeEnum.BY_EMAIL,
@@ -181,7 +174,6 @@ describe('setDefaultInitialValuesFromOffer', () => {
bookingEmail: 'test@example.com',
bookingContact: 'Contact Info',
receiveNotificationEmails: true,
- url: 'http://example.com',
offerLocation: OFFER_LOCATION.OTHER_ADDRESS,
manuallySetAddress: true,
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/__specs__/validationSchema.spec.tsx b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/__specs__/validationSchema.spec.tsx
index b1125ac1111..ae2051aefe0 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/__specs__/validationSchema.spec.tsx
+++ b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/__specs__/validationSchema.spec.tsx
@@ -46,27 +46,6 @@ describe('getValidationSchema', () => {
).rejects.toThrow('Vous devez choisir l’une des options ci-dessus')
})
- it('should validate url correctly when isVenueVirtual is true', async () => {
- const schema = getValidationSchema({ subcategories: [] })
- await expect(
- schema.validate({
- ...defaultAccessibility,
- isVenueVirtual: true,
- url: 'https://example.com',
- })
- ).resolves.toBeTruthy()
-
- await expect(
- schema.validate({
- ...defaultAccessibility,
- isVenueVirtual: true,
- url: 'invalid-url',
- })
- ).rejects.toThrow(
- 'Veuillez renseigner une URL valide. Ex : https://exemple.com'
- )
- })
-
it('should validate bookingContact correctly', async () => {
const schema = getValidationSchema({ subcategories: ['bookingContact'] })
await expect(
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/constants.ts b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/constants.ts
index f49e4f0ac50..e0c43711585 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/constants.ts
+++ b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/constants.ts
@@ -13,7 +13,6 @@ export const DEFAULT_USEFUL_INFORMATION_INITIAL_VALUES: UsefulInformationFormVal
withdrawalDelay: SUBCATEGORIES_FIELDS_DEFAULT_VALUES['withdrawalDelay'],
receiveNotificationEmails: false,
bookingEmail: '',
- url: '',
accessibility: {
[AccessibilityEnum.VISUAL]: false,
[AccessibilityEnum.MENTAL]: false,
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/types.ts b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/types.ts
index 4db5765bb23..91151a14ecb 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/types.ts
+++ b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/types.ts
@@ -10,10 +10,7 @@ export type UsefulInformationFormValues = {
accessibility: AccessibilityFormValues
receiveNotificationEmails: boolean
bookingEmail: string
- url: string
- isVenueVirtual?: boolean
bookingContact?: string
-
offerLocation?: string | undefined
manuallySetAddress?: boolean
'search-addressAutocomplete'?: string
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/utils.ts b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/utils.ts
index 9f8ab93e3ba..04c5e43abe0 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/utils.ts
+++ b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/utils.ts
@@ -67,7 +67,7 @@ export function setDefaultInitialValuesFromOffer({
latitude: String(offer.address.latitude),
longitude: String(offer.address.longitude),
}
- } else if (selectedVenue && selectedVenue.address) {
+ } else if (!offer.isDigital && selectedVenue && selectedVenue.address) {
addressFields = {
offerLocation: String(selectedVenue.address.id_oa),
coords: `${selectedVenue.address.latitude}, ${selectedVenue.address.longitude}`,
@@ -100,8 +100,6 @@ export function setDefaultInitialValuesFromOffer({
bookingEmail: offer.bookingEmail || '',
bookingContact: offer.bookingContact || undefined,
receiveNotificationEmails: !!offer.bookingEmail,
- url: offer.url || DEFAULT_USEFUL_INFORMATION_INITIAL_VALUES['url'],
- isVenueVirtual: offer.venue.isVirtual || false,
...addressFields,
}
}
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/validationSchema.ts b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/validationSchema.ts
index 4f7eeaf9e3b..6c8927c5954 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/validationSchema.ts
+++ b/pro/src/pages/IndividualOffer/IndividualOfferInformations/commons/validationSchema.ts
@@ -3,15 +3,7 @@ import * as yup from 'yup'
import { WithdrawalTypeEnum } from 'apiClient/v1'
import { emailSchema } from 'commons/utils/isValidEmail'
-import { validationSchema as offerLocationSchema } from '../components/OfferLocation/validationSchema'
-
-// TODO: this regex is subject to backtracking which can lead to "catastrophic backtracking", high memory usage and slow performance
-// we cannot use the yup url validation because we need to allow {} in the url to interpolate some data
-const offerFormUrlRegex = new RegExp(
- /*eslint-disable-next-line no-useless-escape*/
- /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)(([a-z0-9]+([\-\.\.-\.@_a-z0-9]+)*\.[a-z]{2,5})|((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.){3}(25[0-5]|(2[0-4]|1\d|[1-9]|)\d))(:[0-9]{1,5})?\S*?$/,
- 'i'
-)
+import { validationSchema as locationSchema } from '../components/OfferLocation/validationSchema'
const isAnyTrue = (values: Record): boolean =>
Object.values(values).includes(true)
@@ -19,10 +11,12 @@ const isAnyTrue = (values: Record): boolean =>
type ValidationSchemaProps = {
subcategories: string[]
isOfferAddressEnabled?: boolean
+ isDigitalOffer?: boolean
}
export const getValidationSchema = ({
subcategories,
isOfferAddressEnabled = false,
+ isDigitalOffer = false,
}: ValidationSchemaProps) => {
const validationSchema = {
withdrawalType: yup.string().when([], {
@@ -41,21 +35,6 @@ export const getValidationSchema = ({
then: (schema) =>
schema.required('Vous devez choisir l’une des options ci-dessus'),
}),
- url: yup.string().when('isVenueVirtual', {
- is: (isVenueVirtual: boolean) => isVenueVirtual,
- then: (schema) =>
- schema
- .required(
- 'Veuillez renseigner une URL valide. Ex : https://exemple.com'
- )
- .test({
- name: 'url',
- message:
- 'Veuillez renseigner une URL valide. Ex : https://exemple.com',
- test: (url?: string) =>
- url ? url.match(offerFormUrlRegex) !== null : true,
- }),
- }),
bookingContact: yup.string().when([], {
is: () => subcategories.includes('bookingContact'),
then: (schema) =>
@@ -96,6 +75,6 @@ export const getValidationSchema = ({
return yup.object().shape({
...validationSchema,
- ...(isOfferAddressEnabled ? offerLocationSchema : {}),
+ ...(isOfferAddressEnabled && !isDigitalOffer ? locationSchema : {}),
})
}
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/IndividualOfferInformationsScreen.tsx b/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/IndividualOfferInformationsScreen.tsx
index 5d694a72779..7bee29d5114 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/IndividualOfferInformationsScreen.tsx
+++ b/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/IndividualOfferInformationsScreen.tsx
@@ -198,12 +198,12 @@ export const IndividualOfferInformationsScreen = ({
offerSubCategory,
isUserAdmin: false,
receiveNotificationEmails: true,
- isVenueVirtual: offer.venue.isVirtual,
})
const validationSchema = getValidationSchema({
subcategories: conditionalFields,
isOfferAddressEnabled,
+ isDigitalOffer: offer.isDigital,
})
const initialValues = setDefaultInitialValuesFromOffer({
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/OfferLocation/validationSchema.ts b/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/OfferLocation/validationSchema.ts
index b4f36242faf..511a0307d62 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/OfferLocation/validationSchema.ts
+++ b/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/OfferLocation/validationSchema.ts
@@ -4,25 +4,13 @@ import { checkCoords } from 'commons/utils/coords'
import { OFFER_LOCATION } from 'pages/IndividualOffer/commons/constants'
const locationSchema = {
- offerLocation: yup
- .string()
- .trim()
- .when('isVenueVirtual', {
- is: false,
- then: (schema) => schema.required('Veuillez sélectionner un choix'),
- }),
+ offerLocation: yup.string().trim().required('Veuillez sélectionner un choix'),
addressAutocomplete: yup
.string()
.trim()
- .when(['offerLocation', 'manuallySetAddress', 'isVenueVirtual'], {
- is: (
- offerLocation: string,
- manuallySetAddress: boolean,
- isVenueVirtual: boolean
- ) =>
- !isVenueVirtual &&
- offerLocation === OFFER_LOCATION.OTHER_ADDRESS &&
- !manuallySetAddress,
+ .when(['offerLocation', 'manuallySetAddress'], {
+ is: (offerLocation: string, manuallySetAddress: boolean) =>
+ offerLocation === OFFER_LOCATION.OTHER_ADDRESS && !manuallySetAddress,
then: (schema) =>
schema.required(
'Veuillez sélectionner une adresse parmi les suggestions'
@@ -31,18 +19,18 @@ const locationSchema = {
street: yup
.string()
.trim()
- .when(['offerLocation', 'isVenueVirtual'], {
- is: (offerLocation: string, isVenueVirtual: boolean) =>
- !isVenueVirtual && offerLocation === OFFER_LOCATION.OTHER_ADDRESS,
+ .when(['offerLocation'], {
+ is: (offerLocation: string) =>
+ offerLocation === OFFER_LOCATION.OTHER_ADDRESS,
then: (schema) =>
schema.required('Veuillez renseigner une adresse postale'),
}),
postalCode: yup
.string()
.trim()
- .when(['offerLocation', 'isVenueVirtual'], {
- is: (offerLocation: string, isVenueVirtual: boolean) =>
- !isVenueVirtual && offerLocation === OFFER_LOCATION.OTHER_ADDRESS,
+ .when(['offerLocation'], {
+ is: (offerLocation: string) =>
+ offerLocation === OFFER_LOCATION.OTHER_ADDRESS,
then: (schema) => schema.required('Veuillez renseigner un code postal'),
})
.min(5, 'Veuillez renseigner un code postal valide')
@@ -50,23 +38,17 @@ const locationSchema = {
city: yup
.string()
.trim()
- .when(['offerLocation', 'isVenueVirtual'], {
- is: (offerLocation: string, isVenueVirtual: boolean) =>
- !isVenueVirtual && offerLocation === OFFER_LOCATION.OTHER_ADDRESS,
+ .when(['offerLocation'], {
+ is: (offerLocation: string) =>
+ offerLocation === OFFER_LOCATION.OTHER_ADDRESS,
then: (schema) => schema.required('Veuillez renseigner une ville'),
}),
coords: yup
.string()
.trim()
- .when(['offerLocation', 'manuallySetAddress', 'isVenueVirtual'], {
- is: (
- offerLocation: string,
- manuallySetAddress: boolean,
- isVenueVirtual: boolean
- ) =>
- !isVenueVirtual &&
- offerLocation === OFFER_LOCATION.OTHER_ADDRESS &&
- manuallySetAddress,
+ .when(['offerLocation', 'manuallySetAddress'], {
+ is: (offerLocation: string, manuallySetAddress: boolean) =>
+ offerLocation === OFFER_LOCATION.OTHER_ADDRESS && manuallySetAddress,
then: (schema) =>
schema
.required('Veuillez renseigner les coordonnées GPS')
diff --git a/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/UsefulInformationForm/UsefulInformationForm.tsx b/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/UsefulInformationForm/UsefulInformationForm.tsx
index c24a76c372d..9c2fd9ef49a 100644
--- a/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/UsefulInformationForm/UsefulInformationForm.tsx
+++ b/pro/src/pages/IndividualOffer/IndividualOfferInformations/components/UsefulInformationForm/UsefulInformationForm.tsx
@@ -68,10 +68,6 @@ export const UsefulInformationForm = ({
? Object.keys(DEFAULT_USEFUL_INFORMATION_INITIAL_VALUES)
: setFormReadOnlyFields(offer)
- // we use venue is virtual here because we cannot infer it from the offerSubCategory
- // because of CATEGORY_STATUS.ONLINE_OR_OFFLINE who can be both virtual or not
- const isVenueVirtual = venue.isVirtual
-
const {
currentUser: { isAdmin, email },
} = useCurrentUser()
@@ -80,7 +76,7 @@ export const UsefulInformationForm = ({
offerSubCategory?.reimbursementRule === REIMBURSEMENT_RULES.NOT_REIMBURSED
const displayWithdrawalReminder =
- !offerSubCategory?.isEvent && !isVenueVirtual
+ !offerSubCategory?.isEvent && !offer.isDigital
const displayBookingContact = offerSubCategory?.canBeWithdrawable
@@ -103,7 +99,7 @@ export const UsefulInformationForm = ({
return (
<>
- {isOfferAddressEnabled && !isVenueVirtual && (
+ {isOfferAddressEnabled && !offer.isDigital && (
)}
@@ -185,7 +181,7 @@ export const UsefulInformationForm = ({
text: 'Quelles modalités de retrait choisir ?',
}}
>
- {isVenueVirtual
+ {offer.isDigital
? 'Indiquez ici tout ce qui peut être utile au bénéficiaire pour le retrait de l’offre.'
: 'Indiquez ici tout ce qui peut être utile au bénéficiaire pour le retrait de l’offre. En renseignant ces informations depuis les paramètres généraux de votre page partenaire, elles s’appliqueront par défaut à toutes vos offres.'}
@@ -198,7 +194,7 @@ export const UsefulInformationForm = ({
maxLength={500}
disabled={readOnlyFields.includes('withdrawalDetails')}
description={
- isVenueVirtual
+ offer.isDigital
? 'Exemples : une création de compte, un code d’accès spécifique, une communication par email...'
: 'Exemples : une autre adresse, un horaire d’accès, un délai de retrait, un guichet spécifique, un code d’accès, une communication par email...'
}
@@ -224,25 +220,6 @@ export const UsefulInformationForm = ({
/>
)}
-
- {isVenueVirtual && (
-
- Lien vers lequel seront renvoyés les bénéficiaires ayant réservé
- votre offre sur l’application pass Culture.
-
- }
- >
-
-
- )}
{isAdmin && (
{
bookingContact: undefined,
isDuo: false,
url: 'https://my.url',
- isVenueVirtual: false,
city: 'Paris',
latitude: '48.853320',
longitude: '2.348979',
diff --git a/pro/src/pages/IndividualOffer/commons/types.ts b/pro/src/pages/IndividualOffer/commons/types.ts
index 507396a836e..1ad1b79f02a 100644
--- a/pro/src/pages/IndividualOffer/commons/types.ts
+++ b/pro/src/pages/IndividualOffer/commons/types.ts
@@ -33,7 +33,6 @@ export interface IndividualOfferFormValues extends Partial {
bookingEmail: string
isDuo: boolean
url: string
- isVenueVirtual?: boolean
bookingContact?: string
offerLocation?: string | undefined
locationLabel?: string | null