-
Notifications
You must be signed in to change notification settings - Fork 77
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
Recording interactions with TCF notices #4161
Recording interactions with TCF notices #4161
Conversation
Passing run #4799 ↗︎
Details:
Review all test suite changes for PR #4161 ↗︎ |
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.
nice job @galvana this is looking like the right approach so far! we'll want to make sure the types are right—they make sense to me, but we should verify with a npm run openapi:generate
. let me know if you'd like help with that!
|
||
const isAllNoticeOnly = privacyNotices.every( | ||
(n) => n.consent_mechanism === ConsentMechanism.NOTICE_ONLY | ||
); |
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 don't need this right now—all TCF payloads will return an empty privacy_notices
array, so we can just pass []
to notices
. also, TCF doesn't have a concept of notice-only yet (see #4141), so for now, let's just pass in false for acknowledgeMode
const handleUpdateAllPreferences = useCallback( | ||
(enabledIds: EnabledIds) => { | ||
const tcf = createTcfSavePayload({ experience, enabledIds }); | ||
(enabledIds: EnabledIds, servedNotices: LastServedNoticeSchema[]) => { |
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 don't think servedNotices
needs to be an arg here—I think you can just reference it above (since it's function inside the component, it has access to its vars)
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.
That's what I tried originally but when I logged out the value of servedNotices
inside handleUpdateAllPreferences
it was empty. The only way I could get it to work is by passing it in as a param. Could it be something to do with useConsentServed
?
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.
Never mind, this is working without the servedNotices
arg
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #4161 +/- ##
=======================================
Coverage 87.83% 87.84%
=======================================
Files 333 333
Lines 21065 21066 +1
Branches 2742 2742
=======================================
+ Hits 18503 18505 +2
+ Misses 2097 2096 -1
Partials 465 465
☔ View full report in Codecov by Sentry. |
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.
awesome job figuring this out @galvana ! I left a comment for something I think we can improve, curious to hear your thoughts!
| "vendor_legitimate_interests" | ||
| "system_consent" | ||
| "system_legitimate_interests"; | ||
type NoticeSubMap = { |
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.
these aren't technically Notices (we typically don't use notices for TCF). maybe we can change this to be TcfEntitiesMap
?
|
||
type NoticeMap = Record<Category, NoticeSubMap>; | ||
|
||
const noticeMap = (servedNotices: LastServedConsentSchema[]): NoticeMap => { |
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.
heh I guess these shouldn't really be called servedNotices
either (you probably noticed the backend type changed from LastServedNoticeSchema
--> LastServedConsentSchema
) so I guess this should be servedConsent
. it's definitely a nit, but I think not conflating notices and TCF is a good distinction that helps with understanding all that's going on here
|
||
servedNotices.forEach((notice) => { | ||
(Object.keys(map) as Category[]).forEach((key) => { | ||
const value = notice[key as keyof LastServedConsentSchema]; |
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.
it might help TS to do something like this https://github.com/ethyca/fides/blob/main/clients/fides-js/src/lib/tcf/types.ts/#L177-L186 for Category
and LastServedConsentSchema
. that said, it might not get you as far as you want, sometimes TS is picky about this kind of thing. but it might save you an as
here or there
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 discuss this next week, I couldn't figure out a way to remove the as keyof
without adding more code than we currently have for the related type definitions.
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.
okay no worries—I figured TS might get picky about it. let's leave it as-is then!
@@ -104,17 +147,21 @@ const transformTcfModelToTcfSave = ({ | |||
return { | |||
id: model.id, | |||
preference, | |||
served_notice_history_id: noticeSubMap[String(model.id)], |
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.
ah I guess this type is still called notice
in the backend 😅 ok I take back what I said about distinguishing between notices and TCF...
@@ -246,14 +312,14 @@ const TcfOverlay: FunctionComponent<OverlayProps> = ({ | |||
userLocationString: fidesRegionString, | |||
cookie, | |||
debug: options.debug, | |||
servedNotices: null, // TODO: served notices | |||
servedNotices: null, |
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 think the thing to do here is to actually refactor NoticeOverlay a little too... I know that's not what this ticket calls for, but I think it'd be a good thing to do if you're up for it. basically, before TCF ever came along, we would:
- In
NoticeOverlay
get theservedNotices
- When the user saves, pass the
servedNotices
toupdateConsentPreferences
along with theconsentPreferencesToSave
updateConsentPreferences
would then do the unenviable task of mappingservedNotices
toconsentPreferencesToSave
Now that we have TCF, we:
- In
TcfOverlay
get theservedNotices
TcfOverlay
does the unenviable task of mappingservedNotices
to each of the tcf entities (what yournoticeSubMap
is doing- We pass the
tcf
obj directly toupdateConsentPreferences
and setservedNotices=null
This is a good approach, and I think we should do the same for notices. In other words, I think updateConsentPreferences
should no longer take a servedNotices
, and we should pass an object that already has the servedNotices
matched into updateConsentPreferences
, same as we do for TCF. so then we can remove some code from preferences.ts
. this might involve updating the type that updateConsentPreferences
takes but hopefully it's not arduous. what do you think?
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.
Sounds good! I gave it a shot, let me know if that's what you had in mind.
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.
nice job, I think you handled it perfectly! 💯
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'm pretty much ready to approve this as I tested locally and it looks great, and I super appreciate the refactor you did for notices! I'm just going to go ask product one more question, and then hopefully we can get this merged 💥
clients/fides-js/src/lib/hooks.ts
Outdated
(event.detail.extraDetails.servingComponent !== | ||
ServingComponent.OVERLAY && | ||
event.detail.extraDetails.servingComponent !== | ||
ServingComponent.TCF_BANNER) |
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.
now that I'm testing this out, I think there's something we should ask product for clarity on... we had a discussion back when we did this for notices of "when" to say consent was served. for notices, we decided only for when the modal pops up, since the banner doesn't actually render notices.
for TCF, as you know, we decided the banner does render what the user is consenting to (via the "stacks") and so we put it on the banner. however, nothing happens if only the modal is opened. for example, if I've already opted in to everything, the banner doesn't render the next time I visit the site. but if I decide I want to make a change and open the modal (by clicking "Manage Consent" on the page in the screenshot), then we don't send another notices-served patch.
I suspect we want to send it for both banner and overlay for TCF, but that we don't want to send it twice, if the user goes through the flow of 1. banner opens 2. user clicks "manage preferences" in the banner 3. the modal pops up. that was actually my first implementation of notices back when I was POC-ing it—we can add a state to the hook and it should sort itself out: 5ad7ebc
but let's confirm with product first, I can ask...
I was finally able to get back to this. I updated the conditions to trigger the notices served to include the TCF_OVERLAY. The only time we don't trigger the notice is for the consent banner, since that's the only component where notices aren't shown directly. |
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.
whew, way to persist through this PR! I know it's probably been haunting you for a while now 😄 great job! ⭐
ServingComponent.OVERLAY && | ||
event.detail.extraDetails.servingComponent !== | ||
ServingComponent.TCF_BANNER) | ||
event.detail.extraDetails.servingComponent === ServingComponent.BANNER |
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.
ah nice, this is clean, and the comment helps a lot 👍
I'm free! |
Description Of Changes
Adding
served_notice_history_id
to the TCF fields of thePATCH /privacy-preference
request.Code Changes
banner
andtcf_banner
forFidesUIShown
eventsPATCH /notices-served
is called from thetcf_banner
and the consentoverlay
Steps to Confirm
FIDES__CONSENT__TCF_ENABLED
totrue
http://localhost:3000/fides-js-demo.html?geolocation=fi-18
to view the TCF bannerDispatching event type FidesUIShown from tcf_banner
in the browser consolePATCH /privacy-preferences
is made, the TCF fields should have theserved_notice_history_id
Pre-Merge Checklist
CHANGELOG.md