cloudcommerce 2.7.5 → 2.8.8

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/ecomplus-stores/barradoce/functions/many/package.json +3 -3
  3. package/ecomplus-stores/barradoce/functions/ssr/package.json +6 -6
  4. package/ecomplus-stores/barradoce/functions/ssr/src/components/Banner.vue +6 -4
  5. package/ecomplus-stores/barradoce/functions/ssr/src/components/CheckoutPage.vue +2 -2
  6. package/ecomplus-stores/barradoce/functions/ssr/src/components/ProductCard.vue +5 -3
  7. package/ecomplus-stores/barradoce/functions/ssr/src/components/SearchModal.vue +3 -2
  8. package/ecomplus-stores/barradoce/functions/ssr/src/components/ShopHeaderMenu.vue +12 -12
  9. package/ecomplus-stores/barradoce/functions/ssr/src/components/ShopHeaderSubmenu.vue +17 -12
  10. package/ecomplus-stores/barradoce/functions/ssr/src/components/ShopSidenavCategory.vue +11 -9
  11. package/ecomplus-stores/barradoce/functions/ssr/src/main/Fallback.astro +23 -13
  12. package/ecomplus-stores/barradoce/functions/ssr/src/pages/404.astro +30 -0
  13. package/ecomplus-stores/barradoce/functions/with-apps/package.json +3 -3
  14. package/ecomplus-stores/barradoce/package.json +2 -2
  15. package/package.json +4 -4
  16. package/packages/api/package.json +1 -1
  17. package/packages/apps/affiliate-program/package.json +2 -2
  18. package/packages/apps/correios/package.json +3 -3
  19. package/packages/apps/custom-payment/package.json +1 -1
  20. package/packages/apps/custom-shipping/package.json +1 -1
  21. package/packages/apps/datafrete/package.json +2 -2
  22. package/packages/apps/discounts/package.json +1 -1
  23. package/packages/apps/emails/package.json +2 -2
  24. package/packages/apps/fb-conversions/package.json +2 -2
  25. package/packages/apps/flash-courier/package.json +2 -2
  26. package/packages/apps/frenet/package.json +2 -2
  27. package/packages/apps/galaxpay/package.json +2 -2
  28. package/packages/apps/google-analytics/package.json +2 -2
  29. package/packages/apps/jadlog/package.json +1 -1
  30. package/packages/apps/loyalty-points/package.json +1 -1
  31. package/packages/apps/mandae/package.json +2 -2
  32. package/packages/apps/melhor-envio/package.json +2 -2
  33. package/packages/apps/mercadopago/package.json +2 -2
  34. package/packages/apps/pagarme/package.json +3 -3
  35. package/packages/apps/pagarme-v5/package.json +2 -2
  36. package/packages/apps/paghiper/package.json +2 -2
  37. package/packages/apps/pix/package.json +2 -2
  38. package/packages/apps/tiny-erp/package.json +2 -2
  39. package/packages/apps/webhooks/package.json +2 -2
  40. package/packages/cli/lib/cli.js +3 -3
  41. package/packages/cli/package.json +1 -1
  42. package/packages/cli/src/cli.ts +3 -3
  43. package/packages/config/package.json +1 -1
  44. package/packages/emails/package.json +2 -2
  45. package/packages/eslint/package.json +1 -1
  46. package/packages/events/package.json +2 -2
  47. package/packages/feeds/package.json +1 -1
  48. package/packages/firebase/package.json +3 -3
  49. package/packages/i18n/package.json +1 -1
  50. package/packages/modules/package.json +2 -2
  51. package/packages/passport/package.json +2 -2
  52. package/packages/ssr/lib/lib/serve-storefront.js +5 -1
  53. package/packages/ssr/lib/lib/serve-storefront.js.map +1 -1
  54. package/packages/ssr/package.json +4 -4
  55. package/packages/ssr/src/lib/serve-storefront.ts +5 -1
  56. package/packages/storefront/astro.config.mjs +1 -0
  57. package/packages/storefront/client.d.ts +1 -0
  58. package/packages/storefront/config/astro/client-sf-directive.mjs +0 -3
  59. package/packages/storefront/config/storefront.tailwind.cjs +13 -0
  60. package/packages/storefront/config/storefront.unocss.cjs +20 -18
  61. package/packages/storefront/package.json +4 -4
  62. package/packages/storefront/src/lib/components/globals/ALink.vue +48 -2
  63. package/packages/storefront/src/lib/composables/use-product-shelf.ts +2 -2
  64. package/packages/storefront/src/lib/composables/use-search-showcase.ts +2 -2
  65. package/packages/storefront/src/lib/composables/use-shipping-calculator.ts +6 -3
  66. package/packages/storefront/src/lib/composables/use-shop-header.ts +10 -7
  67. package/packages/storefront/src/lib/composables/use-sku-selector.ts +1 -1
  68. package/packages/storefront/src/lib/layouts/Base.astro +5 -0
  69. package/packages/storefront/src/lib/layouts/BaseHead.astro +5 -10
  70. package/packages/storefront/src/lib/scripts/push-analytics-events.ts +4 -5
  71. package/packages/storefront/src/lib/state/use-analytics.ts +10 -4
  72. package/packages/test-base/package.json +1 -1
  73. package/packages/types/package.json +1 -1
  74. package/packages/storefront/src/lib/components/ViewTransitions.astro +0 -426
