cloudcommerce 0.4.1 → 0.6.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.
Files changed (110) hide show
  1. package/.github/renovate.json +1 -1
  2. package/CHANGELOG.md +52 -0
  3. package/action.yml +1 -2
  4. package/package.json +7 -7
  5. package/packages/api/package.json +1 -1
  6. package/packages/apps/correios/package.json +1 -1
  7. package/packages/apps/custom-payment/package.json +1 -1
  8. package/packages/apps/custom-shipping/package.json +1 -1
  9. package/packages/apps/datafrete/package.json +1 -1
  10. package/packages/apps/discounts/package.json +1 -1
  11. package/packages/apps/emails/package.json +1 -1
  12. package/packages/apps/fb-conversions/package.json +1 -1
  13. package/packages/apps/frenet/package.json +1 -1
  14. package/packages/apps/galaxpay/package.json +1 -1
  15. package/packages/apps/google-analytics/package.json +1 -1
  16. package/packages/apps/infinitepay/package.json +1 -1
  17. package/packages/apps/jadlog/package.json +1 -1
  18. package/packages/apps/loyalty-points/package.json +1 -1
  19. package/packages/apps/melhor-envio/package.json +1 -1
  20. package/packages/apps/mercadopago/package.json +1 -1
  21. package/packages/apps/pagarme/package.json +2 -2
  22. package/packages/apps/paghiper/package.json +1 -1
  23. package/packages/apps/pix/package.json +1 -1
  24. package/packages/apps/tiny-erp/package.json +1 -1
  25. package/packages/apps/webhooks/package.json +3 -3
  26. package/packages/cli/package.json +1 -1
  27. package/packages/config/package.json +1 -1
  28. package/packages/emails/package.json +1 -1
  29. package/packages/events/package.json +1 -1
  30. package/packages/firebase/package.json +1 -1
  31. package/packages/i18n/package.json +1 -1
  32. package/packages/modules/lib/firebase/checkout.js +4 -1
  33. package/packages/modules/lib/firebase/checkout.js.map +1 -1
  34. package/packages/modules/package.json +1 -1
  35. package/packages/modules/src/firebase/checkout.ts +4 -1
  36. package/packages/passport/package.json +1 -1
  37. package/packages/ssr/package.json +3 -3
  38. package/packages/storefront/client.d.ts +23 -3
  39. package/packages/storefront/config/storefront.cms.cjs +31 -5
  40. package/packages/storefront/config/storefront.cms.mjs +31 -5
  41. package/packages/storefront/dist/client/_astro/PitchBar.457658a3.js +1 -0
  42. package/packages/storefront/dist/client/_astro/Prices.a1302bf9.js +1 -0
  43. package/packages/storefront/dist/client/_astro/ProductCard.1a45764a.js +1 -0
  44. package/packages/storefront/dist/client/_astro/ShopHeader.0a6766ac.js +1 -0
  45. package/packages/storefront/dist/client/_astro/_...slug_.6721f699.css +1 -0
  46. package/packages/storefront/dist/client/_astro/_plugin-vue_export-helper.6da04e63.js +1 -0
  47. package/packages/storefront/dist/client/_astro/client.b854166f.js +1 -0
  48. package/packages/storefront/dist/client/_astro/firebase-app.7ce2ebb1.js +1426 -0
  49. package/packages/storefront/dist/client/_astro/format-money.6f464cee.js +1 -0
  50. package/packages/storefront/dist/client/_astro/hoisted.721ad75d.js +1 -0
  51. package/packages/storefront/dist/client/_astro/idle-callback.889bf0ea.js +1 -0
  52. package/packages/storefront/dist/client/_astro/index.a500792d.js +1 -0
  53. package/packages/storefront/dist/client/_astro/modules-info.80ae4e30.js +1 -0
  54. package/packages/storefront/dist/client/_astro/preload-helper.101896b7.js +1 -0
  55. package/packages/storefront/dist/client/_astro/runtime-dom.esm-bundler.acde10ec.js +1 -0
  56. package/packages/storefront/dist/client/fallback/index.html +8 -8
  57. package/packages/storefront/dist/client/sw.js +1 -1
  58. package/packages/storefront/dist/server/chunks/{astro.0f5b754a.mjs → astro.7d9d5f6e.mjs} +100 -38
  59. package/packages/storefront/dist/server/chunks/pages/{all.671e6bc1.mjs → all.e0f284c9.mjs} +980 -660
  60. package/packages/storefront/dist/server/chunks/{prerender.fd8cdc24.mjs → prerender.9f6cbb00.mjs} +0 -0
  61. package/packages/storefront/dist/server/entry.mjs +100 -48
  62. package/packages/storefront/package.json +8 -8
  63. package/packages/storefront/server.d.ts +34 -0
  64. package/packages/storefront/src/env.d.ts +1 -0
  65. package/packages/storefront/src/helpers/afetch.ts +3 -1
  66. package/packages/storefront/src/helpers/idle-callback.ts +9 -0
  67. package/packages/storefront/src/lib/assets/base.css +6 -0
  68. package/packages/storefront/src/lib/browser-env.ts +22 -0
  69. package/packages/storefront/src/lib/cms.d.ts +25 -0
  70. package/packages/storefront/src/lib/components/Drawer.vue +1 -1
  71. package/packages/storefront/src/lib/components/LoginForm.vue +13 -9
  72. package/packages/storefront/src/lib/components/SocialNetworkIcon.vue +29 -0
  73. package/packages/storefront/src/lib/components/SocialNetworkLink.vue +37 -0
  74. package/packages/storefront/src/lib/components/globals/ALink.vue +2 -2
  75. package/packages/storefront/src/lib/composables/use-shop-header.ts +79 -0
  76. package/packages/storefront/src/lib/layouts/Base.astro +4 -5
  77. package/packages/storefront/src/lib/layouts/BaseHead.astro +7 -7
  78. package/packages/storefront/src/lib/layouts/BaseStateJson.astro +1 -1
  79. package/packages/storefront/src/lib/layouts/PagesHeader.astro +5 -23
  80. package/packages/storefront/src/lib/scripts/firebase-app.ts +16 -3
  81. package/packages/storefront/src/lib/server-data.ts +25 -0
  82. package/packages/storefront/src/lib/ssr-context.ts +11 -10
  83. package/packages/storefront/src/lib/state/customer-session.ts +51 -30
  84. package/packages/storefront/src/lib/state/modules-info.ts +3 -6
  85. package/packages/storefront/tailwind.config.cjs +1 -4
  86. package/packages/types/index.ts +7 -0
  87. package/packages/types/package.json +1 -1
  88. package/pnpm-workspace.yaml +3 -3
  89. package/packages/storefront/dist/client/_astro/PitchBar.004b6ea4.js +0 -1
  90. package/packages/storefront/dist/client/_astro/Prices.f311909a.js +0 -1
  91. package/packages/storefront/dist/client/_astro/Prices.vue_vue_type_script_setup_true_lang.ef47de70.js +0 -1
  92. package/packages/storefront/dist/client/_astro/ProductCard.34de5097.js +0 -1
  93. package/packages/storefront/dist/client/_astro/ShopHeader.cbfee289.js +0 -1
  94. package/packages/storefront/dist/client/_astro/_...slug_.bcc33d9d.css +0 -1
  95. package/packages/storefront/dist/client/_astro/client.56d86c9b.js +0 -1
  96. package/packages/storefront/dist/client/_astro/ecom-utils.92f137f6.js +0 -1
  97. package/packages/storefront/dist/client/_astro/hoisted.6edd7364.js +0 -1
  98. package/packages/storefront/dist/client/_astro/index.2d12be6c.js +0 -1
  99. package/packages/storefront/dist/client/_astro/modules-info.0debb0b0.js +0 -1
  100. package/packages/storefront/dist/client/_astro/runtime-core.esm-bundler.a0432a8e.js +0 -1
  101. package/packages/storefront/dist/client/_astro/runtime-dom.esm-bundler.0e5774ce.js +0 -1
  102. package/packages/storefront/src/lib/components/ADrawer.vue +0 -110
  103. package/packages/storefront/src/lib/components/LoginDrawer.vue +0 -82
  104. package/packages/storefront/src/lib/components/ShopHeader.vue +0 -111
  105. package/packages/storefront/src/lib/components/ShopSidenav.vue +0 -26
  106. package/packages/storefront/src/lib/types/cms-code.d.ts +0 -5
  107. package/packages/storefront/src/lib/types/cms-contacts.d.ts +0 -5
  108. package/packages/storefront/src/lib/types/cms-header.d.ts +0 -5
  109. package/packages/storefront/src/lib/types/cms-settings.d.ts +0 -8
  110. package/packages/storefront/src/lib/types/cms-social.d.ts +0 -5
