Skip to content

Commit

Permalink
(PC-30787)[PRO] feat: can duplicate and can create bookable offer in …
Browse files Browse the repository at this point in the history
…eac offer
  • Loading branch information
smokhtari-passculture committed Oct 21, 2024
1 parent 116db2c commit 100af2e
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { useSWRConfig } from 'swr'

import { api } from 'apiClient/api'
import {
CollectiveOfferAllowedAction,
CollectiveOfferDisplayedStatus,
CollectiveOfferStatus,
CollectiveOfferTemplateAllowedAction,
GetCollectiveOfferResponseModel,
GetCollectiveOfferTemplateResponseModel,
} from 'apiClient/v1'
Expand All @@ -28,19 +30,22 @@ import {
isCollectiveOfferTemplate,
} from 'core/OfferEducational/types'
import { computeURLCollectiveOfferId } from 'core/OfferEducational/utils/computeURLCollectiveOfferId'
import { createOfferFromBookableOffer } from 'core/OfferEducational/utils/createOfferFromBookableOffer'
import { createOfferFromTemplate } from 'core/OfferEducational/utils/createOfferFromTemplate'
import { useActiveFeature } from 'hooks/useActiveFeature'
import { useNotification } from 'hooks/useNotification'
import { useOfferStockEditionURL } from 'hooks/useOfferEditionURL'
import fullArchiveIcon from 'icons/full-archive.svg'
import fullMoreIcon from 'icons/full-more.svg'
import fullCopyIcon from 'icons/full-duplicate.svg'
import fullPlusIcon from 'icons/full-plus.svg'
import fullShowIcon from 'icons/full-show.svg'
import { selectCurrentOffererId } from 'store/user/selectors'
import { Button } from 'ui-kit/Button/Button'
import { ButtonLink } from 'ui-kit/Button/ButtonLink'
import { ButtonVariant } from 'ui-kit/Button/types'
import { Divider } from 'ui-kit/Divider/Divider'
import { Tabs } from 'ui-kit/Tabs/Tabs'
import { isActionAllowedOnCollectiveOffer } from 'utils/isActionAllowedOnCollectiveOffer'

import styles from './CollectiveOfferNavigation.module.scss'

