-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(PC-33485) feat(Modals): resolve modal conflicts #7427
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merci pour cette conception qui a du demander beaucoup de réflexion
Il va falloir documenter (dans /doc
)
si j'ai bien tout compris (c'est encore confus pour moi), on a :
- des modales qui sont composées d'une clé et de props
- un store Zustand qui gère une file d'attente (non priorisée) de modales
- une map qui stock / donne le composant pour render une modale couplé à une clé de modale
est-ce que je me trompe ?
if (modals.has(modalCreator.key)) { | ||
throw new Error(`Modal with key\u00a0: ${modalCreator.key} Already exist`) | ||
} | ||
modals.set(modalCreator.key, element as React.FC<{ params: unknown }>) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
récemment, notre communauté de dev s'est mise d'accord par consensus pour éviter d'ajouter des as
dans la codebase (et supprimer les existants)
si jamais on pense ne pas avoir le choix, il faudrait ajouter un commentaire disant pourquoi c'est nécessaire à cet endroit et qu'est-ce qu'on a essayé de faire comme solution alternative
export const achievementsModal = createModal<{ names: AchievementEnum[] }>('achievements') | ||
|
||
// reactionModal à réadapter | ||
export const reactionModal = createModal<{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ce fichier semble etre une lib très générique (d'après son chemin)
ce fichier dépend d'une feature très spécifique (reaction)
est-ce qu'à terme, ce fichier contiendra toutes les modales de l'app ?
quels seront les impacts sur du code splitting ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ce fichier ne réutilise pas les props défini dans les composants des modals
Line 29 in 99d132e
type Props = { |
avec les évolutions futures, il risque d'y avoir une divergeance entre le type fourni à createModal
et le type des props du composant
params, | ||
} | ||
} | ||
creator.key = key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pourquoi est-ce nécessaire ?
const hasModalOpened = state.modalOpened !== undefined | ||
|
||
return { | ||
...state, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pourquoi a-t-on besoin de spread le state
?
const [nextModal] = state.queue | ||
|
||
return { | ||
...state, | ||
modalOpened: nextModal, | ||
queue: state.queue.filter((queuedModal) => queuedModal !== nextModal), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
est-ce que ceci serait valide ? si oui, ça me semble plus simple
const [nextModal] = state.queue | |
return { | |
...state, | |
modalOpened: nextModal, | |
queue: state.queue.filter((queuedModal) => queuedModal !== nextModal), | |
} | |
const [nextModal, ...queue] = state.queue | |
return { | |
...state, | |
modalOpened: nextModal, | |
queue, | |
} |
const bookingsWithoutReaction = | ||
bookings?.ended_bookings?.filter((booking) => | ||
filterBookingsWithoutReaction(booking, subcategoriesMapping, reactionCategories) | ||
) ?? [] | ||
|
||
const offerImages: OfferImageBasicProps[] = bookingsWithoutReaction.map((current) => { | ||
return { | ||
imageUrl: current.stock.offer.image?.url ?? '', | ||
categoryId: mapping[current.stock.offer.subcategoryId] ?? null, | ||
} | ||
}) | ||
|
||
const firstBooking = bookingsWithoutReaction[0] | ||
const reactionChoiceModalBodyType = | ||
bookingsWithoutReaction.length === 1 | ||
? ReactionChoiceModalBodyEnum.VALIDATION | ||
: ReactionChoiceModalBodyEnum.REDIRECTION |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
si cette partie était faite dans getModal
, on pourrait faire des early return, ce qui permettrait de supprimer plein de ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ça pourrait éviter quelques calculs dans le cas où une autre modal s'affiche avant celle ci
|
||
const isReactionFeatureActive = useFeatureFlag(RemoteStoreFeatureFlags.WIP_REACTION_FEATURE) | ||
if (!modal) return | ||
openModal(modal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
si on arrive depuis un deep link sur autre page que la home, on ne verra pas les modales parce qu'on n'est pas passé par la home
est-ce le comportement voulu ?
return null | ||
} | ||
|
||
const ModalRenderer = modalFactory.get(modalOpened) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
le composant s'appelle aussi ModalRenderer
le shadowing de variable est souvent source de confusion
je suggère de renommer soit le composant, soit la variable dans la fonction
if (hasShowSessionModal) return | ||
hasShowSessionModal = true | ||
const modal = createRelativeModals( | ||
{ | ||
creator: reactionModal, | ||
check: checkReactionModal, | ||
}, | ||
{ | ||
creator: achievementsModal, | ||
check: checkAchievementsModal, | ||
} | ||
) | ||
|
||
const isReactionFeatureActive = useFeatureFlag(RemoteStoreFeatureFlags.WIP_REACTION_FEATURE) | ||
if (!modal) return | ||
openModal(modal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
où sont les tests ?
@@ -108,6 +110,7 @@ export const RootNavigator: React.ComponentType = () => { | |||
{/* The components below are those for which we do not want | |||
their rendering to happen while the splash is displayed. */} | |||
{isSplashScreenHidden ? <PrivacyPolicy /> : null} | |||
<ModalRenderer modalFactory={modalFactory} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PrivacyPolicy
s'affiche uniquement si le splash screen n'est plus affiché
est-ce qu'il n'y aurait pas un risque d'afficher les modales au moment du splash screen ?
@bebstein-pass Que faire de cette PR ? |
Link to JIRA ticket: https://passculture.atlassian.net/browse/PC-33485
Flakiness
If I had to re-run tests in the CI due to flakiness, I add the incident on Notion
Checklist
I have:
Best Practices
Click to expand
These rules apply to files that you make changes to. If you can't respect one of these rules, be sure to explain why with a comment. If you consider correcting the issue is too time consuming/complex: create a ticket. Link the ticket in the code.as
(type assertions are removed at compile-time, there is no runtime checking associated with a type assertion. There won’t be an exception ornull
generated if the type assertion is wrong). In certain casesas const
is acceptable (for example when defining readonly arrays/objects). Usingas
in tests is tolerable.any
(when you want to accept anything because you will be blindly passing it through without interacting with it, you can useunknown
). Usingany
in tests is tolerable.!
when you know that the value can’t benull
orundefined
).@ts-expect-error
and@eslint-disable
.yarn test:lint
,yarn test:types
,yarn start:web
...).gap
(ViewGap
) instead of<Spacer.Column />
,<Spacer.Row />
or<Spacer.Flex />
.Test specific:
user
tofireEvent
.setFeatureFlags
. If not possible, mention which one(s) you want to mock in a comment (example:jest.spyOn(useFeatureFlagAPI, 'useFeatureFlag').mockReturnValue(true) // WIP_NEW_OFFER_TILE in renderPassPlaylist.tsx
)await act(async () => {})
andawait waitFor(/* ... */)
byawait screen.findBySomething()
.act
by default andwaitFor
as a last resort.Advice: