cloudcommerce 0.36.2 → 0.37.1

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 (174) hide show
  1. package/.github/workflows/test-apps.yml +2 -2
  2. package/.gitmodules +0 -3
  3. package/.vscode/settings.json +0 -1
  4. package/CHANGELOG.md +38 -0
  5. package/action.yml +2 -2
  6. package/ecomplus-stores/barra-doce/functions/many/package.json +3 -3
  7. package/ecomplus-stores/barra-doce/functions/ssr/package.json +6 -6
  8. package/ecomplus-stores/barra-doce/functions/with-apps/package.json +3 -3
  9. package/ecomplus-stores/barra-doce/package.json +2 -2
  10. package/package.json +5 -5
  11. package/packages/api/package.json +1 -1
  12. package/packages/apps/affilate-program/package.json +1 -1
  13. package/packages/apps/correios/package.json +1 -1
  14. package/packages/apps/custom-payment/package.json +1 -1
  15. package/packages/apps/custom-shipping/package.json +1 -1
  16. package/packages/apps/datafrete/package.json +1 -1
  17. package/packages/apps/discounts/package.json +1 -1
  18. package/packages/apps/emails/package.json +1 -1
  19. package/packages/apps/fb-conversions/package.json +2 -2
  20. package/packages/apps/flash-courier/package.json +1 -1
  21. package/packages/apps/frenet/package.json +1 -1
  22. package/packages/apps/galaxpay/package.json +1 -1
  23. package/packages/apps/google-analytics/package.json +1 -1
  24. package/packages/apps/jadlog/package.json +1 -1
  25. package/packages/apps/loyalty-points/package.json +1 -1
  26. package/packages/apps/mandae/package.json +1 -1
  27. package/packages/apps/melhor-envio/package.json +1 -1
  28. package/packages/apps/mercadopago/package.json +1 -1
  29. package/packages/apps/pagarme/package.json +1 -1
  30. package/packages/apps/pagarme-v5/package.json +1 -1
  31. package/packages/apps/paghiper/package.json +1 -1
  32. package/packages/apps/pix/package.json +1 -1
  33. package/packages/apps/tiny-erp/package.json +1 -1
  34. package/packages/apps/webhooks/package.json +1 -1
  35. package/packages/cli/package.json +1 -1
  36. package/packages/config/package.json +1 -1
  37. package/packages/emails/package.json +1 -1
  38. package/packages/eslint/package.json +5 -5
  39. package/packages/events/package.json +1 -1
  40. package/packages/feeds/package.json +1 -1
  41. package/packages/firebase/package.json +1 -1
  42. package/packages/i18n/package.json +1 -1
  43. package/packages/modules/package.json +1 -1
  44. package/packages/passport/package.json +1 -1
  45. package/packages/ssr/package.json +4 -4
  46. package/packages/storefront/package.json +11 -10
  47. package/packages/storefront/src/helpers/sf-utils.ts +8 -5
  48. package/packages/storefront/src/lib/components/CarouselControl.vue +1 -1
  49. package/packages/storefront/src/lib/composables/use-search-modal.ts +90 -0
  50. package/packages/storefront/src/lib/composables/use-shop-header.ts +69 -1
  51. package/packages/storefront/src/lib/state/search-engine.ts +39 -13
  52. package/packages/storefront/src/lib/state/shopping-cart.ts +2 -1
  53. package/packages/storefront/src/lib/state/use-analytics.ts +27 -11
  54. package/packages/test-base/package.json +1 -1
  55. package/packages/types/package.json +1 -1
  56. package/ecomplus-stores/monocard/.devcontainer/devcontainer.json +0 -30
  57. package/ecomplus-stores/monocard/.editorconfig +0 -13
  58. package/ecomplus-stores/monocard/.eslintrc.cjs +0 -3
  59. package/ecomplus-stores/monocard/.firebaserc +0 -5
  60. package/ecomplus-stores/monocard/.github/build-and-deploy +0 -1
  61. package/ecomplus-stores/monocard/.github/renovate.json +0 -5
  62. package/ecomplus-stores/monocard/.github/workflows/build-and-deploy.yml +0 -37
  63. package/ecomplus-stores/monocard/.github/workflows/calibreapp-image-actions.yml +0 -23
  64. package/ecomplus-stores/monocard/.gitpod.yml +0 -12
  65. package/ecomplus-stores/monocard/.idx/dev.nix +0 -24
  66. package/ecomplus-stores/monocard/.nvmrc +0 -1
  67. package/ecomplus-stores/monocard/.vscode/extensions.json +0 -8
  68. package/ecomplus-stores/monocard/.vscode/launch.json +0 -11
  69. package/ecomplus-stores/monocard/.vscode/settings.json +0 -13
  70. package/ecomplus-stores/monocard/LICENSE.md +0 -230
  71. package/ecomplus-stores/monocard/README.md +0 -31
  72. package/ecomplus-stores/monocard/SETUP.md +0 -129
  73. package/ecomplus-stores/monocard/SETUP.pt-BR.md +0 -129
  74. package/ecomplus-stores/monocard/functions/config.json +0 -3
  75. package/ecomplus-stores/monocard/functions/example.env +0 -10
  76. package/ecomplus-stores/monocard/functions/many/index.js +0 -14
  77. package/ecomplus-stores/monocard/functions/many/package.json +0 -22
  78. package/ecomplus-stores/monocard/functions/ssr/.eslintrc.cjs +0 -6
  79. package/ecomplus-stores/monocard/functions/ssr/astro.config.mjs +0 -4
  80. package/ecomplus-stores/monocard/functions/ssr/content/blog/.gitkeep +0 -0
  81. package/ecomplus-stores/monocard/functions/ssr/content/extra-pages/terms.json +0 -11
  82. package/ecomplus-stores/monocard/functions/ssr/content/extra-pages/trocas.json +0 -11
  83. package/ecomplus-stores/monocard/functions/ssr/content/layout.json +0 -52
  84. package/ecomplus-stores/monocard/functions/ssr/content/pages/home.json +0 -20
  85. package/ecomplus-stores/monocard/functions/ssr/content/pages/products.json +0 -18
  86. package/ecomplus-stores/monocard/functions/ssr/content/settings.json +0 -78
  87. package/ecomplus-stores/monocard/functions/ssr/index.js +0 -18
  88. package/ecomplus-stores/monocard/functions/ssr/package.json +0 -36
  89. package/ecomplus-stores/monocard/functions/ssr/public/admin/.gitkeep +0 -0
  90. package/ecomplus-stores/monocard/functions/ssr/public/assets/lotties/img_1.png +0 -0
  91. package/ecomplus-stores/monocard/functions/ssr/public/assets/lotties/img_1.webp +0 -0
  92. package/ecomplus-stores/monocard/functions/ssr/public/assets/lotties/phone-nfc.json +0 -1
  93. package/ecomplus-stores/monocard/functions/ssr/public/img/icon.png +0 -0
  94. package/ecomplus-stores/monocard/functions/ssr/public/img/large-icon.png +0 -0
  95. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/card-phone.png +0 -0
  96. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/devices.jpg +0 -0
  97. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/ecom-icon.png +0 -0
  98. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/edit-suit.jpg +0 -0
  99. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/favicon.png +0 -0
  100. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/icon.png +0 -0
  101. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/large-icon.png +0 -0
  102. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-arcelor-mittal.webp +0 -0
  103. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-azul.webp +0 -0
  104. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-banco-pan.webp +0 -0
  105. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-brinks.webp +0 -0
  106. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-mastercard.webp +0 -0
  107. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-pfizer.webp +0 -0
  108. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-prudential.webp +0 -0
  109. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-unimed.webp +0 -0
  110. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo.webp +0 -0
  111. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/mockup-editar.png +0 -0
  112. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/og-image.png +0 -0
  113. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/padronagem-tilada.png +0 -0
  114. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/qrcode-camera.png +0 -0
  115. package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/sua-logo-aqui.png +0 -0
  116. package/ecomplus-stores/monocard/functions/ssr/public/robots.txt +0 -6
  117. package/ecomplus-stores/monocard/functions/ssr/scripts/build.sh +0 -14
  118. package/ecomplus-stores/monocard/functions/ssr/src/assets/card.css +0 -99
  119. package/ecomplus-stores/monocard/functions/ssr/src/assets/style.css +0 -79
  120. package/ecomplus-stores/monocard/functions/ssr/src/components/AccountMenu.vue +0 -97
  121. package/ecomplus-stores/monocard/functions/ssr/src/components/AccountPage.vue +0 -62
  122. package/ecomplus-stores/monocard/functions/ssr/src/components/Banner.vue +0 -59
  123. package/ecomplus-stores/monocard/functions/ssr/src/components/BannersGrid.astro +0 -25
  124. package/ecomplus-stores/monocard/functions/ssr/src/components/Breadcrumbs.astro +0 -44
  125. package/ecomplus-stores/monocard/functions/ssr/src/components/CartItem.vue +0 -64
  126. package/ecomplus-stores/monocard/functions/ssr/src/components/CartSidebar.vue +0 -69
  127. package/ecomplus-stores/monocard/functions/ssr/src/components/CasesGrid.astro +0 -49
  128. package/ecomplus-stores/monocard/functions/ssr/src/components/CheckoutPage.vue +0 -33
  129. package/ecomplus-stores/monocard/functions/ssr/src/components/Collapse.vue +0 -19
  130. package/ecomplus-stores/monocard/functions/ssr/src/components/DemoVideo.vue +0 -10
  131. package/ecomplus-stores/monocard/functions/ssr/src/components/DocDescription.vue +0 -28
  132. package/ecomplus-stores/monocard/functions/ssr/src/components/FeatureTabs.vue +0 -286
  133. package/ecomplus-stores/monocard/functions/ssr/src/components/FeaturesSection.astro +0 -28
  134. package/ecomplus-stores/monocard/functions/ssr/src/components/FooterStamps.vue +0 -63
  135. package/ecomplus-stores/monocard/functions/ssr/src/components/ImagesGallery.vue +0 -154
  136. package/ecomplus-stores/monocard/functions/ssr/src/components/LoginForm.vue +0 -107
  137. package/ecomplus-stores/monocard/functions/ssr/src/components/LottiePhoneNFC.vue +0 -20
  138. package/ecomplus-stores/monocard/functions/ssr/src/components/MonocardCustomizer.vue +0 -261
  139. package/ecomplus-stores/monocard/functions/ssr/src/components/PitchBar.vue +0 -61
  140. package/ecomplus-stores/monocard/functions/ssr/src/components/Prices.vue +0 -95
  141. package/ecomplus-stores/monocard/functions/ssr/src/components/ProductCard.vue +0 -117
  142. package/ecomplus-stores/monocard/functions/ssr/src/components/ProductDetails.vue +0 -122
  143. package/ecomplus-stores/monocard/functions/ssr/src/components/ProductShelf.vue +0 -57
  144. package/ecomplus-stores/monocard/functions/ssr/src/components/ProductSpecifications.vue +0 -42
  145. package/ecomplus-stores/monocard/functions/ssr/src/components/SearchModal.vue +0 -6
  146. package/ecomplus-stores/monocard/functions/ssr/src/components/ShopFooter.vue +0 -71
  147. package/ecomplus-stores/monocard/functions/ssr/src/components/ShopHeader.vue +0 -137
  148. package/ecomplus-stores/monocard/functions/ssr/src/components/ShopHeaderMenu.vue +0 -92
  149. package/ecomplus-stores/monocard/functions/ssr/src/components/ShopSidenav.vue +0 -64
  150. package/ecomplus-stores/monocard/functions/ssr/src/components/ShopSidenavCategory.vue +0 -77
  151. package/ecomplus-stores/monocard/functions/ssr/src/components/SkuSelector.vue +0 -58
  152. package/ecomplus-stores/monocard/functions/ssr/src/env.d.ts +0 -13
  153. package/ecomplus-stores/monocard/functions/ssr/src/layouts/Base.astro +0 -15
  154. package/ecomplus-stores/monocard/functions/ssr/src/layouts/PageFooter.astro +0 -53
  155. package/ecomplus-stores/monocard/functions/ssr/src/layouts/PageHeader.astro +0 -35
  156. package/ecomplus-stores/monocard/functions/ssr/src/main/Fallback.astro +0 -10
  157. package/ecomplus-stores/monocard/functions/ssr/src/main/Home.astro +0 -95
  158. package/ecomplus-stores/monocard/functions/ssr/src/main/Sections.astro +0 -52
  159. package/ecomplus-stores/monocard/functions/ssr/src/main/Wildcard.astro +0 -18
  160. package/ecomplus-stores/monocard/functions/ssr/src/pages/[...slug].astro +0 -42
  161. package/ecomplus-stores/monocard/functions/ssr/src/pages/_vue.ts +0 -10
  162. package/ecomplus-stores/monocard/functions/ssr/src/pages/app/account.astro +0 -34
  163. package/ecomplus-stores/monocard/functions/ssr/src/pages/app/index.astro +0 -62
  164. package/ecomplus-stores/monocard/functions/ssr/src/pages/comprar/index.astro +0 -52
  165. package/ecomplus-stores/monocard/functions/ssr/src/pages/index.astro +0 -32
  166. package/ecomplus-stores/monocard/functions/ssr/src/pages/~fallback.astro +0 -23
  167. package/ecomplus-stores/monocard/functions/ssr/src/scripts/InlineScripts.astro +0 -10
  168. package/ecomplus-stores/monocard/functions/ssr/tailwind.config.cjs +0 -18
  169. package/ecomplus-stores/monocard/functions/ssr/tsconfig.json +0 -12
  170. package/ecomplus-stores/monocard/functions/ssr/uno.config.cjs +0 -5
  171. package/ecomplus-stores/monocard/functions/with-apps/index.js +0 -12
  172. package/ecomplus-stores/monocard/functions/with-apps/package.json +0 -22
  173. package/ecomplus-stores/monocard/package.json +0 -31
  174. package/ecomplus-stores/monocard/scripts/install.sh +0 -24
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/storefront",
3
3
  "type": "module",
