Skip to content

Commit a332a6c

Browse files
committed
feat(privacy): draft workflows
1 parent 79a2eb1 commit a332a6c

File tree

6 files changed

+44
-19
lines changed

6 files changed

+44
-19
lines changed

website/client/src/components/header/banners/privacy.vue

+23-9
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
>
1616
<button
1717
class="btn btn-primary mb-2"
18-
@click="close()"
18+
@click="consent(true)"
1919
>
2020
{{ $t('acceptAllCookies') }}
2121
</button>
22-
<button class="btn btn-secondary mb-2">
22+
<button
23+
class="btn btn-secondary mb-2"
24+
@click="consent(false)"
25+
>
2326
{{ $t('denyNonEssentialCookies') }}
2427
</button>
2528
<a
@@ -72,37 +75,48 @@
7275

7376
<script>
7477
import { nextTick } from 'vue';
75-
import {
76-
hideBanner, isBannerHidden,
77-
} from '@/libs/banner.func';
78+
import { GenericUserPreferencesMixin } from '@/pages/settings/components/genericUserPreferencesMixin';
7879
import { EVENTS } from '@/libs/events';
79-
80-
const BANNER_ID = 'privacy-preferences';
80+
import { mapState } from '@/libs/store';
8181
8282
export default {
83+
mixins: [GenericUserPreferencesMixin],
8384
computed: {
8485
isStaticPage () {
8586
return this.$route.meta.requiresLogin === false;
8687
},
88+
...mapState({
89+
user: 'user.data',
90+
}),
8791
},
8892
data () {
8993
return {
9094
hidden: false,
9195
};
9296
},
9397
mounted () {
94-
if (isBannerHidden(BANNER_ID)) {
98+
if (localStorage.getItem('analyticsConsent') !== null
99+
|| this.user?.preferences?.analyticsConsent !== undefined
100+
) {
95101
this.hidden = true;
96102
}
97103
},
98104
methods: {
99105
close () {
100-
hideBanner(BANNER_ID);
101106
this.hidden = true;
102107
nextTick(() => {
103108
this.$root.$emit(EVENTS.BANNER_HEIGHT_UPDATED);
104109
});
105110
},
111+
consent (decision) {
112+
if (this.user) {
113+
this.user.preferences.analyticsConsent = decision;
114+
this.setUserPreference('analyticsConsent');
115+
} else {
116+
localStorage.setItem('analyticsConsent', decision);
117+
}
118+
this.close();
119+
},
106120
showPrivacyModal () {
107121
this.$root.$emit('bv::show::modal', 'privacy-preferences');
108122
},

website/client/src/libs/analytics.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const REQUIRED_FIELDS = ['eventCategory', 'eventAction'];
1616
function _getConsentedUser () {
1717
const store = getStore();
1818
const user = store.state.user.data;
19-
if (user.preferences?.privacy?.disableAnalytics) return false;
19+
if (!user?.preferences?.analyticsConsent) return false;
2020
return user;
2121
}
2222

website/client/src/pages/settings/siteDataRows/privacyPreferencesRow.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
>
5555
<div class="settings-label w-50"> {{ $t('performanceAnalytics') }}</div>
5656
<toggle-switch
57-
v-model="user.preferences.privacy.disableAnalytics"
58-
@change="setUserPreference('privacy', 'disableAnalytics')"
57+
v-model="user.preferences.analyticsConsent"
58+
@change="setUserPreference('analyticsConsent')"
5959
/>
6060
</div>
6161
<div class="mb-4">

website/client/src/pages/user-main.vue

+6
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,12 @@ export default {
263263
this.$store.state.isUserLoaded = true;
264264
Analytics.setUser();
265265
Analytics.updateUser();
266+
const analyticsConsent = localStorage.getItem('analyticsConsent');
267+
if (analyticsConsent !== null
268+
&& analyticsConsent !== this.user.preferences.analyticsConsent
269+
) {
270+
this.$store.dispatch('user:set', { 'preferences.analyticsConsent': analyticsConsent });
271+
}
266272
if (window && window['habitica-i18n']) {
267273
if (this.user.preferences.language === window['habitica-i18n'].language.code) {
268274
return null;

website/server/libs/analyticsService.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,17 @@ function _setOnce (dataToSetOnce, uuid) {
217217

218218
// There's no error handling directly here because it's handled inside _sendDataTo{Amplitude|Google}
219219
async function track (eventType, data, loggerOnly = false) {
220+
const { user } = data;
221+
if (!user.preferences?.analyticsConsent) {
222+
return;
223+
}
220224
const promises = [
221225
_sendDataToAmplitude(eventType, data, loggerOnly),
222226
];
223-
if (data.user && data.user.registeredThrough) {
227+
if (user.registeredThrough) {
224228
promises.push(_setOnce({
225-
registeredPlatform: data.user.registeredThrough,
226-
}, data.uuid || data.user._id));
229+
registeredPlatform: user.registeredThrough,
230+
}, data.uuid || user._id));
227231
}
228232

229233
return Promise.all(promises);
@@ -232,6 +236,10 @@ async function track (eventType, data, loggerOnly = false) {
232236
// There's no error handling directly here because
233237
// it's handled inside _sendPurchaseDataTo{Amplitude|Google}
234238
async function trackPurchase (data) {
239+
const { user } = data;
240+
if (!user.preferences?.analyticsConsent) {
241+
return;
242+
}
235243
return Promise.all([
236244
_sendPurchaseDataToAmplitude(data),
237245
]);

website/server/models/user/schema.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -626,10 +626,7 @@ export const UserSchema = new Schema({
626626
return isValidCategory;
627627
},
628628
},
629-
privacy: {
630-
disableAnalytics: { $type: Boolean, default: false },
631-
acceptedWebCookies: { $type: Boolean, default: false },
632-
},
629+
analyticsConsent: Boolean,
633630
},
634631
profile: {
635632
blurb: String,

0 commit comments

Comments
 (0)