Expand Down Expand Up @@ -83,6 +88,9 @@ export const CollectiveOfferNavigation = ({
const navigate = useNavigate()
const location = useLocation()
const isMarseilleActive = useActiveFeature('WIP_ENABLE_MARSEILLE')
const areCollectiveNewStatusesEnabled = useActiveFeature(
'ENABLE_COLLECTIVE_NEW_STATUSES'
)
const selectedOffererId = useSelector(selectCurrentOffererId)

const { mutate } = useSWRConfig()
Expand Down Expand Up @@ -236,6 +244,17 @@ export const CollectiveOfferNavigation = ({
}
}

const canDuplicateOffer = offer
? areCollectiveNewStatusesEnabled
? isActionAllowedOnCollectiveOffer(
offer,
isTemplate
? CollectiveOfferTemplateAllowedAction.CAN_CREATE_BOOKABLE_OFFER
: CollectiveOfferAllowedAction.CAN_DUPLICATE
)
: isTemplate
: false

return isEditingExistingOffer ? (
<>
<div className={styles['duplicate-offer']}>
Expand All @@ -255,28 +274,32 @@ export const CollectiveOfferNavigation = ({
</Button>
)}

{isTemplate && (
{canDuplicateOffer && (
<Button
variant={ButtonVariant.TERNARY}
icon={fullMoreIcon}
onClick={() => {
logEvent(Events.CLICKED_DUPLICATE_TEMPLATE_OFFER, {
from: OFFER_FROM_TEMPLATE_ENTRIES.OFFER_TEMPLATE_RECAP,
offererId: selectedOffererId?.toString(),
offerId,
offerType: 'collective',
})
// eslint-disable-next-line @typescript-eslint/no-floating-promises
createOfferFromTemplate(
navigate,
notify,
offerId,
undefined,
isMarseilleActive
)
icon={isTemplate ? fullPlusIcon : fullCopyIcon}
onClick={async () => {
if (isTemplate) {
logEvent(Events.CLICKED_DUPLICATE_TEMPLATE_OFFER, {
from: OFFER_FROM_TEMPLATE_ENTRIES.OFFER_TEMPLATE_RECAP,
offererId: selectedOffererId?.toString(),
offerId,
offerType: 'collective',
})
// eslint-disable-next-line @typescript-eslint/no-floating-promises
createOfferFromTemplate(
navigate,
notify,
offerId,
undefined,
isMarseilleActive
)
} else {
await createOfferFromBookableOffer(navigate, notify, offerId)
}
}}
>
Créer une offre réservable
{isTemplate ? 'Créer une offre réservable' : 'Dupliquer'}
</Button>
)}
</div>
Expand Down
6 changes: 4 additions & 2 deletions pro/src/core/OfferEducational/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,15 @@ export const isCollectiveOffer = (
value: unknown
): value is GetCollectiveOfferResponseModel =>
// Could be enhanced to check that it is also a GetCollectiveOfferTemplateResponseModel
hasProperty(value, 'isTemplate') && value.isTemplate === false
(hasProperty(value, 'isTemplate') && value.isTemplate === false) ||
(hasProperty(value, 'isShowcase') && value.isShowcase === false)

export const isCollectiveOfferTemplate = (
value: unknown
): value is GetCollectiveOfferTemplateResponseModel =>
// Could be enhanced to check that it is also a GetCollectiveOfferTemplateResponseModel
hasProperty(value, 'isTemplate') && value.isTemplate === true
(hasProperty(value, 'isTemplate') && value.isTemplate === true) ||
(hasProperty(value, 'isShowcase') && value.isShowcase === true)

export type VisibilityFormValues = {
visibility: 'all' | 'one'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { api } from 'apiClient/api'
import { getErrorCode, isErrorAPIError } from 'apiClient/helpers'
import {
CollectiveBookingStatus,
CollectiveOfferAllowedAction,
CollectiveOfferResponseModel,
CollectiveOfferStatus,
CollectiveOfferTemplateAllowedAction,
} from 'apiClient/v1'
import { useAnalytics } from 'app/App/analytics/firebase'
import { ArchiveConfirmationModal } from 'components/ArchiveConfirmationModal/ArchiveConfirmationModal'
Expand Down Expand Up @@ -47,6 +49,7 @@ import {
formatBrowserTimezonedDateAsUTC,
isDateValid,
} from 'utils/date'
import { isActionAllowedOnCollectiveOffer } from 'utils/isActionAllowedOnCollectiveOffer'
import { localStorageAvailable } from 'utils/localStorageAvailable'

import { BookingLinkCell } from './BookingLinkCell'
Expand Down Expand Up @@ -90,6 +93,9 @@ export const CollectiveActionsCells = ({
const isNewOffersAndBookingsActive = useActiveFeature(
'WIP_ENABLE_NEW_COLLECTIVE_OFFERS_AND_BOOKINGS_STRUCTURE'
)
const areCollectiveNewStatusesEnabled = useActiveFeature(
'ENABLE_COLLECTIVE_NEW_STATUSES'
)

const collectiveOffersQueryKeys = getCollectiveOffersSwrKeys({
isNewOffersAndBookingsActive,
Expand Down Expand Up @@ -225,7 +231,14 @@ export const CollectiveActionsCells = ({
})
}

const canDuplicateOffer = offer.status !== CollectiveOfferStatus.DRAFT
const canDuplicateOffer = areCollectiveNewStatusesEnabled
? isActionAllowedOnCollectiveOffer(
offer,
offer.isShowcase
? CollectiveOfferTemplateAllowedAction.CAN_CREATE_BOOKABLE_OFFER
: CollectiveOfferAllowedAction.CAN_DUPLICATE
)
: offer.status !== CollectiveOfferStatus.DRAFT

return (
<td
Expand Down
56 changes: 56 additions & 0 deletions pro/src/utils/__specs__/isActionsAllowedOnCollectiveOffer.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {
CollectiveOfferAllowedAction,
CollectiveOfferTemplateAllowedAction,
} from 'apiClient/v1'
import {
getCollectiveOfferFactory,
getCollectiveOfferTemplateFactory,
} from 'utils/collectiveApiFactories'
import { isActionAllowedOnCollectiveOffer } from 'utils/isActionAllowedOnCollectiveOffer'

describe('isActionAllowedOnCollectiveOffer', () => {
it.each([
{
description: 'allowed action CAN_DUPLICATE on bookable offer ',
offer: getCollectiveOfferFactory({
allowedActions: [CollectiveOfferAllowedAction.CAN_DUPLICATE],
}),
action: CollectiveOfferAllowedAction.CAN_DUPLICATE,
expected: true,
},
{
description: 'allowed action CAN_CREATE_BOOKABLE_OFFER on template offer',
offer: getCollectiveOfferTemplateFactory({
allowedActions: [
CollectiveOfferTemplateAllowedAction.CAN_CREATE_BOOKABLE_OFFER,
],
isTemplate: true,
}),
action: CollectiveOfferTemplateAllowedAction.CAN_CREATE_BOOKABLE_OFFER,
expected: true,
},
{
description: 'not allowed action CAN_DUPLICATE on bookable offer ',
offer: getCollectiveOfferFactory({
allowedActions: [],
}),
action: CollectiveOfferAllowedAction.CAN_DUPLICATE,
expected: false,
},
{
description:
'not allowed action CAN_CREATE_BOOKABLE_OFFER on template offer',
offer: getCollectiveOfferTemplateFactory({
allowedActions: [],
isTemplate: true,
}),
action: CollectiveOfferTemplateAllowedAction.CAN_CREATE_BOOKABLE_OFFER,
expected: false,
},
])(
'should return $expected for $description',
({ offer, action, expected }) => {
expect(isActionAllowedOnCollectiveOffer(offer, action)).toBe(expected)
}
)
})
31 changes: 31 additions & 0 deletions pro/src/utils/isActionAllowedOnCollectiveOffer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
CollectiveOfferAllowedAction,
CollectiveOfferResponseModel,
CollectiveOfferTemplateAllowedAction,
GetCollectiveOfferResponseModel,
GetCollectiveOfferTemplateResponseModel,
} from 'apiClient/v1'
import {
isCollectiveOffer,
isCollectiveOfferTemplate,
} from 'core/OfferEducational/types'

export function isActionAllowedOnCollectiveOffer(
offer:
| GetCollectiveOfferResponseModel
| GetCollectiveOfferTemplateResponseModel
| CollectiveOfferResponseModel,
action: CollectiveOfferAllowedAction | CollectiveOfferTemplateAllowedAction
) {
if (isCollectiveOffer(offer)) {
return offer.allowedActions.includes(action as CollectiveOfferAllowedAction)
}

if (isCollectiveOfferTemplate(offer)) {
return offer.allowedActions.includes(
action as CollectiveOfferTemplateAllowedAction
)
}

return false
}

0 comments on commit 100af2e

Please sign in to comment.