4
- "version": "0.36.2",
4
+ "version": "0.37.1",
5
5
  "description": "E-Com Plus Cloud Commerce storefront with Astro",
6
6
  "bin": {
7
7
  "storefront": "./scripts/build-prod.sh"
@@ -29,24 +29,24 @@
29
29
  "prepare-monorepo": "bash scripts/prepare-monorepo.sh"
30
30
  },
31
31
  "dependencies": {
32
- "@astrojs/node": "6.0.4",
32
+ "@astrojs/node": "6.1.0",
33
33
  "@astrojs/vue": "3.0.4",
34
34
  "@cloudcommerce/api": "workspace:*",
35
35
  "@cloudcommerce/config": "workspace:*",
36
36
  "@cloudcommerce/i18n": "workspace:*",
37
37
  "@ecomplus/utils": "1.5.0-rc.5",
38
38
  "@fastify/deepmerge": "^1.3.0",
39
- "@iconify-json/fa6-brands": "^1.1.14",
40
- "@iconify-json/heroicons": "^1.1.14",
41
- "@iconify-json/logos": "^1.1.39",
39
+ "@iconify-json/fa6-brands": "^1.1.17",
40
+ "@iconify-json/heroicons": "^1.1.15",
41
+ "@iconify-json/logos": "^1.1.40",
42
42
  "@types/gtag.js": "^0.0.18",
43
- "@vite-pwa/astro": "^0.1.5",
43
+ "@vite-pwa/astro": "^0.1.6",
44
44
  "@vueuse/core": "10.6.1",
45
- "astro": "3.6.0",
45
+ "astro": "3.6.4",
46
46
  "astro-capo": "^0.0.1",
47
47
  "chroma-js": "^2.4.2",
48
48
  "dotenv": "^16.3.1",
49
- "firebase": "^10.6.0",
49
+ "firebase": "^10.7.0",
50
50
  "image-size": "^1.0.2",
51
51
  "mime": "^3.0.0",
52
52
  "mitt": "^3.0.1",
@@ -55,9 +55,10 @@
55
55
  "tailwindcss": "^3.3.5",
56
56
  "unocss": "^0.57.7",
57
57
  "unplugin-auto-import": "^0.16.7",
58
- "vite": "^4.5.0",
58
+ "vite": "^4.5.1",
59
59
  "vite-plugin-pwa": "^0.17.2",
60
- "vue": "3.3.9"
60
+ "vue": "3.3.10",
61
+ "wade": "0.3.3"
61
62
  },
