-
Notifications
You must be signed in to change notification settings - Fork 9
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
feat(CookieConsent): add CookieConsent component #123
Conversation
Preview is ready. |
5f6202f
to
59df049
Compare
59df049
to
55bd842
Compare
sameSite: true, | ||
}; | ||
|
||
export enum ConsentType { |
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.
Let's not use enums, or at least let's not force users to use them.
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.
Could you explain please
I see that we already have enums in components and even export them
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.
fixed
@@ -0,0 +1,164 @@ | |||
import _ from 'lodash'; |
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.
import _ from 'lodash'; | |
import pick from 'lodash/pick'; |
@@ -0,0 +1,100 @@ | |||
import React, {useEffect} from 'react'; |
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.
We enforce this React import syntax in uikit
and plan to do so here.
import React, {useEffect} from 'react'; | |
import React from 'react'; |
}, 1000); | ||
|
||
return () => clearTimeout(timeoutId); | ||
}, [disableInitialOpen]); |
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.
Not all dependencies are listed
); | ||
} | ||
|
||
export function Collapse({ |
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.
Can we use Disclosure
component form uikit
?
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.
Fixed
<span | ||
className={b('link')} | ||
onClick={onChangeStep(ConsentPopupStep.Manage)} | ||
onKeyDown={onChangeStep(ConsentPopupStep.Manage)} |
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.
When you press any key, for example tab
, you go to the next step.
event.stopPropagation(); | ||
}} | ||
> | ||
<Checkbox |
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.
You should not place interactive content inside a button; it is not accessible.
onClose, | ||
} = props; | ||
|
||
const onClick = useCallback( |
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.
Most of the use of useCallback is unnecessarily
|
||
useEffect(() => { | ||
if (!isNotificationMode) { | ||
consentManager.subscribe(() => { |
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.
Where does unsubscription take place?
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.
fixed
return this.consentEdition; | ||
} | ||
|
||
get projectCEdition() { |
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.
maybe better projectEdition
?
27b7e6a
to
5dfa8df
Compare
951f5fe
to
db5ebb5
Compare
bc4581b
to
761b66f
Compare
// do something: e.g. sent events to analytics | ||
}, []); | ||
|
||
React.useMount(() => { |
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.
What is useMount
? I don't know such a hook in React.
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.
seems like forgot to fix, thank you
fixed
); | ||
|
||
React.useEffect(() => { | ||
setCurrentConsents(getCurrentConsents(consentManager)); |
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.
Do we need also subscribe to changes of consents?
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.
yes, we need for managing visibility
|
||
const b = block('consent-popup'); | ||
|
||
const getCurrentConsents = (consentManager: ConsentManager) => { |
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.
Why this is not a logic of consentManager
itself?
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.
In consentManager we have getConsents that returns actual consents. If we haven't defined consetns yet, we need to show consent component
But in ConsentPopup we need to define all consent types because we need to show them in FoldableList
return getCurrentConsents(consentManager); | ||
}); | ||
const [currentStep, setCurrentStep] = React.useState<`${ConsentPopupStep}`>(step); | ||
const onChangeStep = React.useCallback( |
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.
Why do we need useCallback here?
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.
fixed
}; | ||
}); | ||
}, [cookieList, currentConsents]); | ||
const onChoose = React.useCallback( |
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.
Why do we need useCallback here?
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.
fixed
value: boolean, | ||
cookiesTypes: `${ConsentType}`[], | ||
onlyNecessary?: boolean, |
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.
Strange interface, if onlyNecessary=true, then value is not used, it's not obvious. Seems better:
function prepareConsent(consent: 'All' | 'None' | 'onlyNecessary', cookiesTypes)
and why is this not part of the ConsentManager
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.
move to ConsentManager and change interface
const isConsentsDefined = consentManager.isAllConsentsDefined(); | ||
const shouldOpen = isNotificationMode | ||
? !consentManager.isClosed() || !isConsentsDefined | ||
: !isConsentsDefined; | ||
const differentEdition = consentManager.projectEdition !== consentManager.edition; |
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.
Seems, this logic should be inside consentManager
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.
Disagree, consentManager works only with cookies and managing them
Logic about component visibility should be inside the component
return consentManager.subscribe(() => { | ||
setIsOpened(!consentManager.isAllConsentsDefined()); | ||
}); | ||
}, [consentManager, isNotificationMode]); |
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.
How does it depend on isNotificationMode
?
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.
fixed
consentManager, | ||
onConsentPopupClose, | ||
disableInitialOpen, | ||
onAction, |
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.
What is the use case for this props?
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.
For now - we use it in storybook
But anyone can use it if wants to have own callback
step?: `${ConsentPopupStep}`; | ||
cookieList?: ConsentPopupCookieListItem[]; | ||
/* To open by the link or button, so the popup should not be opened at this moment */ | ||
forceOpenManageStep?: boolean; |
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.
I can't find where this is used?
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.
fixed
b525933
to
98073fc
Compare
private readonly subscribers: Subscriber[] = []; | ||
private readonly cookieSettings: CookieSettings = CONSENT_COOKIE_SETTINGS; | ||
|
||
constructor(mode: `${ConsentMode}`, edition?: number) { |
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.
constructor(mode: `${ConsentMode}`, edition?: number) { | |
constructor({ | |
mode, | |
edition, | |
cookieSettings = CONSENT_COOKIE_SETTINGS | |
}: {mode: `${ConsentMode}`, edition?: number, cookieSettings?: CookieSettings}) { |
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.
fixed
setCookieSettings(settings: Partial<CookieSettings>) { | ||
Object.assign(this.cookieSettings, settings); | ||
} |
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.
setCookieSettings(settings: Partial<CookieSettings>) { | |
Object.assign(this.cookieSettings, settings); | |
} |
I suggest setting it via constructor.
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.
fixed
set mode(newMode: `${ConsentMode}`) { | ||
this.consentMode = newMode; | ||
} |
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.
set mode(newMode: `${ConsentMode}`) { | |
this.consentMode = newMode; | |
} |
With current use of ConsentManager
it should be done via creating a new ConsentManager
.
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.
consentManager should be only one in service
This method is necessary for this scenario: in Notification mode we still want to provide the ability to manage settings. Therefore, when we want to open ConsentPopup on manage step we switch the mode and open it
return this.cookieSettings; | ||
} | ||
|
||
getConsents() { |
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.
I still think that this should return the same as getCurrentConsents
.
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.
fixed
}; | ||
} | ||
|
||
setConsents(consents: Consents) { |
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.
How about this:
setConsents(consents: Consents) { | |
setConsents(consents: Consents | 'All' | 'OnlyNecessary') { |
and make prepareConsent
private?
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.
fixed
|
||
const onConsentPopupAction = (consents: Consents) => { | ||
consentManager.setConsents(consents); | ||
setIsOpened(false); |
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.
onAction
is always called with onClose
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.
add onConsentPopupClose in onConsentPopupAction
const onButtonClick = (onlyNecessary?: boolean) => { | ||
return () => { | ||
onAction(consentManager.prepareConsent(onlyNecessary ? 'OnlyNecessary' : 'All')); | ||
onClose?.(); |
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.
onClose
is not optional.
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.
deleted
}; | ||
const confirmSelectedConsent = () => { | ||
onAction(currentConsents); | ||
onClose?.(); |
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.
onClose
is not optional.
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.
deleted
const onClick = (isAll: boolean) => { | ||
return () => { | ||
onAction(consentManager.prepareConsent(isAll ? 'All' : 'OnlyNecessary')); | ||
onClose?.(); |
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.
onClose
is not optional.
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.
deleted from SimpleConsent
newValue = { | ||
...newValue, | ||
[AdditionalConsentParams.Closed]: true, | ||
}; |
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.
newValue = { | |
...newValue, | |
[AdditionalConsentParams.Closed]: true, | |
}; | |
newValue[AdditionalConsentParams.Closed] = true; |
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.
fixed
98073fc
to
fc98d41
Compare
b60ebbc
to
56bebb1
Compare
56bebb1
to
108205e
Compare
No description provided.