From 3dec49b72c15ba766d17161eead6646598e08bad Mon Sep 17 00:00:00 2001 From: Kalista Payne Date: Thu, 11 Sep 2025 14:58:10 -0500 Subject: [PATCH] GPC Message (#15508) * feat(gpc): warn user about enabling analytics * fix(gpc): style tweaks * fix(privacy): local storage doesn't understand Boolean * fix(gpc): do record if user has opted in * fix(privacy): don't flip flop if no value changed --- .../client/src/assets/scss/typography.scss | 4 ++ website/client/src/libs/analytics.js | 2 +- .../client/src/pages/settings-overview.vue | 2 +- .../siteDataRows/privacyPreferencesRow.vue | 62 ++++++++++++++++++- website/client/src/pages/user-main.vue | 11 ++-- website/common/locales/en/settings.json | 4 +- 6 files changed, 76 insertions(+), 9 deletions(-) diff --git a/website/client/src/assets/scss/typography.scss b/website/client/src/assets/scss/typography.scss index f82fed2d72..d20415160f 100644 --- a/website/client/src/assets/scss/typography.scss +++ b/website/client/src/assets/scss/typography.scss @@ -123,6 +123,10 @@ h4 { background-color: $purple-300 !important; } +.bg-yellow-50 { + background-color: $yellow-50 !important; +} + .bg-white { background-color: $white !important; } diff --git a/website/client/src/libs/analytics.js b/website/client/src/libs/analytics.js index 6520a449ae..5ed2a84f46 100644 --- a/website/client/src/libs/analytics.js +++ b/website/client/src/libs/analytics.js @@ -19,7 +19,7 @@ let analyticsReady = false; function _getConsentedUser () { const store = getStore(); const user = store.state.user.data; - if (!user?.preferences?.analyticsConsent || navigator.globalPrivacyControl) { + if (!user?.preferences?.analyticsConsent) { return false; } return user; diff --git a/website/client/src/pages/settings-overview.vue b/website/client/src/pages/settings-overview.vue index 89523e3718..66c9a8d68e 100644 --- a/website/client/src/pages/settings-overview.vue +++ b/website/client/src/pages/settings-overview.vue @@ -98,7 +98,7 @@ } .settings-content { - flex: 0 0 732px; + flex: 0 0 751px; max-width: unset; ::v-deep { diff --git a/website/client/src/pages/settings/siteDataRows/privacyPreferencesRow.vue b/website/client/src/pages/settings/siteDataRows/privacyPreferencesRow.vue index 797747ea8b..66866f97cc 100644 --- a/website/client/src/pages/settings/siteDataRows/privacyPreferencesRow.vue +++ b/website/client/src/pages/settings/siteDataRows/privacyPreferencesRow.vue @@ -33,6 +33,21 @@ v-html="$t('privacySettingsOverview') + ' ' + $t('learnMorePrivacy')" >

+
+
+
+
+
+
@@ -91,6 +106,29 @@ line-height: 1.33; } + .gpc-alert { + border-radius: 4px; + line-height: 1.714; + + .gpc-message { + opacity: 0.9; + } + + ::v-deep a { + color: $black; + text-decoration: underline; + } + + .svg-icon { + width: 16px; + opacity: 0.75; + + ::v-deep svg path { + fill: $black; + } + } + } + .mb-28p { margin-bottom: 28px; } @@ -110,6 +148,7 @@ import ToggleSwitch from '@/components/ui/toggleSwitch.vue'; import { GenericUserPreferencesMixin } from '@/pages/settings/components/genericUserPreferencesMixin'; import { InlineSettingMixin } from '../components/inlineSettingMixin'; import { mapState } from '@/libs/store'; +import alert from '@/assets/svg/for-css/alert.svg?raw'; export default { mixins: [ @@ -120,14 +159,32 @@ export default { SaveCancelButtons, ToggleSwitch, }, + data () { + return { + icons: Object.freeze({ + alert, + }), + }; + }, computed: { ...mapState({ user: 'user.data', }), + gpcEnabled () { + return navigator.globalPrivacyControl; + }, + gpcInfo () { + const gpcUrl = 'https://globalprivacycontrol.org/'; + if (this.user.preferences.analyticsConsent) { + return this.$t('gpcPlusAnalytics', { url: gpcUrl }); + } + return this.$t('gpcWarning', { url: gpcUrl }); + }, }, methods: { finalize () { this.setUserPreference('analyticsConsent'); + localStorage.setItem('analyticsConsent', this.user.preferences.analyticsConsent); this.mixinData.inlineSettingMixin.sharedState.inlineSettingUnsavedValues = false; }, prefToggled () { @@ -135,7 +192,10 @@ export default { this.mixinData.inlineSettingMixin.sharedState.inlineSettingUnsavedValues = newVal; }, resetControls () { - this.user.preferences.analyticsConsent = !this.user.preferences.analyticsConsent; + if (this.mixinData.inlineSettingMixin.sharedState.inlineSettingUnsavedValues) { + this.user.preferences.analyticsConsent = !this.user.preferences.analyticsConsent; + this.mixinData.inlineSettingMixin.sharedState.inlineSettingUnsavedValues = false; + } }, }, }; diff --git a/website/client/src/pages/user-main.vue b/website/client/src/pages/user-main.vue index 3e23050dfe..22b02b96b7 100644 --- a/website/client/src/pages/user-main.vue +++ b/website/client/src/pages/user-main.vue @@ -263,11 +263,12 @@ export default { this.$store.dispatch('tasks:fetchUserTasks'), ]).then(() => { this.$store.state.isUserLoaded = true; - const analyticsConsent = localStorage.getItem('analyticsConsent'); - if (analyticsConsent !== null - && analyticsConsent !== this.user.preferences.analyticsConsent - ) { - this.$store.dispatch('user:set', { 'preferences.analyticsConsent': analyticsConsent }); + let analyticsConsent = localStorage.getItem('analyticsConsent'); + if (analyticsConsent !== null) { + analyticsConsent = analyticsConsent === 'true'; + if (analyticsConsent !== this.user.preferences.analyticsConsent) { + this.$store.dispatch('user:set', { 'preferences.analyticsConsent': analyticsConsent }); + } } if (window && window['habitica-i18n']) { if (this.user.preferences.language === window['habitica-i18n'].language.code) { diff --git a/website/common/locales/en/settings.json b/website/common/locales/en/settings.json index 8df37e842c..6105305720 100644 --- a/website/common/locales/en/settings.json +++ b/website/common/locales/en/settings.json @@ -271,5 +271,7 @@ "performanceAnalytics": "Performance and Analytics", "usedForSupport": "These are used to improve the user experience, performance, and services of our website and apps. This data is used by our support team when handling requests and bug reports.", "savePreferences": "Save Preferences", - "habiticaPrivacyPolicy": "Habitica's Privacy Policy" + "habiticaPrivacyPolicy": "Habitica's Privacy Policy", + "gpcWarning": "GPC is on. Turning on tracking below will override this and send data to our analytics partners.", + "gpcPlusAnalytics": "GPC is on. You have opted in to tracking and sending data to our analytics partners." }