@@ -227,6 +227,19 @@ const genTailwindConfig = (themeOptions = {}) => {
227
227
  };
228
228
  return utilities;
229
229
  }, {}),
230
+ // Inspired by https://www.tailwindcss-animated.com/configurator.html
231
+ '.animate-once': {
232
+ 'animation-iteration-count': '1',
233
+ },
234
+ '.animate-twice': {
235
+ 'animation-iteration-count': '2',
236
+ },
237
+ '.animate-thrice': {
238
+ 'animation-iteration-count': '3',
239
+ },
240
+ '.animate-infinite': {
241
+ 'animation-iteration-count': 'infinite',
242
+ },
230
243
  });
231
244
  addVariant('sticky-header', 'body.StickyHeader &');
232
245
  },
@@ -94,29 +94,31 @@ const genUnoCSSConfig = (_tailwindConfig) => {
94
94
  ...theme
95
95
  } = tailwindConfig.theme.extend;
96
96
  if (themeAnimation) {
97
- Object.keys(themeAnimation).forEach((animation) => {
98
- let keyframes = '';
99
- const keyframesObj = themeKeyframes?.[animation];
100
- if (keyframesObj) {
101
- Object.keys(keyframesObj).forEach((point) => {
102
- const css = keyframesObj[point];
103
- keyframes += ` ${point} {`;
104
- Object.keys(css).forEach((prop) => {
105
- keyframes += ` ${prop}: ${css[prop]};`;
97
+ // Ref.: https://github.com/animated-unocss/animated-unocss/blob/main/src/animated.ts
98
+ // Copy paste keyframes: https://animate.zyob.top/
99
+ rules.push([
100
+ new RegExp(`^animate-(${Object.keys(themeAnimation).join('|')})$`),
101
+ ([, animation]) => {
102
+ let keyframes = '';
103
+ const keyframesObj = themeKeyframes?.[animation];
104
+ if (keyframesObj) {
105
+ Object.keys(keyframesObj).forEach((point) => {
106
+ const css = keyframesObj[point];
107
+ keyframes += ` ${point} {`;
108
+ Object.keys(css).forEach((prop) => {
109
+ keyframes += ` ${prop}: ${css[prop]};`;
110
+ });
111
+ keyframes += ' }';
106
112
  });
107
- keyframes += ' }';
108
- });
109
- }
110
- rules.push([
111
- `animate-${animation}`,
112
- [
113
+ }
114
+ return [
113
115
  keyframes
114
116
  ? `@keyframes ${animation} {${keyframes} }`
115
117
  : '',
116
118
  { animation: themeAnimation[animation] },
117
- ],
118
- ]);
119
- });
119
+ ];
120
+ },
121
+ ]);
120
122
  }
121
123
  return defineConfig({
122
124
  preflights,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/storefront",
3
3
  "type": "module",
4
- "version": "2.7.5",
4
+ "version": "2.8.8",
5
5
  "description": "E-Com Plus Cloud Commerce storefront with Astro",
6
6
  "bin": {
7
7
  "storefront": "./scripts/build-prod.sh"
@@ -44,7 +44,7 @@
44
44
  "@vite-pwa/astro": "^0.3.0",
45
45
  "@vueuse/core": "10.9.0",
46
46
  "@webcontainer/api": "^1.1.9",
47
- "astro": "4.4.9",
47
+ "astro": "4.5.0",
48
48
  "astro-capo": "^0.0.1",
49
49
  "chroma-js": "^2.4.2",
50
50
  "dotenv": "^16.4.5",
@@ -61,11 +61,11 @@
61
61
  "vite-plugin-pwa": "^0.19.2",
62
62
  "vue": "^3.4.21",
63
63
  "wade": "0.3.3",
64
- "yaml": "^2.4.0"
64
+ "yaml": "^2.4.1"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@cloudcommerce/eslint": "workspace:*",
68
68
  "@cloudcommerce/types": "workspace:*",
69
- "@types/react": "^18.2.62"
69
+ "@types/react": "^18.2.64"
70
70
  }
71
71
  }
@@ -1,12 +1,23 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue';
2
+ import {
3
+ ref,
4
+ computed,
5
+ watch,
6
+ onMounted,
7
+ } from 'vue';
8
+ import { useElementVisibility, useElementHover } from '@vueuse/core';
9
+ import { isMobile, requestIdleCallback } from '@@sf/sf-lib';
3
10
 
4
11
  export interface Props {
5
12
  href?: string | null;
6
13
  target?: string;
14
+ prefetch?: 'hover' | 'visible' | 'never';
7
15
  }
8
16
 
9
- const props = defineProps<Props>();
17
+ const props = withDefaults(defineProps<Props>(), {
18
+ prefetch: 'hover',
19
+ });
20
+ const link = ref<HTMLElement | null>(null);
10
21
  const linkTarget = computed(() => {
11
22
  if (!props.href) return undefined;
12
23
  if (props.target) return props.target;
@@ -17,10 +28,45 @@ const linkTarget = computed(() => {
17
28
  }
18
29
  return undefined;
19
30
  });
31
+ const prefetchHref = computed(() => {
32
+ if (import.meta.env.SSR || !props.href || linkTarget.value) return null;
33
+ const pathname = props.href.replace(/^(https:\/\/[^/]+)?([^#?]+).*$/i, '$2');
34
+ if (pathname.startsWith('/app/') || pathname === window.location.pathname) {
35
+ return null;
36
+ }
37
+ return pathname;
38
+ });
39
+ if (prefetchHref.value) {
40
+ onMounted(() => {
41
+ const { prefetch } = props;
42
+ const isOnHover = prefetch === 'hover';
43
+ if (isMobile && isOnHover) return;
44
+ const isOnVisible = prefetch === 'visible';
45
+ const useElementEv = isOnVisible
46
+ ? useElementVisibility
47
+ : isOnHover && useElementHover;
48
+ if (!useElementEv) return;
49
+ const isActive = useElementEv(link.value);
50
+ const unwatch = watch(isActive, (_isActive) => {
51
+ if (!_isActive || !window.$prefetch) return;
52
+ unwatch();
53
+ setTimeout(() => {
54
+ if (isOnVisible && !isActive.value) return;
55
+ requestIdleCallback(() => {
56
+ if (!prefetchHref.value) return;
57
+ window.$prefetch!(prefetchHref.value);
58
+ });
59
+ }, isOnVisible ? 100 : 1);
60
+ }, {
61
+ immediate: true,
62
+ });
63
+ });
64
+ }
20
65
  </script>
21
66
 
22
67
  <template>
23
68
  <component
69
+ ref="link"
24
70
  :is="href ? 'a' : 'span'"
25
71
  :href="href"
26
72
  :target="linkTarget"
@@ -32,7 +32,7 @@ const useProductShelf = (props: Props) => {
32
32
  if (!props.products) {
33
33
  isFetching.value = true;
34
34
  fetching = (async () => {
35
- const limit = props.limit || 24;
35
+ const limit = props.limit || 12;
36
36
  const offset = props.page ? (props.page - 1) * limit : 0;
37
37
  let endpointQuery = `offset=${offset}&limit=${limit}`;
38
38
  if (props.sort) {
@@ -41,7 +41,7 @@ const useProductShelf = (props: Props) => {
41
41
  if (props.isRelatedProducts) {
42
42
  const { apiContext } = globalThis.$storefront;
43
43
  if (apiContext?.resource === 'products') {
44
- endpointQuery = `like=${apiContext.doc._id}`;
44
+ endpointQuery += `like=${apiContext.doc._id}`;
45
45
  if (!title.value && title.value !== null) {
46
46
  title.value = i19relatedProducts;
47
47
  }
@@ -8,7 +8,7 @@ import {
8
8
  watch,
9
9
  shallowReactive,
10
10
  } from 'vue';
11
- import { useUrlSearchParams, watchOnce } from '@vueuse/core';
11
+ import { useUrlSearchParams } from '@vueuse/core';
12
12
  import { isScreenLg, scrollToEl } from '@@sf/sf-lib';
13
13
  import {
14
14
  i19discount,
@@ -145,7 +145,7 @@ const useSearchShowcase = (props: Props) => {
145
145
  if (searchEngine.wasFetched.value) {
146
146
  startWatchingFetch();
147
147
  } else {
148
- watchOnce(searchEngine.wasFetched, startWatchingFetch);
148
+ watch(searchEngine.wasFetched, startWatchingFetch, { once: true });
149
149
  }
150
150
 
151
151
  const { activeFilters, filtersCount } = useSearchActiveFilters({
@@ -13,7 +13,7 @@ import {
13
13
  watch,
14
14
  toRef,
15
15
  } from 'vue';
16
- import { useDebounceFn, watchOnce } from '@vueuse/core';
16
+ import { useDebounceFn } from '@vueuse/core';
17
17
  import { price as getPrice, formatMoney } from '@ecomplus/utils';
18
18
  import config from '@cloudcommerce/config';
19
19
  import {
@@ -120,8 +120,11 @@ export const useShippingCalculator = (props: Props) => {
120
120
  const isFetching = ref(false);
121
121
  const fetchShippingServices = useDebounceFn((isRetry?: boolean) => {
122
122
  if (isFetching.value) {
123
- watchOnce((isFetching), (_isFetching) => {
124
- if (!_isFetching) fetchShippingServices();
123
+ const unwatch = watch((isFetching), (_isFetching) => {
124
+ if (!_isFetching) {
125
+ fetchShippingServices();
126
+ unwatch();
127
+ }
125
128
  });
126
129
  return;
127
130
  }
@@ -1,7 +1,6 @@
1
1
  import type { Ref } from 'vue';
2
2
  import type { Categories } from '@cloudcommerce/api/types';
3
3
  import { ref, computed, watch } from 'vue';
4
- import { watchOnce } from '@vueuse/core';
5
4
  import { getSearchUrl } from '@@sf/sf-lib';
6
5
  import { totalItems } from '@@sf/state/shopping-cart';
7
6
  import useStickyHeader from '@@sf/composables/use-sticky-header';
@@ -128,9 +127,11 @@ const useShopHeader = (props: Props) => {
128
127
 
129
128
  const isSearchOpen = ref(false);
130
129
  const isSearchOpenOnce = ref(false);
131
- watchOnce(isSearchOpen, () => {
132
- isSearchOpenOnce.value = true;
133
- });
130
+ if (!import.meta.env.SSR) {
131
+ watch(isSearchOpen, () => {
132
+ isSearchOpenOnce.value = true;
133
+ }, { once: true });
134
+ }
134
135
  const searchTerm = ref('');
135
136
  const isSearchPage = !import.meta.env.SSR && /^\/s\/?/.test(window.location.pathname);
136
137
  let urlSearchQ: string | null | undefined;
@@ -169,9 +170,11 @@ const useShopHeader = (props: Props) => {
169
170
  };
170
171
  const isCartOpen = ref(false);
171
172
  const isCartOpenOnce = ref(false);
172
- watchOnce(isCartOpen, () => {
173
- isCartOpenOnce.value = true;
174
- });
173
+ if (!import.meta.env.SSR) {
174
+ watch(isCartOpen, () => {
175
+ isCartOpenOnce.value = true;
176
+ }, { once: true });
177
+ }
175
178
  const delayedCartItems = ref(0);
176
179
  const handleOnMounted = () => {
177
180
  watch(totalItems, (newTotalItems, prevTotalItems) => {
@@ -27,7 +27,7 @@ const useSkuSelector = (props: Props) => {
27
27
  || [],
28
28
  );
29
29
  if (!grids.length && !import.meta.env.SSR) {
30
- window.addEventListener('storefront:data:data', () => {
30
+ window.addEventListener('storefront:data:grids', () => {
31
31
  globalThis.$storefront.data.grids?.forEach((grid) => grids.push(grid));
32
32
  }, { once: true });
33
33
  }
@@ -21,6 +21,11 @@ const { customCode } = await getContent('layout');
21
21
  <slot name="base-body-scripts">
22
22
  <script src="../scripts/session-utm"></script>
23
23
  <script src="../scripts/push-analytics-events"></script>
24
+ <script>
25
+ /* eslint-disable */
26
+ import { prefetch } from 'astro:prefetch';
27
+ window.$prefetch = prefetch;
28
+ </script>
24
29
  </slot>
25
30
  <slot name="before-body-end" />
26
31
  </BaseBody>
@@ -2,16 +2,9 @@
2
2
  import { pwaInfo } from 'virtual:pwa-info';
3
3
  import { img as getImg, price as getPrice } from '@ecomplus/utils';
4
4
  import { i19searchProducts } from '@@i18n';
5
- import ViewTransitions from '@@sf/components/ViewTransitions.astro';
6
-
7
- export interface Props {
8
- hasViewTransitions?: boolean;
9
- }
10
5
 
11
6
  // @ts-ignore
12
7
  const isPWA = pwaInfo !== false; // config/astro/mock-pwa-info.mjs
13
- const hasViewTransitions = Astro.props.hasViewTransitions !== false
14
- && !Astro.url.pathname.startsWith('/app/');
15
8
  const {
16
9
  storeId,
17
10
  isHomepage,
@@ -107,6 +100,9 @@ window.GIT_BRANCH = '${import.meta.env.GIT_BRANCH || ''}';
107
100
  window.$storefront = ${JSON.stringify({ settings, data: {} })};`;
108
101
  if (apiContext.error) {
109
102
  const { message, statusCode } = apiContext.error;
103
+ if (statusCode) {
104
+ Astro.response.status = statusCode;
105
+ }
110
106
  const url = Astro.url.pathname;
111
107
  inlineClientJS += `
112
108
  console.error(${JSON.stringify(message)});
@@ -210,8 +206,7 @@ const generator = `e-com.plus @cloudcommerce/storefront, ${Astro.generator}`;
210
206
  && <link rel="manifest" href="/manifest.webmanifest" />}
211
207
  </>}
212
208
 
213
- <script is:inline set:html={inlineClientJS} transition:persist />
214
- <script type="application/ld+json" set:html={inlineJSONLd} />
209
+ <script is:inline set:html={inlineClientJS} />
210
+ <script is:inline type="application/ld+json" set:html={inlineJSONLd} />
215
211
 
216
- {hasViewTransitions && <ViewTransitions fallback="none" />}
217
212
  {contextInlineClientJS && <script is:inline set:html={contextInlineClientJS} />}
@@ -84,16 +84,15 @@ if (
84
84
  });
85
85
  });
86
86
 
87
- let lastPageLocation = '';
87
+ let lastHref = '';
88
88
  const sendPageView = () => {
89
- const pageLocation = window.location.toString();
90
- if (pageLocation === lastPageLocation) return;
89
+ const href = window.location.toString();
90
+ if (href === lastHref) return;
91
91
  emitGtagEvent('page_view', {
92
92
  ...getPageViewParams(),
93
- page_location: pageLocation,
94
93
  client_id: trackingIds.g_client_id || trackingIds.client_id,
95
94
  });
96
- lastPageLocation = pageLocation;
95
+ lastHref = href;
97
96
  };
98
97
  sendPageView();
99
98
  window.addEventListener('storefront:apiContext', () => {
@@ -1,6 +1,5 @@
1
1
  import type { Products, Carts, SearchItem } from '@cloudcommerce/types';
2
2
  import { watch } from 'vue';
3
- import { watchOnce } from '@vueuse/core';
4
3
  import { price as getPrice, name as getName } from '@ecomplus/utils';
5
4
  import { customer, isLogged } from '@@sf/state/customer-session';
6
5
  import { cartEvents } from '@@sf/state/shopping-cart';
@@ -44,8 +43,16 @@ if (!import.meta.env.SSR) {
44
43
  }
45
44
 
46
45
  export const getPageViewParams = () => {
46
+ let pageLocation = '';
47
+ if (window.location.pathname.startsWith('/~')) {
48
+ const urlParams = new URLSearchParams(window.location.search);
49
+ pageLocation = urlParams.get('url') || '';
50
+ }
51
+ if (!pageLocation) {
52
+ pageLocation = window.location.toString();
53
+ }
47
54
  return {
48
- page_location: window.location.toString(),
55
+ page_location: pageLocation,
49
56
  language: globalThis.$storefront.settings.lang || 'pt_br',
50
57
  page_title: document.title,
51
58
  user_agent: navigator.userAgent,
@@ -222,7 +229,6 @@ export const useAnalytics = ({
222
229
  }: {
223
230
  experimentId?: string,
224
231
  } = {}) => {
225
- document.addEventListener('astro:beforeload', resetPageViewPromise);
226
232
  const {
227
233
  gtag,
228
234
  GTAG_TAG_ID,
@@ -288,7 +294,7 @@ export const useAnalytics = ({
288
294
  if (isLogged.value) {
289
295
  emitGtagEvent('login', {});
290
296
  } else {
291
- watchOnce(isLogged, () => emitGtagEvent('login', {}));
297
+ watch(isLogged, () => emitGtagEvent('login', {}), { once: true });
292
298
  }
293
299
  cartEvents.on('*', (evName, cartItem) => {
294
300
  emitGtagEvent(
@@ -2,7 +2,7 @@
2
2
  "name": "@cloudcommerce/test-base",
3
3
  "private": true,
4
4
  "type": "module",
5
- "version": "2.7.5",
5
+ "version": "2.8.8",
6
6
  "description": "E-Com Plus Cloud Commerce basic setup for testing",
7
7
  "main": "lib/index.js",
8
8
  "repository": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/types",
3
3
  "type": "module",
4
- "version": "2.7.5",
4
+ "version": "2.8.8",
5
5
  "description": "E-Com Plus Cloud Commerce reusable type definitions",
6
6
  "main": "index.ts",
7
7
  "repository": {