@scayle/storefront-nuxt 7.44.1 → 7.46.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/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # @scayle/storefront-nuxt
2
2
 
3
+ ## 7.46.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Use new password change API when oauth is enabled
8
+
9
+ ### Patch Changes
10
+
11
+ - Locale is optional in formatCurrency
12
+ - Updated dependencies
13
+ - @scayle/storefront-core@7.32.0
14
+
15
+ ## 7.45.0
16
+
17
+ ### Minor Changes
18
+
19
+ - Migrate currency formatters to a composable
20
+
21
+ Because the currency formatter functions depend on the `useCurrentShop` composable, they must also be initialized through a composable. Additionally, because `formatPrice` was the same as `toCurrency` except that it excluded the symbol, the two functions have been merged into `formatCurrency`. If you don't want the currency symbol to be displayed, set the `style` option to `decimal`. These changes requires a small migration step.
22
+
23
+ Before:
24
+
25
+ ```typescript
26
+ toCurrency(100, { currency: 'EUR' })
27
+ formatPrice(100, { currencyFractionDigits: 2 })
28
+ ```
29
+
30
+ After:
31
+
32
+ ```typescript
33
+ const { formatCurrency } = useFormatHelpers()
34
+ formatCurrency(100, { currency: 'EUR' })
35
+ formatCurrency(100, { style: 'decimal', currencyFractionDigits: 2 })
36
+ ```
37
+
3
38
  ## 7.44.1
4
39
 
5
40
  ### Patch Changes
package/dist/module.json CHANGED
@@ -4,5 +4,5 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.7.0"
6
6
  },
7
- "version": "7.44.0"
7
+ "version": "7.45.0"
8
8
  }