62
63
  "devDependencies": {
63
64
  "@cloudcommerce/eslint": "workspace:*",
@@ -11,16 +11,19 @@ export const requestIdleCallback = (fn: (...args: any[]) => any, fallbackMs = 30
11
11
  }
12
12
  };
13
13
 
14
- export const slugify = (str: string) => {
14
+ export const clearAccents = (str: string) => {
15
15
  return str
16
- .toLowerCase()
17
- .trim()
18
16
  .replace(/[ÁáÃãÂâÀà]/g, 'a')
19
17
  .replace(/[Éé]/g, 'e')
20
18
  .replace(/[Íí]/g, 'i')
21
- .replace(/[ÓóÔô]/g, 'o')
19
+ .replace(/[ÕõÓóÔô]/g, 'o')
22
20
  .replace(/[Úú]/g, 'u')
23
- .replace(/[Çç]/g, 'c')
21
+ .replace(/[Çç]/g, 'c');
22
+ };
23
+
24
+ export const slugify = (str: string) => {
25
+ return clearAccents(str.trim())
26
+ .toLowerCase()
24
27
  .replace(/[\W\r\n]/gm, '-')
25
28
  .replace(/-{2,}/g, '-')
26
29
  .replace(/(^-)|(-$)/g, '');
@@ -18,7 +18,7 @@ const isX = axis === 'x';
18
18
  type="button"
19
19
  :aria-label="!isPrev ? $t.i19next : $t.i19previous"
20
20
  @click="changeSlide(!isPrev ? 1 : -1)"
21
- class="group absolute z-[2]"
21
+ class="group absolute z-[11]"
22
22
  :class="isX
23
23
  ? `${(!isPrev ? 'right-0' : 'left-0')} top-0`
24
24
  : `${(!isPrev ? 'bottom-0' : 'top-0')} left-0`"
@@ -0,0 +1,90 @@
1
+ import type {
2
+ Categories,
3
+ Brands,
4
+ Collections,
5
+ } from '@cloudcommerce/api/types';
6
+ import { ref, watch, toRef } from 'vue';
7
+ import Wade from 'wade';
8
+ import { clearAccents } from '@@sf/sf-lib';
9
+ import { SearchEngine, searchHistory } from '@@sf/state/search-engine';
10
+
11
+ export interface Props {
12
+ term: string;
13
+ fetchDebounce?: number;
14
+ productsLimit?: number;
15
+ }
16
+
17
+ const storefrontData = globalThis.$storefront.data as {
18
+ categories?: Array<Partial<Categories>>,
19
+ brands?: Array<Partial<Brands>>,
20
+ collections?: Array<Partial<Collections>>,
21
+ };
22
+ const wadeDocs: Array<{
23
+ text: string,
24
+ type: 'categories' | 'brands' | 'collections' | 'blog',
25
+ data: Record<string, any> & { name: string, slug: string },
26
+ }> = [];
27
+ (['categories', 'brands', 'collections'] as const).forEach((resource) => {
28
+ const docsList = storefrontData[resource];
29
+ if (docsList) {
30
+ for (let i = 0; i < docsList.length; i++) {
31
+ const doc = docsList[i];
32
+ if (doc.name && doc.slug) {
33
+ wadeDocs.push({
34
+ text: clearAccents(`${doc.name} ${(doc as Categories).short_description}`),
35
+ type: resource,
36
+ data: doc as typeof wadeDocs[number]['data'],
37
+ });
38
+ }
39
+ }
40
+ }
41
+ });
42
+ let wadeSearch: ((t: string) => { index: number, score: number }[]) | undefined;
43
+ if (wadeDocs.length) {
44
+ if (globalThis.$storefront.settings.lang === 'pt_br') {
45
+ Wade.config.stopWords = ['e', 'a', 'o', 'de', 'para', 'com', 'tem'];
46
+ }
47
+ wadeSearch = Wade(wadeDocs.map(({ text }) => text));
48
+ }
49
+
50
+ export const useSearchModal = (props: Props) => {
51
+ const searchEngine = new SearchEngine({
52
+ debounce: props.fetchDebounce || 300,
53
+ });
54
+ searchEngine.pageSize.value = props.productsLimit || 12;
55
+ searchEngine.isWithCount.value = true;
56
+ searchEngine.isWithBuckets.value = false;
57
+ const productCount = ref(0);
58
+ const linkHits = ref<Array<{ title: string, href: string }>>([]);
59
+ watch(toRef(props, 'term'), async (term) => {
60
+ searchEngine.fetch(term);
61
+ if (wadeSearch) {
62
+ const wadeResults = wadeSearch(clearAccents(term));
63
+ linkHits.value = wadeResults.map(({ index }) => {
64
+ const { name, slug } = wadeDocs[index].data;
65
+ return { title: name, href: `/${slug}` };
66
+ });
67
+ }
68
+ }, {
69
+ immediate: true,
70
+ });
71
+ watch(searchEngine.meta, () => {
72
+ productCount.value = searchEngine.meta.count || 0;
73
+ });
74
+ const filteredHistory = ref<string[]>([]);
75
+ watch(searchHistory, () => {
76
+ filteredHistory.value = searchHistory.filter((term) => term !== props.term);
77
+ }, {
78
+ immediate: true,
79
+ });
80
+ return {
81
+ searchHistory: filteredHistory,
82
+ searchEngine,
83
+ isFetching: searchEngine.isFetching,
84
+ productHits: searchEngine.products,
85
+ productCount,
86
+ linkHits,
87
+ };
88
+ };
89
+
90
+ export default useSearchModal;
@@ -1,12 +1,15 @@
1
1
  import type { Ref } from 'vue';
2
2
  import type { Categories } from '@cloudcommerce/api/types';
3
- import { computed } from 'vue';
3
+ import { ref, computed, watch } from 'vue';
4
+ import { watchOnce } from '@vueuse/core';
5
+ import { totalItems } from '@@sf/state/shopping-cart';
4
6
  import useStickyHeader from '@@sf/composables/use-sticky-header';
5
7
 
6
8
  type PartCategory = Partial<Categories>;
7
9
 
8
10
  export interface Props {
9
11
  header: Ref<HTMLElement | null>;
12
+ searchInput?: Ref<HTMLInputElement | null>;
10
13
  categories?: PartCategory[];
11
14
  menuCategorySlugs?: string[];
12
15
  menuRandomCategories?: number;
@@ -78,6 +81,7 @@ const filterSubcategories = (
78
81
  const useShopHeader = (props: Props) => {
79
82
  const {
80
83
  header,
84
+ searchInput,
81
85
  categories = (globalThis.$storefront.data.categories || []) as PartCategory[],
82
86
  menuCategorySlugs,
83
87
  menuRandomCategories = 7,
@@ -120,6 +124,61 @@ const useShopHeader = (props: Props) => {
120
124
  }
121
125
  return false;
122
126
  });
127
+
128
+ const isSearchOpen = ref(false);
129
+ const isSearchOpenOnce = ref(false);
130
+ watchOnce(isSearchOpen, () => {
131
+ isSearchOpenOnce.value = true;
132
+ });
133
+ const searchTerm = ref('');
134
+ const isSearchPage = !import.meta.env.SSR && window.location.pathname === '/s';
135
+ const urlSearchQ = isSearchPage
136
+ ? new URLSearchParams(window.location.search).get('q')
137
+ : undefined;
138
+ if (typeof urlSearchQ === 'string') {
139
+ searchTerm.value = urlSearchQ;
140
+ }
141
+ const quickSearchTerm = computed(() => {
142
+ if (searchTerm.value && searchTerm.value.length >= 2
143
+ && searchTerm.value !== urlSearchQ) {
144
+ return searchTerm.value;
145
+ }
146
+ return '';
147
+ });
148
+ const toggleSearch = (ev: Event) => {
149
+ if (isSearchOpen.value && searchTerm.value) return;
150
+ ev.preventDefault();
151
+ isSearchOpen.value = !isSearchOpen.value;
152
+ if (isSearchOpen.value && searchInput) {
153
+ setTimeout(() => {
154
+ if (!searchInput.value) return;
155
+ const { length } = searchTerm.value;
156
+ searchInput.value.setSelectionRange(length, length);
157
+ searchInput.value.focus();
158
+ }, 50);
159
+ }
160
+ };
161
+ const isCartOpen = ref(false);
162
+ const isCartOpenOnce = ref(false);
163
+ watchOnce(isCartOpen, () => {
164
+ isCartOpenOnce.value = true;
165
+ });
166
+ const delayedCartItems = ref(0);
167
+ const handleOnMounted = () => {
168
+ watch(totalItems, (newTotalItems, prevTotalItems) => {
169
+ if (typeof prevTotalItems === 'number') {
170
+ if (prevTotalItems < newTotalItems) {
171
+ isCartOpen.value = true;
172
+ } else if (prevTotalItems && !newTotalItems) {
173
+ isCartOpen.value = false;
174
+ }
175
+ }
176
+ delayedCartItems.value = newTotalItems;
177
+ }, {
178
+ immediate: true,
179
+ });
180
+ };
181
+
123
182
  return {
124
183
  isSticky,
125
184
  staticHeight,
@@ -130,6 +189,15 @@ const useShopHeader = (props: Props) => {
130
189
  getCategoryTree,
131
190
  categoryTrees,
132
191
  inlineMenuTrees,
192
+ isSearchOpen,
193
+ isSearchOpenOnce,
194
+ searchTerm,
195
+ quickSearchTerm,
196
+ toggleSearch,
197
+ isCartOpen,
198
+ isCartOpenOnce,
199
+ cartTotalItems: delayedCartItems,
200
+ handleOnMounted,
133
201
  };
134
202
  };
135
203
 
@@ -1,4 +1,4 @@
1
- import type { SearchItem } from '@cloudcommerce/types';
1
+ import type { SearchItem, SearchResult } from '@cloudcommerce/types';
2
2
  import { ref, watch, shallowReactive } from 'vue';
3
3
  import { useDebounceFn } from '@vueuse/core';
4
4
  import api from '@cloudcommerce/api';
@@ -8,6 +8,13 @@ const storageKey = 'ecomSeachHistory';
8
8
 
9
9
  export const searchHistory = useStorage<string[]>(storageKey, []);
10
10
 
11
+ for (let i = 0; i < searchHistory.length; i++) {
12
+ if (typeof searchHistory[i] !== 'string') {
13
+ searchHistory.splice(i, 1);
14
+ i -= 1;
15
+ }
16
+ }
17
+
11
18
  export const search = async ({
12
19
  term,
13
20
  params,
@@ -30,11 +37,19 @@ export const search = async ({
30
37
  term,
31
38
  },
32
39
  });
33
- if (response.data.result.length && !searchHistory.includes(term)) {
34
- const termIndex = searchHistory.findIndex((_term) => term.startsWith(_term));
35
- if (termIndex > -1) {
36
- searchHistory[termIndex] = term;
40
+ if (response.data.result.length) {
41
+ const completeTermIndex = searchHistory.findIndex((_term) => {
42
+ return _term.includes(term) && !(_term.replace(term, '')).includes(' ');
43
+ });
44
+ if (completeTermIndex > -1) {
45
+ const completeTerm = searchHistory[completeTermIndex];
46
+ searchHistory.splice(completeTermIndex, 1);
47
+ searchHistory.unshift(completeTerm);
37
48
  } else {
49
+ const termIndex = searchHistory.findIndex((_term) => term.startsWith(_term));
50
+ if (termIndex > -1) {
51
+ searchHistory.splice(termIndex, 1);
52
+ }
38
53
  searchHistory.unshift(term);
39
54
  }
40
55
  while (searchHistory.length > 20) {
@@ -45,27 +60,35 @@ export const search = async ({
45
60
  };
46
61
 
47
62
  export class SearchEngine {
48
- url: 'search/v1' | `search/v1?${string}`;
49
63
  fields?: readonly string[];
50
64
  term = ref('');
65
+ isWithCount = ref(true);
66
+ isWithBuckets = ref(true);
51
67
  params = shallowReactive<Record<string, any>>({});
52
68
  pageSize = ref(24);
53
69
  pageNumber = ref(1);
70
+ isFetching = ref(false);
54
71
  products = shallowReactive<SearchItem[]>([]);
72
+ meta = shallowReactive<SearchResult<'v1'>['meta']>({
73
+ offset: 0,
74
+ limit: 0,
75
+ fields: [],
76
+ sort: [],
77
+ query: {},
78
+ });
55
79
  #search: ReturnType<typeof useDebounceFn<typeof search>>;
56
80
  constructor({
57
81
  fields,
58
- url = 'search/v1',
59
82
  debounce = 150,
60
83
  }: {
61
84
  fields?: readonly string[],
62
- url?: 'search/v1' | `search/v1?${string}`,
63
85
  debounce?: number,
64
86
  } = {}) {
65
87
  this.fields = fields;
66
- this.url = url;
67
- this.products = shallowReactive([]);
68
- this.#search = useDebounceFn(search, debounce);
88
+ this.#search = useDebounceFn((opts) => {
89
+ this.isFetching.value = true;
90
+ return search(opts);
91
+ }, debounce);
69
92
  watch([this.term, this.params], () => {
70
93
  this.pageNumber.value = 1;
71
94
  });
@@ -81,17 +104,20 @@ export class SearchEngine {
81
104
  const response = await this.#search({
82
105
  term: this.term.value,
83
106
  params: {
107
+ ...this.params,
84
108
  limit,
85
109
  offset,
86
- ...this.params,
110
+ count: this.isWithCount.value || undefined,
111
+ buckets: this.isWithBuckets.value || undefined,
87
112
  },
88
- url: this.url,
89
113
  fields: this.fields,
90
114
  });
91
115
  if (response) {
116
+ this.isFetching.value = false;
92
117
  const { data } = response;
93
118
  if (data.meta) {
94
119
  this.products.splice(0);
120
+ Object.assign(this.meta, data.meta);
95
121
  }
96
122
  data.result.forEach((item) => this.products.push(item));
97
123
  }
@@ -9,9 +9,10 @@ import parseProduct from '@@sf/state/shopping-cart/parse-product';
9
9
  type CartItem = CartSet['items'][0];
10
10
  const storageKey = 'ecomShoppingCart';
11
11
  const emptyCart = {
12
+ subtotal: 0,
12
13
  items: [],
13
14
  };
14
- const shoppingCart = useStorage<CartSet>(storageKey, emptyCart);
15
+ const shoppingCart = useStorage<CartSet & { subtotal: number }>(storageKey, emptyCart);
15
16
  const totalItems = computed(() => {
16
17
  return shoppingCart.items.reduce((acc, item) => {
17
18
  return acc + item.quantity;
@@ -1,8 +1,10 @@
1
1
  import type { Products, Carts, SearchItem } from '@cloudcommerce/types';
2
+ import { watch } from 'vue';
2
3
  import { watchOnce } from '@vueuse/core';
3
4
  import { price as getPrice, name as getName } from '@ecomplus/utils';
4
5
  import { customer, isLogged } from '@@sf/state/customer-session';
5
6
  import { cartEvents } from '@@sf/state/shopping-cart';
7
+ import { searchHistory } from '@@sf/state/search-engine';
6
8
  import utm from '@@sf/scripts/session-utm';
7
9
 
8
10
  export const trackingIds: {
@@ -218,17 +220,6 @@ export const getGtagItem = (product: Partial<Products> | SearchItem | CartItem)
218
220
 
219
221
  export const useAnalytics = () => {
220
222
  document.addEventListener('astro:beforeload', resetPageViewPromise);
221
- if (isLogged.value) {
222
- emitGtagEvent('login', {});
223
- } else {
224
- watchOnce(isLogged, () => emitGtagEvent('login', {}));
225
- }
226
- cartEvents.on('*', (evName, cartItem) => {
227
- emitGtagEvent(
228
- evName === 'addCartItem' ? 'add_to_cart' : 'remove_from_cart',
229
- { items: [getGtagItem(cartItem)] },
230
- );
231
- });
232
223
  const {
233
224
  gtag,
234
225
  GTAG_TAG_ID,
@@ -279,6 +270,31 @@ export const useAnalytics = () => {
279
270
  }
280
271
  storage.setItem(`analytics_${key}`, trackingIds[key]);
281
272
  });
273
+ if (isLogged.value) {
274
+ emitGtagEvent('login', {});
275
+ } else {
276
+ watchOnce(isLogged, () => emitGtagEvent('login', {}));
277
+ }
278
+ cartEvents.on('*', (evName, cartItem) => {
279
+ emitGtagEvent(
280
+ evName === 'addCartItem' ? 'add_to_cart' : 'remove_from_cart',
281
+ { items: [getGtagItem(cartItem)] },
282
+ );
283
+ });
284
+ watch(searchHistory, () => {
285
+ const term = searchHistory[0];
286
+ if (term) {
287
+ emitGtagEvent('search', { search_term: term });
288
+ }
289
+ });
290
+ if (window.location.pathname === '/s') {
291
+ setTimeout(() => {
292
+ const urlSearchQ = new URLSearchParams(window.location.search).get('q');
293
+ if (urlSearchQ && typeof urlSearchQ === 'string') {
294
+ emitGtagEvent('view_search_results', { search_term: urlSearchQ });
295
+ }
296
+ }, 300);
297
+ }
282
298
  };
283
299
 
284
300
  export default useAnalytics;
@@ -2,7 +2,7 @@
2
2
  "name": "@cloudcommerce/test-base",
3
3
  "private": true,
4
4
  "type": "module",
5
- "version": "0.36.2",
5
+ "version": "0.37.1",
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": "0.36.2",
4
+ "version": "0.37.1",
5
5
  "description": "E-Com Plus Cloud Commerce reusable type definitions",
6
6
  "main": "index.ts",
7
7
  "repository": {
@@ -1,30 +0,0 @@
1
- {
2
- "postCreateCommand": "npm i && npm i --prefix=functions/ssr",
3
- "waitFor": "postCreateCommand",
4
- "portsAttributes": {
5
- "3000": {
6
- "label": "Application",
7
- "onAutoForward": "openPreview"
8
- }
9
- },
10
- "forwardPorts": [
11
- 3000
12
- ],
13
- "postAttachCommand": {
14
- "Server": "npm run dev"
15
- },
16
- "customizations": {
17
- "codespaces": {
18
- "openFiles": [
19
- "functions/ssr/src/main/Home.astro"
20
- ]
21
- },
22
- "vscode": {
23
- "extensions": [
24
- "astro-build.astro-vscode",
25
- "vue.volar",
26
- "bradlc.vscode-tailwindcss"
27
- ]
28
- }
29
- }
30
- }
@@ -1,13 +0,0 @@
1
- # editorconfig.org
2
- root = true
3
-
4
- [*]
5
- indent_style = space
6
- indent_size = 2
7
- end_of_line = lf
8
- charset = utf-8
9
- trim_trailing_whitespace = true
10
- insert_final_newline = true
11
-
12
- [*.md]
13
- trim_trailing_whitespace = false
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- extends: './node_modules/@cloudcommerce/eslint/base.eslintrc.cjs',
3
- };
@@ -1,5 +0,0 @@
1
- {
2
- "projects": {
3
- "default": "ecom2monocard"
4
- }
5
- }
@@ -1,5 +0,0 @@
1
- {
2
- "extends": [
3
- "github>ecomplus/cloud-commerce:store.renovate"
4
- ]
5
- }
@@ -1,37 +0,0 @@
1
- name: Build and deploy
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
- paths:
8
- - 'functions/**'
9
- - 'package-lock.json'
10
- - '.firebaserc'
11
- - '.ecomplus/**'
12
- - '.github/build-and-deploy'
13
- - '.github/workflows/build-and-deploy.yml'
14
- pull_request:
15
- paths:
16
- - 'functions/ssr/**'
17
- - '.firebaserc'
18
- - 'package-lock.json'
19
-
20
- jobs:
21
- build-and-deploy:
22
- name: Cloud Commerce build and deploy
23
- runs-on: ubuntu-latest
24
- if: |
25
- github.event.head_commit.message != 'Initial commit' &&
26
- !contains(github.event.head_commit.message, '[skip ci]')
27
- steps:
28
- - uses: actions/checkout@v3
29
- with:
30
- fetch-depth: 0
31
- - uses: ecomplus/cloud-commerce@main
32
- with:
33
- github-token: ${{ secrets.GITHUB_TOKEN }}
34
- firebase-service-account: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
35
- ecom-authentication-id: ${{ secrets.ECOM_AUTHENTICATION_ID }}
36
- ecom-api-key: ${{ secrets.ECOM_API_KEY }}
37
- ecom-store-id: ${{ secrets.ECOM_STORE_ID }}
@@ -1,23 +0,0 @@
1
- name: Compress images
2
-
3
- on:
4
- pull_request:
5
- paths:
6
- - '**.jpg'
7
- - '**.jpeg'
8
- - '**.png'
9
- - '**.webp'
10
- - 'package-lock.json'
11
-
12
- jobs:
13
- build:
14
- # Only run on Pull Requests within the same repository, and not from forks.
15
- if: github.event.pull_request.head.repo.full_name == github.repository
16
- name: calibreapp/image-actions
17
- runs-on: ubuntu-latest
18
- steps:
19
- - uses: actions/checkout@v3
20
- - name: Compress images
21
- uses: calibreapp/image-actions@main
22
- with:
23
- githubToken: ${{ secrets.GITHUB_TOKEN }}
@@ -1,12 +0,0 @@
1
- tasks:
2
- - init: npm i && npm i --prefix=functions/ssr
3
- command: npm run dev
4
- vscode:
5
- extensions:
6
- - astro-build.astro-vscode
7
- - vue.volar
8
- - bradlc.vscode-tailwindcss
9
- ports:
10
- - port: 3000
11
- onOpen: open-preview
12
- visibility: public
@@ -1,24 +0,0 @@
1
- {pkgs}: {
2
- channel = "stable-23.05"; # "stable-23.05" or "unstable"
3
- packages = [
4
- pkgs.nodejs_18
5
- pkgs.nodePackages.firebase-tools
6
- ];
7
- idx.extensions = [
8
- "vue.volar"
9
- # Other recommended extensions crashing launch
10
- # "dbaeumer.vscode-eslint",
11
- # "astro-build.astro-vscode",
12
- # "bradlc.vscode-tailwindcss",
13
- ];
14
- idx.previews = {
15
- enable = true;
16
- previews = [
17
- {
18
- command = ["npm" "run" "dev" "--" "--port" "$PORT" "--host"];
19
- manager = "web";
20
- id = "web";
21
- }
22
- ];
23
- };
24
- }
@@ -1 +0,0 @@
1
- 18
@@ -1,8 +0,0 @@
1
- {
2
- "recommendations": [
3
- "dbaeumer.vscode-eslint",
4
- "astro-build.astro-vscode",
5
- "vue.volar",
6
- "bradlc.vscode-tailwindcss"
7
- ]
8
- }
@@ -1,11 +0,0 @@
1
- {
2
- "version": "0.2.0",
3
- "configurations": [
4
- {
5
- "command": "./node_modules/.bin/cloudcommerce dev",
6
- "name": "Development server",
7
- "request": "launch",
8
- "type": "node-terminal"
9
- }
10
- ]
11
- }