@@ -4,12 +4,10 @@ import {
4
4
  i19accessMyAccount,
5
5
  i19createAnAccount,
6
6
  i19enterWithPassword,
7
- i19hello,
8
7
  i19iForgotMyPassword,
9
8
  i19password,
10
9
  i19sendLoginCodeByEmail,
11
10
  i19signUp,
12
- i19visitor,
13
11
  } from '@@i18n';
14
12
  import {
15
13
  getAuth,
@@ -22,9 +20,20 @@ import {
22
20
  isLogged,
23
21
  } from '@@sf/state/customer-session';
24
22
 
25
- const emit = defineEmits(['login', 'logout']);
23
+ // eslint-disable-next-line no-spaced-func, func-call-spacing
24
+ const emit = defineEmits<{
25
+ (e: 'set:is-logged', value: boolean): void
26
+ (e: 'set:email', value: string): void
27
+ (e: 'set:customer-name', value: string): void
28
+ }>();
26
29
  watch(isLogged, (_isLogged) => {
27
- emit(_isLogged ? 'login' : 'logout');
30
+ emit('set:is-logged', _isLogged);
31
+ emit('set:customer-name', customerName.value);
32
+ }, {
33
+ immediate: true,
34
+ });
35
+ watch(email, (_email) => {
36
+ emit('set:email', _email);
28
37
  }, {
29
38
  immediate: true,
30
39
  });
@@ -58,11 +67,6 @@ const submitLogin = async () => {
58
67
  </script>
59
68
 
60
69
  <template>
61
- <slot name="greetings" v-bind="{ customerName }">
62
- <div class="text-xl font-medium mb-5">
63
- {{ `${i19hello} ${customerName || i19visitor}` }}
64
- </div>
65
- </slot>
66
70
  <form
67
71
  class="login-form text-base"
68
72
  @submit.prevent="submitLogin"
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ import type { NetworkName } from '@@sf/server-data';
3
+ import { computed } from 'vue';
4
+
5
+ export interface Props {
6
+ as?: string;
7
+ network: NetworkName;
8
+ }
9
+
10
+ const props = withDefaults(defineProps<Props>(), {
11
+ as: 'i',
12
+ });
13
+ const iconClassName = computed(() => {
14
+ switch (props.network) {
15
+ case 'facebook': return 'i-facebook';
16
+ case 'instagram': return 'i-instagram';
17
+ case 'whatsapp': return 'i-whatsapp';
18
+ case 'youtube': return 'i-youtube';
19
+ case 'pinterest': return 'i-pinterest';
20
+ case 'tiktok': return 'i-tiktok';
21
+ case 'twitter': return 'i-twitter';
22
+ default: return '';
23
+ }
24
+ });
25
+ </script>
26
+
27
+ <template>
28
+ <component :is="as" :class="iconClassName" />
29
+ </template>
@@ -0,0 +1,37 @@
1
+ <script setup lang="ts">
2
+ import type { NetworkName } from '@@sf/server-data';
3
+ import { computed } from 'vue';
4
+ import { isMobile } from '@@sf/browser-env';
5
+ import { socialNetworks } from '@@sf/server-data';
6
+ import SocialNetworkIcon from '@@sf/components/SocialNetworkIcon.vue';
7
+
8
+ export interface Props {
9
+ network: NetworkName;
10
+ href?: string;
11
+ message?: string;
12
+ }
13
+
14
+ const props = defineProps<Props>();
15
+ const fixedHref = computed(() => {
16
+ let href = props.href || socialNetworks[props.network];
17
+ if (props.network === 'whatsapp') {
18
+ const tel = href.replace(/[^+\d]/g, '');
19
+ // eslint-disable-next-line prefer-template
20
+ href = `https://${(isMobile ? 'api' : 'web')}.whatsapp.com/send?phone=`
21
+ + encodeURIComponent(tel.charAt(0) === '+' ? tel : `+55${tel}`);
22
+ if (props.message) {
23
+ href += `&text=${encodeURIComponent(props.message)}`;
24
+ }
25
+ }
26
+ return href;
27
+ });
28
+ </script>
29
+
30
+ <template>
31
+ <ALink :href="fixedHref">
32
+ <slot>
33
+ <SocialNetworkIcon :network="network" />
34
+ <slot name="append"></slot>
35
+ </slot>
36
+ </ALink>
37
+ </template>
@@ -9,11 +9,11 @@ export interface Props {
9
9
  const props = defineProps<Props>();
10
10
  const linkTarget = computed(() => {
11
11
  if (props.target) return props.target;
12
- if (props.href.startsWith('http') && globalThis.storefront.settings) {
12
+ if (props.href.startsWith('http')) {
13
13
  const domain = globalThis.storefront.settings.domain || window.location.host;
14
14
  if (props.href.startsWith(`https://${domain}`)) return null;
15
15
  }
16
- return null;
16
+ return '_blank';
17
17
  });
18
18
  </script>
19
19
 
@@ -0,0 +1,79 @@
1
+ import type { Ref } from 'vue';
2
+ import type { CategoriesList } from '@cloudcommerce/api/types';
3
+ import { ref, computed } from 'vue';
4
+ import useStickyHeader from '@@sf/composables/use-sticky-header';
5
+
6
+ export interface Props {
7
+ header: Ref<HTMLElement>;
8
+ categories: CategoriesList;
9
+ }
10
+
11
+ type CategoryTree = CategoriesList[0] & {
12
+ subcategories: Array<CategoryTree>,
13
+ };
14
+
15
+ const filterMainCategories = (categories: CategoriesList) => {
16
+ return categories.filter(({ slug, parent }) => {
17
+ return slug && !parent;
18
+ });
19
+ };
20
+
21
+ const filterSubcategories = (
22
+ categories: CategoriesList,
23
+ parentCategory: CategoriesList[0],
24
+ ) => {
25
+ return categories.filter(({ slug, parent }) => {
26
+ if (slug && parent) {
27
+ return parent._id === parentCategory._id
28
+ || (parent.slug && parent.slug === parentCategory.slug);
29
+ }
30
+ return false;
31
+ });
32
+ };
33
+
34
+ const useShopHeader = (props: Props) => {
35
+ const { header } = props;
36
+ const {
37
+ isSticky,
38
+ staticHeight,
39
+ staticY,
40
+ } = useStickyHeader({ header });
41
+ const positionY = computed(() => {
42
+ return isSticky.value ? header.value.offsetHeight : staticY.value;
43
+ });
44
+ const mainCategories = filterMainCategories(props.categories);
45
+ const getSubcategories = (parentCategory: CategoriesList[0]) => {
46
+ return filterSubcategories(props.categories, parentCategory);
47
+ };
48
+ const getCategoryTree = (parentCategory: CategoriesList[0]): CategoryTree => {
49
+ return {
50
+ ...parentCategory,
51
+ subcategories: getSubcategories(parentCategory).map((subcategory) => {
52
+ return getCategoryTree(subcategory);
53
+ }),
54
+ };
55
+ };
56
+ const categoryTrees = mainCategories.map(getCategoryTree);
57
+ const isSidenavOpen = ref(false);
58
+ return {
59
+ isSticky,
60
+ staticHeight,
61
+ staticY,
62
+ positionY,
63
+ mainCategories,
64
+ getSubcategories,
65
+ getCategoryTree,
66
+ categoryTrees,
67
+ isSidenavOpen,
68
+ };
69
+ };
70
+
71
+ export default useShopHeader;
72
+
73
+ export {
74
+ useShopHeader,
75
+ filterMainCategories,
76
+ filterSubcategories,
77
+ };
78
+
79
+ export type { CategoryTree };
@@ -1,5 +1,4 @@
1
1
  ---
2
- import type CmsCode from '@@sf/types/cms-code';
3
2
  import type { PageContext } from '@@sf/ssr-context';
4
3
  import BaseHead from '@@sf/layouts/BaseHead.astro';
5
4
  import BaseStateJson from '@@sf/layouts/BaseStateJson.astro';
@@ -12,14 +11,14 @@ export interface Props {
12
11
 
13
12
  const { pageContext, title } = Astro.props as Props;
14
13
  const { cms } = pageContext;
15
- const cmsCustomCode = cms('code') as CmsCode;
14
+ const cmsCustomCode = await cms('code');
16
15
  ---
17
16
 
18
17
  <head>
19
18
  <BaseHead pageContext={pageContext} title={title} />
20
19
  <BaseStateJson pageContext={pageContext} />
21
- {cmsCustomCode.css && <style>{cmsCustomCode.css}</style>}
22
- {cmsCustomCode.html_head && <Fragment set:html={cmsCustomCode.html_head} />}
20
+ {cmsCustomCode?.css && <style>{cmsCustomCode.css}</style>}
21
+ {cmsCustomCode?.html_head && <Fragment set:html={cmsCustomCode.html_head} />}
23
22
  <slot name="base-head-scripts">
24
23
  <script src="../scripts/modules-info-preset"></script>
25
24
  </slot>
@@ -27,7 +26,7 @@ const cmsCustomCode = cms('code') as CmsCode;
27
26
  </head>
28
27
  <BaseBody pageContext={pageContext}>
29
28
  <slot />
30
- {cmsCustomCode.html_body && <Fragment set:html={cmsCustomCode.html_body} />}
29
+ {cmsCustomCode?.html_body && <Fragment set:html={cmsCustomCode.html_body} />}
31
30
  <slot name="base-body-scripts">
32
31
  <script src="../scripts/session-utm"></script>
33
32
  </slot>
@@ -1,5 +1,4 @@
1
1
  ---
2
- import type CmsSocial from '@@sf/types/cms-social';
3
2
  import type { PageContext } from '@@sf/ssr-context';
4
3
  import { pwaInfo } from 'virtual:pwa-info';
5
4
  import { img as getImg } from '@ecomplus/utils';
@@ -33,7 +32,7 @@ const favicon = settings.icon
33
32
  })).src
34
33
  : '/favicon.ico';
35
34
  const canonicalUrl = new URL(Astro.url.pathname, Astro.site || `https://${domain}`);
36
- const cmsSocial = cms('social') as CmsSocial;
35
+ const cmsMetatags = await cms('metatags');
37
36
  const ogLocale = lang.length === 2 ? lang : lang.substring(0, 2) + lang.slice(3).toUpperCase();
38
37
  let ogImage: string | undefined;
39
38
  if (apiDoc) {
@@ -41,9 +40,9 @@ if (apiDoc) {
41
40
  ogImage = picture && picture.url;
42
41
  }
43
42
  if (!ogImage) {
44
- if (cmsSocial.og_image) {
45
- ogImage = cmsSocial.og_image.charAt(0) === '/'
46
- ? `https://${domain}${cmsSocial.og_image}` : cmsSocial.og_image;
43
+ if (cmsMetatags?.og_image) {
44
+ ogImage = cmsMetatags.og_image.charAt(0) === '/'
45
+ ? `https://${domain}${cmsMetatags.og_image}` : cmsMetatags.og_image;
47
46
  }
48
47
  } else {
49
48
  ogImage = ogImage.replace(/(\w+\.)?(ecoms\d)\.com/i, '$2-nyc3.nyc3.cdn.digitaloceanspaces.com');
@@ -69,9 +68,10 @@ if (!ogImage) {
69
68
  <meta property="og:type" content="website">
70
69
  <meta property="og:locale" content={ogLocale}>
71
70
  {ogImage && <meta property="og:image" content={ogImage} />}
72
- {cmsSocial.fb_app_id && <meta property="fb:app_id" content={cmsSocial.fb_app_id} />}
71
+ {cmsMetatags?.fb_app_id && <meta property="fb:app_id" content={cmsMetatags.fb_app_id} />}
73
72
  <meta name="twitter:card" content="summary">
74
- {cmsSocial.twitter_username && <meta name="twitter:site" content={cmsSocial.twitter_username} />}
73
+ {cmsMetatags?.twitter_username &&
74
+ <meta name="twitter:site" content={cmsMetatags.twitter_username} />}
75
75
  <meta name="ecom-store-id" content={String(storeId)}>
76
76
  {pwaInfo && <Fragment set:html={pwaInfo.webManifest.linkTag} />}
77
77
  <script>
@@ -32,7 +32,7 @@ if (apiDoc) {
32
32
  apiDoc.price = getPrice(apiDoc);
33
33
  }
34
34
  const slimDocRegex = globalThis.storefront_slim_doc_regex
35
- || /body|meta|records|description|i18n/;
35
+ || /body_|meta_|metafields|_records|i18n/;
36
36
  const minifyApiDoc = (nestedDoc: any) => {
37
37
  if (typeof nestedDoc === 'object' && nestedDoc) {
38
38
  if (Array.isArray(nestedDoc)) {
@@ -1,9 +1,7 @@
1
1
  ---
2
- import type CmsHeader from '@@sf/types/cms-header';
3
2
  import type { PageContext } from '@@sf/ssr-context';
4
- import Picture from '@@sf/ssr/Picture.astro';
5
3
  import PitchBar, { type Props as PitchBarProps } from '~/components/PitchBar.vue';
6
- import ShopHeader, { type Props as ShopHeaderProps } from '@@sf/components/ShopHeader.vue';
4
+ import ShopHeader, { type Props as ShopHeaderProps } from '~/components/ShopHeader.vue';
7
5
 
8
6
  export interface Props {
9
7
  pageContext: PageContext;
@@ -14,20 +12,13 @@ const {
14
12
  pageContext: {
15
13
  isHomepage,
16
14
  apiState,
17
- settings,
18
15
  cms,
19
16
  },
20
17
  } = Astro.props as Props;
21
- const header = cms('header') as CmsHeader &
22
- { marketing_stripe?: { text: string, link: string }, logo?: string };
18
+ const cmsHeader = await cms('header');
23
19
  const pitchBar: PitchBarProps = { slides: [] };
24
- if (header.pitch_bar) {
25
- pitchBar.slides = header.pitch_bar;
26
- } else if (header.marketing_stripe) {
27
- pitchBar.slides = [{
28
- href: header.marketing_stripe.link,
29
- html: header.marketing_stripe.text,
30
- }];
20
+ if (cmsHeader?.pitch_bar) {
21
+ pitchBar.slides = cmsHeader.pitch_bar;
31
22
  }
32
23
  const shopHeader: ShopHeaderProps = {
33
24
  categories: apiState.categories,
@@ -46,16 +37,7 @@ const LogoHeading = Astro.props.logoHeading || (isHomepage ? 'h1' : 'h2');
46
37
  <slot name="logo">
47
38
  <a href="/">
48
39
  <LogoHeading>
49
- <slot name="logo-picture">
50
- <Picture
51
- src={header.logo || settings.logo}
52
- alt={settings.name}
53
- widths={[300]}
54
- sizes="150px"
55
- fetchpriority="high"
56
- class="hover:drop-shadow-sm"
57
- />
58
- </slot>
40
+ <slot name="logo-picture" />
59
41
  </LogoHeading>
60
42
  </a>
61
43
  </slot>
@@ -1,7 +1,20 @@
1
1
  import { initializeApp } from 'firebase/app';
2
+ import {
3
+ getAuth,
4
+ onAuthStateChanged,
5
+ isSignInWithEmailLink,
6
+ signInWithEmailLink,
7
+ // updateProfile,
8
+ } from 'firebase/auth';
2
9
 
3
- const app = initializeApp(window.firebaseConfig);
10
+ const firebaseApp = initializeApp(window.firebaseConfig);
4
11
 
5
- export default app;
12
+ export default firebaseApp;
6
13
 
7
- export const firebaseApp = app;
14
+ export {
15
+ firebaseApp,
16
+ getAuth,
17
+ onAuthStateChanged,
18
+ isSignInWithEmailLink,
19
+ signInWithEmailLink,
20
+ };
@@ -0,0 +1,25 @@
1
+ const {
2
+ settings,
3
+ context: apiContext,
4
+ } = globalThis.storefront;
5
+
6
+ const networkNames = [
7
+ 'whatsapp',
8
+ 'instagram',
9
+ 'facebook',
10
+ 'twitter',
11
+ 'youtube',
12
+ 'tiktok',
13
+ 'pinterest',
14
+ ] as const;
15
+ type NetworkName = typeof networkNames[number];
16
+ const socialNetworks: Partial<Record<NetworkName, string>> = {};
17
+ networkNames.forEach((network: NetworkName) => {
18
+ if (settings[network]) {
19
+ socialNetworks[network] = settings[network];
20
+ }
21
+ });
22
+
23
+ export { settings, apiContext, socialNetworks };
24
+
25
+ export type { NetworkName };
@@ -1,7 +1,7 @@
1
1
  import type { AstroGlobal } from 'astro';
2
2
  import type { BaseConfig } from '@cloudcommerce/config';
3
3
  import type { CategoriesList, BrandsList } from '@cloudcommerce/api/types';
4
- import type CmsSettings from './types/cms-settings';
4
+ import type { CMS, CmsSettings } from './cms';
5
5
  import { EventEmitter } from 'node:events';
6
6
  import api, { ApiError, ApiEndpoint } from '@cloudcommerce/api';
7
7
  import _getConfig from '../../storefront.config.mjs';
@@ -18,8 +18,7 @@ type StorefrontConfig = {
18
18
  settings: CmsSettings,
19
19
  dirContent: string,
20
20
  // eslint-disable-next-line no-unused-vars
21
- cms: <T extends string>(filename: T) => T extends `${string}/`
22
- ? Array<string> : Record<string, any>,
21
+ cms: CMS,
23
22
  };
24
23
 
25
24
  const emitter = new EventEmitter();
@@ -28,11 +27,6 @@ const getConfig: () => StorefrontConfig = _getConfig;
28
27
  declare global {
29
28
  // eslint-disable-next-line
30
29
  var api_prefetch_endpoints: ApiEndpoint[];
31
- // eslint-disable-next-line
32
- var storefront: {
33
- settings: Partial<CmsSettings>,
34
- onLoad: (callback: (...args: any[]) => void) => void,
35
- };
36
30
  }
37
31
  if (!globalThis.api_prefetch_endpoints) {
38
32
  globalThis.api_prefetch_endpoints = ['categories'];
@@ -71,7 +65,7 @@ const loadPageContext = async (Astro: AstroGlobal, {
71
65
  const config = getConfig();
72
66
  globalThis.storefront.settings = config.settings;
73
67
  let cmsContent: Record<string, any> | undefined;
74
- let apiResource: string | undefined;
68
+ let apiResource: 'products' | 'categories' | 'brands' | 'collections' | undefined;
75
69
  let apiDoc: Record<string, any> | undefined;
76
70
  const apiState: {
77
71
  categories?: CategoriesList,
@@ -88,7 +82,7 @@ const loadPageContext = async (Astro: AstroGlobal, {
88
82
  ];
89
83
  if (slug) {
90
84
  if (cmsCollection) {
91
- cmsContent = config.cms(`${cmsCollection}/${slug}`);
85
+ cmsContent = await config.cms(`${cmsCollection}/${slug}`);
92
86
  } else {
93
87
  apiFetchings[0] = api.get(`slugs/${slug}`, apiOptions);
94
88
  }
@@ -134,6 +128,13 @@ const loadPageContext = async (Astro: AstroGlobal, {
134
128
  } else {
135
129
  setResponseCache(Astro, 120, 300);
136
130
  }
131
+ if (apiDoc) {
132
+ globalThis.storefront.context = {
133
+ resource: apiResource,
134
+ doc: apiDoc as any,
135
+ timestamp: Date.now(),
136
+ };
137
+ }
137
138
  const pageContext = {
138
139
  ...config,
139
140
  isHomepage,
@@ -1,16 +1,10 @@
1
1
  import type { Customers } from '@cloudcommerce/api/types';
2
+ import type { Auth } from 'firebase/auth';
2
3
  import api from '@cloudcommerce/api';
3
4
  import { nickname as getNickname } from '@ecomplus/utils';
4
5
  import { computed } from 'vue';
5
- import {
6
- getAuth,
7
- onAuthStateChanged,
8
- isSignInWithEmailLink,
9
- signInWithEmailLink,
10
- // updateProfile,
11
- } from 'firebase/auth';
6
+ import requestIdleCallback from '../../helpers/idle-callback';
12
7
  import useStorage from './use-storage';
13
- import '../scripts/firebase-app';
14
8
 
15
9
  const storageKey = 'SESSION';
16
10
  const emptySession = {
@@ -44,18 +38,9 @@ const customerEmail = computed({
44
38
  },
45
39
  });
46
40
 
47
- const firebaseAuth = getAuth();
48
- if (isSignInWithEmailLink(firebaseAuth, window.location.href)) {
49
- const urlParams = new URLSearchParams(window.location.search);
50
- const email = urlParams.get('email');
51
- if (email) {
52
- signInWithEmailLink(firebaseAuth, email, window.location.href)
53
- .catch(console.error);
54
- }
55
- }
56
-
41
+ let firebaseAuth: Auth;
57
42
  const isLogged = computed(() => {
58
- return isAuthenticated.value || !!firebaseAuth.currentUser;
43
+ return isAuthenticated.value || !!firebaseAuth?.currentUser?.emailVerified;
59
44
  });
60
45
  const logout = () => {
61
46
  session.auth = emptySession.auth;
@@ -97,21 +82,56 @@ const fetchCustomer = async () => {
97
82
  return data;
98
83
  };
99
84
 
100
- onAuthStateChanged(firebaseAuth, async (user) => {
101
- if (user) {
102
- if (user.emailVerified) {
103
- const isEmailChanged = user.email !== customerEmail.value;
104
- if (isEmailChanged || !isAuthenticated.value) {
105
- await authenticate();
106
- if (isEmailChanged || !customerName.value) {
107
- await fetchCustomer();
85
+ let isAuthInitialized = false;
86
+ const initializeFirebaseAuth = (canWaitIdle = !window.location.pathname.startsWith('/app/')) => {
87
+ if (import.meta.env.SSR || isAuthInitialized) return;
88
+ isAuthInitialized = true;
89
+ const runImport = () => import('../scripts/firebase-app')
90
+ .then(({
91
+ getAuth,
92
+ onAuthStateChanged,
93
+ isSignInWithEmailLink,
94
+ signInWithEmailLink,
95
+ }) => {
96
+ firebaseAuth = getAuth();
97
+ onAuthStateChanged(firebaseAuth, async (user) => {
98
+ if (user) {
99
+ if (user.displayName && !customerName.value) {
100
+ session.customer.display_name = user.displayName;
101
+ }
102
+ if (user.email && (!customerEmail.value || user.emailVerified)) {
103
+ session.customer.main_email = user.email;
104
+ }
105
+ if (user.emailVerified) {
106
+ const isEmailChanged = user.email !== customerEmail.value;
107
+ if (isEmailChanged || !isAuthenticated.value) {
108
+ await authenticate();
109
+ if (isEmailChanged || !customerName.value) {
110
+ await fetchCustomer();
111
+ }
112
+ }
113
+ }
114
+ } else {
115
+ logout();
116
+ }
117
+ });
118
+ if (isSignInWithEmailLink(firebaseAuth, window.location.href)) {
119
+ const urlParams = new URLSearchParams(window.location.search);
120
+ const email = urlParams.get('email');
121
+ if (email) {
122
+ signInWithEmailLink(firebaseAuth, email, window.location.href)
123
+ .then(() => window.localStorage.removeItem('emailForSignIn'))
124
+ .catch(console.error);
108
125
  }
109
126
  }
110
- }
127
+ })
128
+ .catch(console.error);
129
+ if (canWaitIdle) {
130
+ requestIdleCallback(runImport);
111
131
  } else {
112
- logout();
132
+ runImport();
113
133
  }
114
- });
134
+ };
115
135
 
116
136
  export default session;
117
137
 
@@ -126,4 +146,5 @@ export {
126
146
  authenticate,
127
147
  getAccessToken,
128
148
  fetchCustomer,
149
+ initializeFirebaseAuth,
129
150
  };
@@ -8,6 +8,7 @@ import { formatMoney } from '@ecomplus/utils';
8
8
  import loadingGlobalInfoPreset from '@@sf/scripts/modules-info-preset';
9
9
  import utm from '@@sf/scripts/session-utm';
10
10
  import afetch from '../../helpers/afetch';
11
+ import requestIdleCallback from '../../helpers/idle-callback';
11
12
 
12
13
  const emptyInfo = {
13
14
  list_payments: {},
@@ -140,11 +141,7 @@ if (!import.meta.env.SSR) {
140
141
  .catch(console.error);
141
142
  });
142
143
  };
143
- if (typeof window.requestIdleCallback === 'function') {
144
- window.requestIdleCallback(fetchInfo);
145
- } else {
146
- setTimeout(fetchInfo, 300);
147
- }
144
+ requestIdleCallback(fetchInfo);
148
145
  }
149
146
 
150
147
  export default modulesInfo;
@@ -156,7 +153,7 @@ const parsePhrase = <T extends keyof typeof modulesInfo>(
156
153
  formatValue: (x: any) => string = formatMoney,
157
154
  ) => {
158
155
  return computed(() => {
159
- const searchString = `{{${varName}}}`;
156
+ const searchString = `{${varName}}`;
160
157
  const index = phrase.indexOf(searchString);
161
158
  if (index > -1) {
162
159
  const fieldValue = modulesInfo[modName][varName];
@@ -40,14 +40,11 @@ let defaultThemeOptions = {
40
40
  iconAliases: {
41
41
  'shopping-cart': 'shopping-bag',
42
42
  cashback: 'arrow-uturn-left',
43
- 'chevron-right': 'chevron-right',
44
- 'chevron-left': 'chevron-left',
45
- 'chevron-up': 'chevron-up',
46
- 'chevron-down': 'chevron-down',
47
43
  menu: 'bars-3-bottom-left',
48
44
  search: 'magnifying-glass',
49
45
  account: 'user-circle',
50
46
  close: 'x-mark',
47
+ logout: 'arrow-right-on-rectangle',
51
48
  },
52
49
  };
53
50
  if (globalThis.storefront_theme_options) {
@@ -97,6 +97,13 @@ type CmsSettings = {
97
97
  currency: string,
98
98
  currency_symbol: string,
99
99
  country_code: string,
100
+ whatsapp?: string,
101
+ instagram?: string,
102
+ facebook?: string,
103
+ twitter?: string,
104
+ youtube?: string,
105
+ tiktok?: string,
106
+ pinterest?: string,
100
107
  modules?: {
101
108
  list_payments?: {
102
109
  installments_option?: Partial<ListPaymentsResponse['installments_option']>,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/types",
3
3
  "type": "module",
4
- "version": "0.4.1",
4
+ "version": "0.6.0",
5
5
  "description": "E-Com Plus Cloud Commerce reusable type definitions",
6
6
  "main": "index.ts",
7
7
  "repository": {
@@ -5,6 +5,6 @@ packages:
5
5
  - 'store'
6
6
  - 'store/*'
7
7
  - 'store/functions/*'
8
- - 'ecomplus-stores/*'
9
- - 'ecomplus-stores/*/*'
10
- - 'ecomplus-stores/*/functions/*'
8
+ #- 'ecomplus-stores/*'
9
+ #- 'ecomplus-stores/*/*'
10
+ #- 'ecomplus-stores/*/functions/*'
@@ -1 +0,0 @@
1
- import{v as O}from"./runtime-dom.esm-bundler.0e5774ce.js";import{p as U}from"./modules-info.0debb0b0.js";import{c as w,d as L,o as r,a as f,l as h,e as k,n as R,u as i,m as G,i as u,p as y,q as N,s as J,v as Q,x as X,y as Y,j as H,w as p,k as M,z as Z,A as ee,g as x,B as te,F as ae,C as se,b as oe}from"./runtime-core.esm-bundler.a0432a8e.js";import{u as ne,a as le,b as re}from"./index.2d12be6c.js";/* empty css */import"./session-utm.72684b84.js";import"./ecom-utils.92f137f6.js";const ue=s=>{const l=w(()=>s.slides.map(({html:t})=>U(t).value)),o=w(()=>l.value.filter(t=>t).length);return{parsedContents:l,countValidSlides:o}},D=Symbol("carousel"),ie=["aria-label","data-carousel-control"],_=L({__name:"CarouselControl",props:{direction:{default:1}},setup(s){const{changeSlide:l}=G(D);return(o,t)=>(r(),f("button",{type:"button","aria-label":s.direction>0?"Próximo":"Anterior",onClick:t[0]||(t[0]=n=>i(l)(s.direction)),"data-carousel-control":s.direction>0?"next":"previous"},[h(o.$slots,"default",{},()=>[k("i",{class:R(["m-0",s.direction>0?"i-chevron-right":"i-chevron-left"])},null,2)])],8,ie))}}),ce=L({__name:"Carousel",props:{as:{default:"ul"},modelValue:{default:1},autoplay:null},emits:["update:modelValue"],setup(s,{emit:l}){const o=s,t=u(o.modelValue-1);y(N(o,"modelValue"),e=>{t.value=e-1}),y(t,(e,a)=>{e!==a&&l("update:modelValue",e+1)});const n=u(null),{x:V,isScrolling:c,arrivedState:d}=ne(n),C=w(()=>d.left),S=w(()=>d.right),b=u([]),W=u(0),P=u(0),B=u(0),F=()=>{W.value=n.value.scrollWidth,P.value=n.value.offsetWidth},j=()=>{const e=[...n.value.children];b.value=e.map(a=>({offsetLeft:a.offsetLeft,width:a.offsetWidth}))},q=e=>{const a=e>0?t.value:t.value+e,E=b.value[a]?.width||0;return E?E*e:0},T=()=>{const e=b.value.findIndex(a=>Math.abs(a.offsetLeft-V.value)<=5);e>-1&&(t.value=e||0)},$=()=>{const e=W.value-P.value;B.value=b.value.findIndex(({offsetLeft:a})=>a>=e-5)};let v=null;const g=()=>{o.autoplay&&(clearTimeout(v),v=setTimeout(()=>{m(1)},o.autoplay))},m=e=>{if(e<0){if(C.value){$(),t.value=B.value-1,m(1);return}}else if(S.value){t.value=1,m(-1);return}const a=q(e);a&&(n.value.scrollBy({left:a,behavior:"smooth"}),g())};y(c,e=>{e?clearTimeout(v):(T(),g())});const I=u(null),K=le(I);y(K,e=>{e?clearTimeout(v):g()});const z=()=>{n.value&&(F(),j(),T(),$())},A=re(z,400);return J(()=>{z(),Q(()=>{[...n.value.children].forEach(e=>{e.setAttribute("tabindex","0")})}),g(),window.addEventListener("resize",A)}),X(()=>{window.removeEventListener("resize",A),clearTimeout(v)}),Y(D,{autoplay:N(o,"autoplay"),changeSlide:m,isBoundLeft:C,isBoundRight:S}),(e,a)=>(r(),f("div",{ref_key:"carousel",ref:I,"data-carousel":""},[(r(),H(M(s.as),{ref_key:"wrapper",ref:n,"data-carousel-wrapper":""},{default:p(()=>[h(e.$slots,"default")]),_:3},512)),h(e.$slots,"controls",Z(ee({changeSlide:m,isBoundLeft:i(C),isBoundRight:i(S),currentPage:t.value+1,pageCount:B.value+1})),()=>[x(_,{direction:-1},{default:p(()=>[h(e.$slots,"previous")]),_:3}),x(_,null,{default:p(()=>[h(e.$slots,"next")]),_:3})])],512))}}),de={class:"bg-base-100 relative z-1"},fe={class:"container md:w-2/3 mx-auto px-3 py-1"},pe=["innerHTML"],ve={class:"text-xl leading-none text-base-400"},_e=L({__name:"PitchBar",props:{slides:null},setup(s){const l=s,{parsedContents:o,countValidSlides:t}=ue(l);return(n,V)=>(r(),f("div",de,[k("div",fe,[x(ce,{autoplay:i(t)>1?7e3:null},{controls:p(()=>[te(k("div",ve,[x(_,{direction:-1,class:"pr-2 bg-base-100 hover:text-base-700"}),x(_,{class:"pl-2 bg-base-100 hover:text-base-700"})],512),[[O,i(t)>1]])]),default:p(()=>[(r(!0),f(ae,null,se(s.slides,(c,d)=>(r(),f("li",{key:d},[(r(),H(M(c.href?"ALink":"span"),{href:c.href,target:c.target,class:R(["inline-block px-8",c.href?"hover:underline":null])},{default:p(()=>[i(o)[d]?(r(),f("span",{key:0,innerHTML:i(o)[d],class:"prose text-sm text-base-800"},null,8,pe)):oe("",!0)]),_:2},1032,["href","target","class"]))]))),128))]),_:1},8,["autoplay"])])]))}});export{_e as default};
@@ -1 +0,0 @@
1
- import{_ as o}from"./Prices.vue_vue_type_script_setup_true_lang.ef47de70.js";/* empty css */import"./modules-info.0debb0b0.js";import"./session-utm.72684b84.js";import"./runtime-core.esm-bundler.a0432a8e.js";import"./ecom-utils.92f137f6.js";export{o as default};