@@ -0,0 +1,14 @@
1
+ type FormatCurrencyOptions = {
2
+ locale?: string;
3
+ currencyFractionDigits?: number;
4
+ style?: 'currency';
5
+ currency: string;
6
+ } | {
7
+ locale?: string;
8
+ currencyFractionDigits?: number;
9
+ style: 'decimal';
10
+ };
11
+ export default function useFormatHelpers(): {
12
+ formatCurrency: (value: number, options?: FormatCurrencyOptions) => string;
13
+ };
14
+ export {};
@@ -0,0 +1,27 @@
1
+ import { getDefaultFractionDigits } from "@scayle/storefront-core";
2
+ import { useCurrentShop } from "./useCurrentShop.mjs";
3
+ export default function useFormatHelpers() {
4
+ const currentShop = useCurrentShop();
5
+ const formatCurrency = (value, options) => {
6
+ const {
7
+ locale = currentShop.value.locale,
8
+ currencyFractionDigits = currentShop.value.currencyFractionDigits
9
+ } = options || {};
10
+ const currency = options?.style !== "decimal" ? options?.currency ?? currentShop.value.currency : void 0;
11
+ const minimumFractionDigits = options?.style !== "decimal" ? getDefaultFractionDigits(
12
+ locale,
13
+ options?.currency ?? currentShop.value.currency
14
+ ) : currencyFractionDigits;
15
+ return (value / 100).toLocaleString(locale, {
16
+ style: options?.style ?? "currency",
17
+ ...currencyFractionDigits && {
18
+ minimumFractionDigits: minimumFractionDigits !== void 0 ? Math.min(minimumFractionDigits, currencyFractionDigits) : currencyFractionDigits
19
+ },
20
+ maximumFractionDigits: currencyFractionDigits,
21
+ currency
22
+ });
23
+ };
24
+ return {
25
+ formatCurrency
26
+ };
27
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@scayle/storefront-nuxt",
3
3
  "type": "module",
4
- "version": "7.44.1",
4
+ "version": "7.46.0",
5
5
  "description": "Nuxt integration for the SCAYLE Commerce Engine and Storefront API",
6
6
  "author": "SCAYLE Commerce Engine",
7
7
  "license": "MIT",
@@ -62,7 +62,7 @@
62
62
  "dependencies": {
63
63
  "@nuxt/kit": "3.8.2",
64
64
  "@scayle/h3-session": "0.3.4",
65
- "@scayle/storefront-core": "7.31.0",
65
+ "@scayle/storefront-core": "7.32.0",
66
66
  "@scayle/unstorage-compression-driver": "0.1.1",
67
67
  "@vueuse/core": "10.7.0",
68
68
  "consola": "3.2.3",
@@ -101,16 +101,16 @@
101
101
  "vue": ">=3.3.0"
102
102
  },
103
103
  "resolutions": {
104
- "@vue/compiler-core": "3.3.9",
105
- "@vue/shared": "3.3.9",
106
- "@vue/compiler-dom": "3.3.9",
107
- "@vue/compiler-sfc": "3.3.9",
108
- "@vue/compiler-ssr": "3.3.9",
109
- "@vue/reactivity-transform": "3.3.9",
110
- "@vue/reactivity": "3.3.9",
111
- "@vue/runtime-core": "3.3.9",
112
- "@vue/runtime-dom": "3.3.9",
113
- "@vue/server-renderer": "3.3.9"
104
+ "@vue/compiler-core": "3.3.12",
105
+ "@vue/shared": "3.3.12",
106
+ "@vue/compiler-dom": "3.3.12",
107
+ "@vue/compiler-sfc": "3.3.12",
108
+ "@vue/compiler-ssr": "3.3.12",
109
+ "@vue/reactivity-transform": "3.3.12",
110
+ "@vue/reactivity": "3.3.12",
111
+ "@vue/runtime-core": "3.3.12",
112
+ "@vue/runtime-dom": "3.3.12",
113
+ "@vue/server-renderer": "3.3.12"
114
114
  },
115
115
  "volta": {
116
116
  "node": "20.10.0"
@@ -1,6 +0,0 @@
1
- declare module '../../../module' {
2
- interface AdditionalShopConfig {
3
- paymentProviders: string[];
4
- }
5
- }
6
- export {};
@@ -1,277 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { createRequest, createResponse } from "node-mocks-http";
3
- import { createEvent } from "h3";
4
- import { getCurrentShopForRequest, getPublicShopData } from "./bootstrap.utils.mjs";
5
- const DOMAIN_DE = "de.scayle.example";
6
- const DOMAIN_AT = "at.scayle.example";
7
- const DOMAIN_US = "us.scayle.example";
8
- const CHECKOUT_HOST = "https://checkout.scayle.cloud";
9
- const baseShop = {
10
- appKeys: {
11
- wishlistKey: "wishlist_{shopId}_{userId}",
12
- basketKey: "basket_{shopId}_{userId}",
13
- hashAlgorithm: "sha256"
14
- },
15
- auth: {
16
- resetPasswordUrl: ""
17
- },
18
- domain: "demo.test",
19
- paymentProviders: [],
20
- checkout: {
21
- host: CHECKOUT_HOST,
22
- token: "",
23
- secret: "",
24
- user: ""
25
- }
26
- };
27
- describe("getCurrentShopForRequest", () => {
28
- it("respects the x-shop-id header", () => {
29
- const req = createRequest({
30
- url: "/api/getProducts",
31
- headers: {
32
- "x-shop-id": "1002"
33
- }
34
- });
35
- const moduleOptions = {
36
- shopSelector: "domain",
37
- stores: {
38
- DE_DE: {
39
- ...baseShop,
40
- shopId: 1001,
41
- domain: DOMAIN_DE,
42
- locale: "de-DE",
43
- currency: "EUR"
44
- },
45
- DE_AT: {
46
- ...baseShop,
47
- shopId: 1002,
48
- domain: DOMAIN_AT,
49
- locale: "de-AT",
50
- currency: "EUR"
51
- },
52
- DE_US: {
53
- ...baseShop,
54
- shopId: 1003,
55
- domain: DOMAIN_US,
56
- locale: "en-US",
57
- currency: "USD"
58
- }
59
- }
60
- };
61
- const shop = getCurrentShopForRequest(
62
- createEvent(req, createResponse()),
63
- moduleOptions
64
- );
65
- expect(shop.shopId).to.eq(1002);
66
- });
67
- it("falls back to the path when shopSelector = path", () => {
68
- const moduleOptions = {
69
- shopSelector: "path",
70
- stores: {
71
- DE_DE: {
72
- ...baseShop,
73
- shopId: 1001,
74
- path: "de",
75
- locale: "de-DE",
76
- currency: "EUR"
77
- },
78
- DE_AT: {
79
- ...baseShop,
80
- shopId: 1002,
81
- path: "at",
82
- locale: "de-AT",
83
- currency: "EUR"
84
- },
85
- EN_US: {
86
- ...baseShop,
87
- shopId: 1003,
88
- path: "foobar",
89
- locale: "en-US",
90
- currency: "USD"
91
- },
92
- DE_CH: {
93
- ...baseShop,
94
- shopId: 1004,
95
- path: "de-ch",
96
- locale: "de-CH",
97
- currency: "CHF"
98
- }
99
- }
100
- };
101
- expect(
102
- getCurrentShopForRequest(
103
- createEvent(
104
- createRequest({
105
- url: "https://de.scayle.example/foobar/men/shirts"
106
- }),
107
- createResponse()
108
- ),
109
- moduleOptions
110
- ).shopId
111
- ).to.eq(1003);
112
- expect(
113
- getCurrentShopForRequest(
114
- createEvent(
115
- createRequest({
116
- url: "/foobar/men/shirts"
117
- }),
118
- createResponse()
119
- ),
120
- moduleOptions
121
- ).shopId
122
- ).to.eq(1003);
123
- expect(
124
- getCurrentShopForRequest(
125
- createEvent(
126
- createRequest({
127
- url: "https://de.scayle.example/at/men/shirts"
128
- }),
129
- createResponse()
130
- ),
131
- moduleOptions
132
- ).shopId
133
- ).to.eq(1002);
134
- expect(
135
- getCurrentShopForRequest(
136
- createEvent(
137
- createRequest({
138
- url: "https://de.scayle.example/de-ch/men/shirts"
139
- }),
140
- createResponse()
141
- ),
142
- moduleOptions
143
- ).shopId
144
- ).to.eq(1004);
145
- });
146
- it("falls back to the domain when shopSelector = domain", () => {
147
- const req = createRequest({
148
- url: "https://de.scayle.example/at/frauen"
149
- });
150
- const moduleOptions = {
151
- shopSelector: "domain",
152
- stores: {
153
- DE_DE: {
154
- ...baseShop,
155
- shopId: 1001,
156
- domain: DOMAIN_DE,
157
- locale: "de-DE",
158
- currency: "EUR"
159
- },
160
- DE_AT: {
161
- ...baseShop,
162
- shopId: 1002,
163
- domain: DOMAIN_AT,
164
- locale: "de-AT",
165
- currency: "EUR"
166
- },
167
- EN_US: {
168
- ...baseShop,
169
- shopId: 1003,
170
- domain: DOMAIN_US,
171
- locale: "en-US",
172
- currency: "USD"
173
- }
174
- }
175
- };
176
- const shop = getCurrentShopForRequest(
177
- createEvent(req, createResponse()),
178
- moduleOptions
179
- );
180
- expect(shop.shopId).to.eq(1001);
181
- });
182
- it("falls back to the first shop when there is no match", () => {
183
- const req = createRequest({
184
- url: "https://de.scayle.example/foobar/men/shirts",
185
- headers: {
186
- "x-shop-id": "1005"
187
- }
188
- });
189
- const moduleOptions = {
190
- shopSelector: "domain",
191
- stores: {
192
- DE_DE: {
193
- ...baseShop,
194
- shopId: 1001,
195
- domain: DOMAIN_DE,
196
- locale: "de-DE",
197
- currency: "EUR"
198
- },
199
- DE_AT: {
200
- ...baseShop,
201
- shopId: 1002,
202
- domain: DOMAIN_AT,
203
- locale: "de-AT",
204
- currency: "EUR"
205
- },
206
- EN_US: {
207
- ...baseShop,
208
- shopId: 1003,
209
- domain: DOMAIN_US,
210
- locale: "en-US",
211
- currency: "USD"
212
- }
213
- }
214
- };
215
- const shop = getCurrentShopForRequest(
216
- createEvent(req, createResponse()),
217
- moduleOptions
218
- );
219
- expect(shop.shopId).to.eq(1001);
220
- });
221
- });
222
- describe("getPublicShopData", () => {
223
- it("excludes checkout secrets from the public shop data", () => {
224
- const shopConfig = {
225
- ...baseShop,
226
- shopId: 1003,
227
- domain: DOMAIN_US,
228
- path: "en",
229
- locale: "en-US",
230
- currency: "USD"
231
- };
232
- expect(getPublicShopData(shopConfig, 1003, "/api")).to.eql({
233
- shopId: 1003,
234
- domain: DOMAIN_US,
235
- path: "en",
236
- locale: "en-US",
237
- currency: "USD",
238
- isActive: true,
239
- checkout: {
240
- host: CHECKOUT_HOST
241
- },
242
- apiBasePath: "/api"
243
- });
244
- });
245
- it("includes additional shop data for keys in storefront.publicShopData", () => {
246
- const shopConfig = {
247
- ...baseShop,
248
- shopId: 1003,
249
- domain: DOMAIN_US,
250
- path: "en",
251
- locale: "en-US",
252
- currency: "USD",
253
- paymentProviders: ["visa", "klarna"],
254
- checkout: {
255
- host: CHECKOUT_HOST,
256
- token: "",
257
- secret: "",
258
- user: ""
259
- }
260
- };
261
- expect(
262
- getPublicShopData(shopConfig, 1003, "/api", ["paymentProviders"])
263
- ).to.eql({
264
- shopId: 1003,
265
- domain: DOMAIN_US,
266
- path: "en",
267
- locale: "en-US",
268
- currency: "USD",
269
- paymentProviders: ["visa", "klarna"],
270
- isActive: true,
271
- checkout: {
272
- host: CHECKOUT_HOST
273
- },
274
- apiBasePath: "/api"
275
- });
276
- });
277
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,66 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { getRedirectLookupUrls, getTargetLocation } from "./redirects.utils.mjs";
3
- describe("redirects module", () => {
4
- describe("getRedirectLookupUrls", () => {
5
- it("returns the relative and absolute URL", () => {
6
- expect(
7
- getRedirectLookupUrls(
8
- new URL("https://demo.example/de/frauen/kleidung"),
9
- /* @__PURE__ */ new Set()
10
- )
11
- ).to.eql({
12
- relativeSourceUrl: "/de/frauen/kleidung",
13
- absoluteSourceUrl: "https://demo.example/de/frauen/kleidung"
14
- });
15
- });
16
- it("strips trailing slashes", () => {
17
- expect(
18
- getRedirectLookupUrls(new URL("https://demo.example/men/"), /* @__PURE__ */ new Set())
19
- ).to.eql({
20
- relativeSourceUrl: "/men",
21
- absoluteSourceUrl: "https://demo.example/men"
22
- });
23
- });
24
- it("strips query params", () => {
25
- expect(
26
- getRedirectLookupUrls(
27
- new URL("https://demo.example/products?p=20&term=foo"),
28
- /* @__PURE__ */ new Set()
29
- )
30
- ).to.eql({
31
- relativeSourceUrl: "/products",
32
- absoluteSourceUrl: "https://demo.example/products"
33
- });
34
- });
35
- it("does not strip whitelisted query params", () => {
36
- expect(
37
- getRedirectLookupUrls(
38
- new URL("https://demo.example/test/page/?foo=1&bar=10"),
39
- /* @__PURE__ */ new Set(["bar"])
40
- )
41
- ).to.eql({
42
- relativeSourceUrl: "/test/page?bar=10",
43
- absoluteSourceUrl: "https://demo.example/test/page?bar=10"
44
- });
45
- });
46
- });
47
- describe("getTargetLocation", () => {
48
- it("uses the source as the base for relative URLs", () => {
49
- expect(
50
- getTargetLocation(
51
- new URL("http://demo.test/source/location"),
52
- "/target"
53
- )
54
- ).to.eq("http://demo.test/target");
55
- });
56
- it("copies non-whitelisted query params from source", () => {
57
- expect(
58
- getTargetLocation(
59
- new URL("http://demo.test/source?foo=10&bar=20"),
60
- "/redirect",
61
- /* @__PURE__ */ new Set(["foo"])
62
- )
63
- ).to.eq("http://demo.test/redirect?bar=20");
64
- });
65
- });
66
- });
@@ -1,11 +0,0 @@
1
- type BaseOptions = {
2
- locale: string;
3
- currencyFractionDigits?: number;
4
- };
5
- type FormatOptions = BaseOptions;
6
- type ToCurrencyOptions = BaseOptions & {
7
- currency: string;
8
- };
9
- export declare const toCurrency: (value: number, options?: ToCurrencyOptions) => string;
10
- export declare const formatPrice: (value: number, formatOptions?: FormatOptions) => string;
11
- export {};
@@ -1,32 +0,0 @@
1
- import { getDefaultFractionDigits } from "@scayle/storefront-core";
2
- import { useCurrentShop } from "../composables/core/useCurrentShop.mjs";
3
- export const toCurrency = (value, options) => {
4
- const currentShop = useCurrentShop();
5
- const {
6
- locale = currentShop.value.locale,
7
- currency = currentShop.value.currency,
8
- currencyFractionDigits = currentShop.value.currencyFractionDigits
9
- } = options || {};
10
- const minimumFractionDigits = getDefaultFractionDigits(locale, currency);
11
- return (value / 100).toLocaleString(locale, {
12
- style: "currency",
13
- ...currencyFractionDigits && {
14
- minimumFractionDigits: Math.min(
15
- minimumFractionDigits,
16
- currencyFractionDigits
17
- )
18
- },
19
- maximumFractionDigits: currencyFractionDigits,
20
- currency
21
- });
22
- };
23
- export const formatPrice = (value, formatOptions) => {
24
- const currentShop = useCurrentShop();
25
- const {
26
- locale = currentShop.value.locale,
27
- currencyFractionDigits = currentShop.value.currencyFractionDigits
28
- } = formatOptions || {};
29
- return (value / 100).toLocaleString(locale, {
30
- minimumFractionDigits: currencyFractionDigits
31
- });
32
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1,83 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import { ref } from "vue";
3
- import { toCurrency, formatPrice } from "./price.mjs";
4
- describe("Price utils", () => {
5
- vi.mock("../composables/core/useCurrentShop", () => ({
6
- useCurrentShop: () => ref({
7
- locale: "de-DE",
8
- currency: "EUR",
9
- currencyFractionDigits: 2
10
- })
11
- }));
12
- describe("toCurrency", () => {
13
- it("should return value with EUR currency", () => {
14
- const options = {
15
- locale: "de-DE",
16
- currency: "EUR",
17
- currencyFractionDigits: 2
18
- };
19
- const currency = toCurrency(200, options);
20
- expect(currency).be.eq("2,00\xA0\u20AC");
21
- });
22
- it("should return value with EUR currency with default options", () => {
23
- const currency = toCurrency(200);
24
- expect(currency).be.eq("2,00\xA0\u20AC");
25
- });
26
- it("should return value with EUR currency with default options", () => {
27
- const currency = toCurrency(200);
28
- expect(currency).be.eq("2,00\xA0\u20AC");
29
- });
30
- it("should return value with USD currency", () => {
31
- const options = {
32
- locale: "de-DE",
33
- currency: "USD",
34
- currencyFractionDigits: 2
35
- };
36
- const currency = toCurrency(200, options);
37
- expect(currency).be.eq("2,00\xA0$");
38
- });
39
- it("should return value with one fraction digit", () => {
40
- const options = {
41
- locale: "de-DE",
42
- currency: "USD",
43
- currencyFractionDigits: 1
44
- };
45
- const currency = toCurrency(200, options);
46
- expect(currency).be.eq("2,0\xA0$");
47
- });
48
- it("should return value with two fraction digits if no fraction digits set", () => {
49
- const options = {
50
- locale: "de-DE",
51
- currency: "USD"
52
- };
53
- const currency = toCurrency(200, options);
54
- expect(currency).be.eq("2,00\xA0$");
55
- });
56
- it("should return value properly formatted for en-US locale", () => {
57
- const options = {
58
- locale: "en-US",
59
- currency: "USD"
60
- };
61
- const currency = toCurrency(200, options);
62
- expect(currency).be.eq("$2.00");
63
- });
64
- });
65
- describe("formatPrice", () => {
66
- it("should return formatted price with two fraction digits", () => {
67
- const options = {
68
- locale: "en-US",
69
- currencyFractionDigits: 2
70
- };
71
- const price = formatPrice(200, options);
72
- expect(price).be.eq("2.00");
73
- });
74
- it("should return formatted price with one fraction digits", () => {
75
- const options = {
76
- locale: "en-US",
77
- currencyFractionDigits: 1
78
- };
79
- const price = formatPrice(200, options);
80
- expect(price).be.eq("2.0");
81
- });
82
- });
83
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,15 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { getCurrentPage } from "./route.mjs";
3
- describe("getCurrentPage", () => {
4
- it("should return parsed current page", () => {
5
- const page = getCurrentPage({ page: "20" });
6
- expect(page).be.equal(20);
7
- });
8
- it("should return undefined if page does not exist inside the query", () => {
9
- const page = getCurrentPage({});
10
- expect(page).be.equal(void 0);
11
- });
12
- it("should return undefined if page is not a string", () => {
13
- expect(getCurrentPage({ page: ["1", "2"] })).toBe(void 0);
14
- });
15
- });