@plentymarkets/shop-core 1.3.11 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/composables/__tests__/useCookieBar.spec.js +64 -9
- package/dist/runtime/composables/__tests__/useRegisterCookie.spec.js +3 -0
- package/dist/runtime/composables/useCookieBar.d.ts +4 -3
- package/dist/runtime/composables/useCookieBar.js +26 -30
- package/dist/runtime/composables/useRegisterCookie.d.ts +1 -1
- package/dist/runtime/composables/useRegisterCookie.js +15 -15
- package/dist/runtime/types/cookies.d.ts +5 -0
- package/dist/runtime/utils/runtime.d.ts +1 -0
- package/dist/runtime/utils/runtime.js +1 -0
- package/package.json +3 -2
package/dist/module.json
CHANGED
|
@@ -3,6 +3,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
3
3
|
import { mockNuxtImport } from "@nuxt/test-utils/runtime";
|
|
4
4
|
import { useCookieBar } from "../useCookieBar.js";
|
|
5
5
|
import { useCookieConsent } from "../useCookieConsent.js";
|
|
6
|
+
import { ref } from "vue";
|
|
6
7
|
const { useCookie } = vi.hoisted(() => ({
|
|
7
8
|
useCookie: vi.fn().mockReturnValue({})
|
|
8
9
|
}));
|
|
@@ -11,11 +12,12 @@ const { useRouter } = vi.hoisted(() => ({
|
|
|
11
12
|
go: vi.fn()
|
|
12
13
|
})
|
|
13
14
|
}));
|
|
14
|
-
mockNuxtImport("useRouter", () => useRouter);
|
|
15
15
|
mockNuxtImport("useCookie", () => useCookie);
|
|
16
|
+
mockNuxtImport("useRouter", () => useRouter);
|
|
16
17
|
describe("useCookieBar", () => {
|
|
17
18
|
beforeEach(() => {
|
|
18
19
|
const cookieInit = {
|
|
20
|
+
configHash: "",
|
|
19
21
|
barTitle: "Test",
|
|
20
22
|
barDescription: "Test",
|
|
21
23
|
groups: [
|
|
@@ -35,19 +37,29 @@ describe("useCookieBar", () => {
|
|
|
35
37
|
]
|
|
36
38
|
},
|
|
37
39
|
{
|
|
40
|
+
id: 1,
|
|
38
41
|
name: "marketing",
|
|
42
|
+
accepted: false,
|
|
43
|
+
showMore: false,
|
|
44
|
+
description: "Marketing cookies description",
|
|
39
45
|
cookies: [
|
|
40
46
|
{
|
|
41
47
|
name: "testCookie",
|
|
42
48
|
accepted: false,
|
|
43
49
|
Lifespan: "100",
|
|
44
|
-
script: []
|
|
50
|
+
script: [],
|
|
51
|
+
Provider: "TestProvider",
|
|
52
|
+
Status: "Inactive",
|
|
53
|
+
PrivacyPolicy: "/PrivacyPolicy"
|
|
45
54
|
},
|
|
46
55
|
{
|
|
47
56
|
name: "externalScript",
|
|
48
57
|
accepted: false,
|
|
49
58
|
Lifespan: "100",
|
|
50
|
-
script: ["https://cdn02.plentymarkets.com/mevofvd5omld/frontend/test-cookie-external-script.js"]
|
|
59
|
+
script: ["https://cdn02.plentymarkets.com/mevofvd5omld/frontend/test-cookie-external-script.js"],
|
|
60
|
+
Provider: "TestProvider",
|
|
61
|
+
Status: "Inactive",
|
|
62
|
+
PrivacyPolicy: "/PrivacyPolicy"
|
|
51
63
|
}
|
|
52
64
|
]
|
|
53
65
|
}
|
|
@@ -99,21 +111,41 @@ describe("useCookieBar", () => {
|
|
|
99
111
|
expect(document.cookie).not.toContain("testCookie=testValue");
|
|
100
112
|
});
|
|
101
113
|
it("should set state read from browser-cookie", () => {
|
|
102
|
-
const { initializeCookies, data } = useCookieBar();
|
|
103
114
|
const browserCookies = {
|
|
104
|
-
|
|
105
|
-
|
|
115
|
+
hash: "",
|
|
116
|
+
groups: {
|
|
117
|
+
"CookieBar.essentials.label": {
|
|
118
|
+
"CookieBar.essentials.cookies.payPal.name": true
|
|
119
|
+
},
|
|
120
|
+
marketing: {
|
|
121
|
+
testCookie: true
|
|
122
|
+
}
|
|
106
123
|
}
|
|
107
124
|
};
|
|
108
|
-
useCookie.
|
|
125
|
+
useCookie.mockImplementation((name) => {
|
|
126
|
+
if (name === "consent-cookie") return ref(browserCookies);
|
|
127
|
+
return ref(null);
|
|
128
|
+
});
|
|
129
|
+
const { initializeCookies, data } = useCookieBar();
|
|
109
130
|
initializeCookies();
|
|
110
131
|
expect(data.value.groups[1].cookies[0].accepted).toBe(true);
|
|
111
132
|
});
|
|
112
133
|
it("should reload the page if a consent cookie is revoked", () => {
|
|
113
134
|
const { setConsent, initializeCookies, data } = useCookieBar();
|
|
114
135
|
const RouterGoSpy = vi.fn();
|
|
115
|
-
useRouter.mockReturnValue({
|
|
116
|
-
|
|
136
|
+
useRouter.mockReturnValue({ go: RouterGoSpy });
|
|
137
|
+
useCookie.mockImplementation((name) => {
|
|
138
|
+
if (name === "consent-cookie") {
|
|
139
|
+
return ref({
|
|
140
|
+
hash: "abc123",
|
|
141
|
+
groups: {
|
|
142
|
+
marketing: {
|
|
143
|
+
testCookie: true
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return ref(null);
|
|
117
149
|
});
|
|
118
150
|
initializeCookies();
|
|
119
151
|
data.value.groups[1].cookies[0].accepted = false;
|
|
@@ -152,4 +184,27 @@ describe("useCookieBar", () => {
|
|
|
152
184
|
expect(data.value.groups[1].cookies[0].accepted).toBe(true);
|
|
153
185
|
expect(consent.value).toBe(true);
|
|
154
186
|
});
|
|
187
|
+
it("should show the cookie bar if hash is missing", () => {
|
|
188
|
+
const browserCookies = { groups: {} };
|
|
189
|
+
useCookie.mockImplementation((name) => {
|
|
190
|
+
if (name === "consent-cookie") return ref(browserCookies);
|
|
191
|
+
return ref(null);
|
|
192
|
+
});
|
|
193
|
+
const { initializeCookies, visible } = useCookieBar();
|
|
194
|
+
initializeCookies();
|
|
195
|
+
expect(visible.value).toBe(true);
|
|
196
|
+
});
|
|
197
|
+
it("should show the cookie bar if hash does not match", () => {
|
|
198
|
+
const browserCookies = {
|
|
199
|
+
hash: "mismatchedHash",
|
|
200
|
+
groups: {}
|
|
201
|
+
};
|
|
202
|
+
useCookie.mockImplementation((name) => {
|
|
203
|
+
if (name === "consent-cookie") return ref(browserCookies);
|
|
204
|
+
return ref(null);
|
|
205
|
+
});
|
|
206
|
+
const { initializeCookies, visible } = useCookieBar();
|
|
207
|
+
initializeCookies();
|
|
208
|
+
expect(visible.value).toBe(true);
|
|
209
|
+
});
|
|
155
210
|
});
|
|
@@ -4,6 +4,9 @@ import { useRegisterCookie } from "../useRegisterCookie.js";
|
|
|
4
4
|
vi.mock("nuxt/app", () => ({
|
|
5
5
|
useRuntimeConfig: vi.fn()
|
|
6
6
|
}));
|
|
7
|
+
vi.mock("../../utils/runtime", () => ({
|
|
8
|
+
isClient: vi.fn(() => false)
|
|
9
|
+
}));
|
|
7
10
|
describe("useRegisterCookie", () => {
|
|
8
11
|
it("adds a cookie to the specified group", () => {
|
|
9
12
|
const { add } = useRegisterCookie();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { Cookie, CookieGroupFromNuxtConfig } from '../types/index.js';
|
|
1
|
+
import { type Ref } from 'vue';
|
|
2
|
+
import type { Cookie, CookieGroup, CookieGroupFromNuxtConfig } from '../types/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* @description Composable for managing cookie consent bar.
|
|
5
5
|
* @example
|
|
@@ -10,7 +10,8 @@ import type { Cookie, CookieGroupFromNuxtConfig } from '../types/index.js';
|
|
|
10
10
|
* ```
|
|
11
11
|
*/
|
|
12
12
|
export declare const useCookieBar: () => {
|
|
13
|
-
|
|
13
|
+
cookieGroups: import("vue").ComputedRef<CookieGroup[]>;
|
|
14
|
+
changeVisibilityState: () => boolean;
|
|
14
15
|
setConsent: () => void;
|
|
15
16
|
initializeCookies: () => void;
|
|
16
17
|
setAllCookiesState: (accepted: boolean) => void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useRuntimeConfig, useState, useCookie, useRouter } from "nuxt/app";
|
|
2
|
-
import { toRefs } from "vue";
|
|
2
|
+
import { computed, toRefs } from "vue";
|
|
3
3
|
import { cookieBarHelper } from "../utils/cookieBarHelper.js";
|
|
4
4
|
import { useCookieConsent } from "./useCookieConsent.js";
|
|
5
|
+
import { sha256 } from "js-sha256";
|
|
5
6
|
const checkIfScriptIsExternal = (scriptName) => {
|
|
6
7
|
return scriptName.startsWith("http");
|
|
7
8
|
};
|
|
@@ -12,66 +13,60 @@ export const useCookieBar = () => {
|
|
|
12
13
|
visible: false,
|
|
13
14
|
loading: false
|
|
14
15
|
}));
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const changeVisibilityState = () => {
|
|
18
|
-
state.value.visible = !state.value.visible;
|
|
19
|
-
};
|
|
16
|
+
const changeVisibilityState = () => state.value.visible = !state.value.visible;
|
|
17
|
+
const cookieGroups = computed(() => state.value.data?.groups || []);
|
|
20
18
|
const initializeCookies = () => {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
19
|
+
const runtimeCookies = useRuntimeConfig().public.cookieGroups;
|
|
20
|
+
const { configHash, ...configWithoutHash } = runtimeCookies;
|
|
21
|
+
runtimeCookies.configHash = sha256(JSON.stringify(configWithoutHash));
|
|
22
|
+
const browserCookies = useCookie("consent-cookie", { default: () => null });
|
|
23
|
+
const browserHash = browserCookies.value?.hash ?? "";
|
|
24
|
+
runtimeCookies.groups.forEach((group) => {
|
|
24
25
|
group.cookies.forEach((cookie) => {
|
|
25
|
-
const isAccepted = group.name === ESSENTIAL_COOKIE_GROUP ||
|
|
26
|
-
if (browserCookies.value?.[group.name]?.[cookie.name] !== void 0 || group.name === ESSENTIAL_COOKIE_GROUP) {
|
|
26
|
+
const isAccepted = group.name === ESSENTIAL_COOKIE_GROUP || (browserCookies.value?.groups?.[group.name]?.[cookie.name] ?? false);
|
|
27
|
+
if (browserCookies.value?.groups?.[group.name]?.[cookie.name] !== void 0 || group.name === ESSENTIAL_COOKIE_GROUP) {
|
|
27
28
|
cookie.accepted = isAccepted;
|
|
28
|
-
if (isAccepted && cookie.script && cookie.script.length)
|
|
29
|
-
fetchScripts(cookie.script);
|
|
30
|
-
}
|
|
29
|
+
if (isAccepted && cookie.script && cookie.script.length) fetchScripts(cookie.script);
|
|
31
30
|
}
|
|
32
31
|
const { consent } = useCookieConsent(cookie.name);
|
|
33
32
|
consent.value = isAccepted;
|
|
34
33
|
});
|
|
35
34
|
group.accepted = group.cookies.some((cookie) => cookie.accepted);
|
|
36
35
|
});
|
|
37
|
-
state.value.data =
|
|
38
|
-
|
|
39
|
-
state.value.visible = true;
|
|
40
|
-
}
|
|
36
|
+
state.value.data = runtimeCookies;
|
|
37
|
+
state.value.visible = browserHash !== runtimeCookies.configHash;
|
|
41
38
|
};
|
|
42
39
|
const setConsent = () => {
|
|
43
40
|
const { getMinimumLifeSpan } = cookieBarHelper();
|
|
44
41
|
const router = useRouter();
|
|
45
|
-
const browserCookies = useCookie("consent-cookie");
|
|
42
|
+
const browserCookies = useCookie("consent-cookie", { default: () => null });
|
|
46
43
|
let cookieRevoke = false;
|
|
47
|
-
const jsonCookie =
|
|
44
|
+
const jsonCookie = cookieGroups.value.reduce((accumulator, group) => {
|
|
48
45
|
accumulator[group.name] = group.cookies.reduce((childAccumulator, cookie) => {
|
|
49
|
-
const currentStatus = !!browserCookies.value?.[group.name]?.[cookie.name] || false;
|
|
46
|
+
const currentStatus = !!browserCookies.value?.groups?.[group.name]?.[cookie.name] || false;
|
|
50
47
|
const { consent } = useCookieConsent(cookie.name);
|
|
51
48
|
childAccumulator[cookie.name] = cookie.accepted || false;
|
|
52
49
|
consent.value = cookie.accepted || false;
|
|
53
50
|
if (currentStatus && !consent.value) {
|
|
54
51
|
cookieRevoke = true;
|
|
55
52
|
removeCookies(cookie);
|
|
56
|
-
} else if (!currentStatus && consent.value && cookie.script && cookie.script.length) {
|
|
57
|
-
fetchScripts(cookie.script);
|
|
58
53
|
}
|
|
54
|
+
if (!currentStatus && consent.value && cookie.script && Array.isArray(cookie.script) && cookie.script.length)
|
|
55
|
+
fetchScripts(cookie.script);
|
|
59
56
|
return childAccumulator;
|
|
60
57
|
}, {});
|
|
61
58
|
return accumulator;
|
|
62
59
|
}, {});
|
|
63
60
|
const consentCookie = useCookie("consent-cookie", {
|
|
64
61
|
path: "/",
|
|
65
|
-
maxAge: getMinimumLifeSpan(
|
|
62
|
+
maxAge: getMinimumLifeSpan(cookieGroups.value)
|
|
66
63
|
});
|
|
67
|
-
consentCookie.value = JSON.stringify(jsonCookie);
|
|
64
|
+
consentCookie.value = JSON.stringify({ hash: state.value.data.configHash, groups: jsonCookie });
|
|
68
65
|
changeVisibilityState();
|
|
69
|
-
if (cookieRevoke)
|
|
70
|
-
router.go(0);
|
|
71
|
-
}
|
|
66
|
+
if (cookieRevoke) router.go(0);
|
|
72
67
|
};
|
|
73
68
|
const setAllCookiesState = (accepted) => {
|
|
74
|
-
|
|
69
|
+
cookieGroups.value.forEach((group) => {
|
|
75
70
|
const isAccepted = group.name === ESSENTIAL_COOKIE_GROUP || accepted;
|
|
76
71
|
group.accepted = isAccepted;
|
|
77
72
|
group.cookies.forEach((cookie) => cookie.accepted = isAccepted);
|
|
@@ -79,7 +74,7 @@ export const useCookieBar = () => {
|
|
|
79
74
|
setConsent();
|
|
80
75
|
};
|
|
81
76
|
const accept = (name) => {
|
|
82
|
-
|
|
77
|
+
cookieGroups.value.forEach((group) => {
|
|
83
78
|
group.cookies.forEach((cookie) => {
|
|
84
79
|
if (cookie.name === name) {
|
|
85
80
|
cookie.accepted = true;
|
|
@@ -104,6 +99,7 @@ export const useCookieBar = () => {
|
|
|
104
99
|
};
|
|
105
100
|
return {
|
|
106
101
|
...toRefs(state.value),
|
|
102
|
+
cookieGroups,
|
|
107
103
|
changeVisibilityState,
|
|
108
104
|
setConsent,
|
|
109
105
|
initializeCookies,
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { useRuntimeConfig } from "nuxt/app";
|
|
2
|
+
import { isClient } from "../utils/runtime.js";
|
|
2
3
|
export const useRegisterCookie = () => {
|
|
3
|
-
const add = (
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const add = (newCookie, group) => {
|
|
5
|
+
if (isClient()) {
|
|
6
|
+
console.error(
|
|
7
|
+
"Cookies can only be registered on the server side, use plugin.server.ts to only run your plugin on the server side"
|
|
8
|
+
);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const runtimeCookies = useRuntimeConfig().public.cookieGroups;
|
|
12
|
+
if (runtimeCookies?.groups) {
|
|
13
|
+
for (const cookieGroup of runtimeCookies.groups) {
|
|
8
14
|
if (cookieGroup.name === group) {
|
|
9
|
-
if (!cookieGroup.cookies)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (cookieGroup.cookies.some((existingCookie) => {
|
|
13
|
-
return existingCookie.name === cookie.name;
|
|
14
|
-
})) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
cookieGroup.cookies.push(cookie);
|
|
15
|
+
if (!cookieGroup.cookies) cookieGroup.cookies = [];
|
|
16
|
+
if (cookieGroup.cookies.some((runtimeCookie) => runtimeCookie.name === newCookie.name)) return;
|
|
17
|
+
cookieGroup.cookies.push(newCookie);
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
|
-
}
|
|
20
|
+
}
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
23
|
return {
|
|
@@ -17,6 +17,7 @@ export type CookieGroup = {
|
|
|
17
17
|
cookies: Cookie[];
|
|
18
18
|
};
|
|
19
19
|
export type CookieGroupFromNuxtConfig = {
|
|
20
|
+
configHash: string;
|
|
20
21
|
groups: CookieGroup[];
|
|
21
22
|
barTitle: string;
|
|
22
23
|
barDescription: string;
|
|
@@ -26,3 +27,7 @@ export type JsonCookie = {
|
|
|
26
27
|
[key: string]: boolean;
|
|
27
28
|
};
|
|
28
29
|
};
|
|
30
|
+
export type BrowserCookies = {
|
|
31
|
+
hash: string;
|
|
32
|
+
groups: JsonCookie;
|
|
33
|
+
} | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isClient: () => boolean | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const isClient = () => import.meta.client;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plentymarkets/shop-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Core module for PlentyONE Shop",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -42,8 +42,9 @@
|
|
|
42
42
|
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@plentymarkets/shop-api": "^0.
|
|
45
|
+
"@plentymarkets/shop-api": "^0.105.0",
|
|
46
46
|
"@vue-storefront/sdk": "^3.4.1",
|
|
47
|
+
"js-sha256": "^0.11.0",
|
|
47
48
|
"mitt": "^3.0.1",
|
|
48
49
|
"resolve": "^1.22.10"
|
|
49
50
|
},
|