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.
- package/.github/workflows/test-apps.yml +2 -2
- package/.gitmodules +0 -3
- package/.vscode/settings.json +0 -1
- package/CHANGELOG.md +38 -0
- package/action.yml +2 -2
- package/ecomplus-stores/barra-doce/functions/many/package.json +3 -3
- package/ecomplus-stores/barra-doce/functions/ssr/package.json +6 -6
- package/ecomplus-stores/barra-doce/functions/with-apps/package.json +3 -3
- package/ecomplus-stores/barra-doce/package.json +2 -2
- package/package.json +5 -5
- package/packages/api/package.json +1 -1
- package/packages/apps/affilate-program/package.json +1 -1
- package/packages/apps/correios/package.json +1 -1
- package/packages/apps/custom-payment/package.json +1 -1
- package/packages/apps/custom-shipping/package.json +1 -1
- package/packages/apps/datafrete/package.json +1 -1
- package/packages/apps/discounts/package.json +1 -1
- package/packages/apps/emails/package.json +1 -1
- package/packages/apps/fb-conversions/package.json +2 -2
- package/packages/apps/flash-courier/package.json +1 -1
- package/packages/apps/frenet/package.json +1 -1
- package/packages/apps/galaxpay/package.json +1 -1
- package/packages/apps/google-analytics/package.json +1 -1
- package/packages/apps/jadlog/package.json +1 -1
- package/packages/apps/loyalty-points/package.json +1 -1
- package/packages/apps/mandae/package.json +1 -1
- package/packages/apps/melhor-envio/package.json +1 -1
- package/packages/apps/mercadopago/package.json +1 -1
- package/packages/apps/pagarme/package.json +1 -1
- package/packages/apps/pagarme-v5/package.json +1 -1
- package/packages/apps/paghiper/package.json +1 -1
- package/packages/apps/pix/package.json +1 -1
- package/packages/apps/tiny-erp/package.json +1 -1
- package/packages/apps/webhooks/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/config/package.json +1 -1
- package/packages/emails/package.json +1 -1
- package/packages/eslint/package.json +5 -5
- package/packages/events/package.json +1 -1
- package/packages/feeds/package.json +1 -1
- package/packages/firebase/package.json +1 -1
- package/packages/i18n/package.json +1 -1
- package/packages/modules/package.json +1 -1
- package/packages/passport/package.json +1 -1
- package/packages/ssr/package.json +4 -4
- package/packages/storefront/package.json +11 -10
- package/packages/storefront/src/helpers/sf-utils.ts +8 -5
- package/packages/storefront/src/lib/components/CarouselControl.vue +1 -1
- package/packages/storefront/src/lib/composables/use-search-modal.ts +90 -0
- package/packages/storefront/src/lib/composables/use-shop-header.ts +69 -1
- package/packages/storefront/src/lib/state/search-engine.ts +39 -13
- package/packages/storefront/src/lib/state/shopping-cart.ts +2 -1
- package/packages/storefront/src/lib/state/use-analytics.ts +27 -11
- package/packages/test-base/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/ecomplus-stores/monocard/.devcontainer/devcontainer.json +0 -30
- package/ecomplus-stores/monocard/.editorconfig +0 -13
- package/ecomplus-stores/monocard/.eslintrc.cjs +0 -3
- package/ecomplus-stores/monocard/.firebaserc +0 -5
- package/ecomplus-stores/monocard/.github/build-and-deploy +0 -1
- package/ecomplus-stores/monocard/.github/renovate.json +0 -5
- package/ecomplus-stores/monocard/.github/workflows/build-and-deploy.yml +0 -37
- package/ecomplus-stores/monocard/.github/workflows/calibreapp-image-actions.yml +0 -23
- package/ecomplus-stores/monocard/.gitpod.yml +0 -12
- package/ecomplus-stores/monocard/.idx/dev.nix +0 -24
- package/ecomplus-stores/monocard/.nvmrc +0 -1
- package/ecomplus-stores/monocard/.vscode/extensions.json +0 -8
- package/ecomplus-stores/monocard/.vscode/launch.json +0 -11
- package/ecomplus-stores/monocard/.vscode/settings.json +0 -13
- package/ecomplus-stores/monocard/LICENSE.md +0 -230
- package/ecomplus-stores/monocard/README.md +0 -31
- package/ecomplus-stores/monocard/SETUP.md +0 -129
- package/ecomplus-stores/monocard/SETUP.pt-BR.md +0 -129
- package/ecomplus-stores/monocard/functions/config.json +0 -3
- package/ecomplus-stores/monocard/functions/example.env +0 -10
- package/ecomplus-stores/monocard/functions/many/index.js +0 -14
- package/ecomplus-stores/monocard/functions/many/package.json +0 -22
- package/ecomplus-stores/monocard/functions/ssr/.eslintrc.cjs +0 -6
- package/ecomplus-stores/monocard/functions/ssr/astro.config.mjs +0 -4
- package/ecomplus-stores/monocard/functions/ssr/content/blog/.gitkeep +0 -0
- package/ecomplus-stores/monocard/functions/ssr/content/extra-pages/terms.json +0 -11
- package/ecomplus-stores/monocard/functions/ssr/content/extra-pages/trocas.json +0 -11
- package/ecomplus-stores/monocard/functions/ssr/content/layout.json +0 -52
- package/ecomplus-stores/monocard/functions/ssr/content/pages/home.json +0 -20
- package/ecomplus-stores/monocard/functions/ssr/content/pages/products.json +0 -18
- package/ecomplus-stores/monocard/functions/ssr/content/settings.json +0 -78
- package/ecomplus-stores/monocard/functions/ssr/index.js +0 -18
- package/ecomplus-stores/monocard/functions/ssr/package.json +0 -36
- package/ecomplus-stores/monocard/functions/ssr/public/admin/.gitkeep +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/assets/lotties/img_1.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/assets/lotties/img_1.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/assets/lotties/phone-nfc.json +0 -1
- package/ecomplus-stores/monocard/functions/ssr/public/img/icon.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/large-icon.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/card-phone.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/devices.jpg +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/ecom-icon.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/edit-suit.jpg +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/favicon.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/icon.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/large-icon.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-arcelor-mittal.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-azul.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-banco-pan.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-brinks.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-mastercard.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-pfizer.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-prudential.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo-unimed.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/logo.webp +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/mockup-editar.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/og-image.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/padronagem-tilada.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/qrcode-camera.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/img/uploads/sua-logo-aqui.png +0 -0
- package/ecomplus-stores/monocard/functions/ssr/public/robots.txt +0 -6
- package/ecomplus-stores/monocard/functions/ssr/scripts/build.sh +0 -14
- package/ecomplus-stores/monocard/functions/ssr/src/assets/card.css +0 -99
- package/ecomplus-stores/monocard/functions/ssr/src/assets/style.css +0 -79
- package/ecomplus-stores/monocard/functions/ssr/src/components/AccountMenu.vue +0 -97
- package/ecomplus-stores/monocard/functions/ssr/src/components/AccountPage.vue +0 -62
- package/ecomplus-stores/monocard/functions/ssr/src/components/Banner.vue +0 -59
- package/ecomplus-stores/monocard/functions/ssr/src/components/BannersGrid.astro +0 -25
- package/ecomplus-stores/monocard/functions/ssr/src/components/Breadcrumbs.astro +0 -44
- package/ecomplus-stores/monocard/functions/ssr/src/components/CartItem.vue +0 -64
- package/ecomplus-stores/monocard/functions/ssr/src/components/CartSidebar.vue +0 -69
- package/ecomplus-stores/monocard/functions/ssr/src/components/CasesGrid.astro +0 -49
- package/ecomplus-stores/monocard/functions/ssr/src/components/CheckoutPage.vue +0 -33
- package/ecomplus-stores/monocard/functions/ssr/src/components/Collapse.vue +0 -19
- package/ecomplus-stores/monocard/functions/ssr/src/components/DemoVideo.vue +0 -10
- package/ecomplus-stores/monocard/functions/ssr/src/components/DocDescription.vue +0 -28
- package/ecomplus-stores/monocard/functions/ssr/src/components/FeatureTabs.vue +0 -286
- package/ecomplus-stores/monocard/functions/ssr/src/components/FeaturesSection.astro +0 -28
- package/ecomplus-stores/monocard/functions/ssr/src/components/FooterStamps.vue +0 -63
- package/ecomplus-stores/monocard/functions/ssr/src/components/ImagesGallery.vue +0 -154
- package/ecomplus-stores/monocard/functions/ssr/src/components/LoginForm.vue +0 -107
- package/ecomplus-stores/monocard/functions/ssr/src/components/LottiePhoneNFC.vue +0 -20
- package/ecomplus-stores/monocard/functions/ssr/src/components/MonocardCustomizer.vue +0 -261
- package/ecomplus-stores/monocard/functions/ssr/src/components/PitchBar.vue +0 -61
- package/ecomplus-stores/monocard/functions/ssr/src/components/Prices.vue +0 -95
- package/ecomplus-stores/monocard/functions/ssr/src/components/ProductCard.vue +0 -117
- package/ecomplus-stores/monocard/functions/ssr/src/components/ProductDetails.vue +0 -122
- package/ecomplus-stores/monocard/functions/ssr/src/components/ProductShelf.vue +0 -57
- package/ecomplus-stores/monocard/functions/ssr/src/components/ProductSpecifications.vue +0 -42
- package/ecomplus-stores/monocard/functions/ssr/src/components/SearchModal.vue +0 -6
- package/ecomplus-stores/monocard/functions/ssr/src/components/ShopFooter.vue +0 -71
- package/ecomplus-stores/monocard/functions/ssr/src/components/ShopHeader.vue +0 -137
- package/ecomplus-stores/monocard/functions/ssr/src/components/ShopHeaderMenu.vue +0 -92
- package/ecomplus-stores/monocard/functions/ssr/src/components/ShopSidenav.vue +0 -64
- package/ecomplus-stores/monocard/functions/ssr/src/components/ShopSidenavCategory.vue +0 -77
- package/ecomplus-stores/monocard/functions/ssr/src/components/SkuSelector.vue +0 -58
- package/ecomplus-stores/monocard/functions/ssr/src/env.d.ts +0 -13
- package/ecomplus-stores/monocard/functions/ssr/src/layouts/Base.astro +0 -15
- package/ecomplus-stores/monocard/functions/ssr/src/layouts/PageFooter.astro +0 -53
- package/ecomplus-stores/monocard/functions/ssr/src/layouts/PageHeader.astro +0 -35
- package/ecomplus-stores/monocard/functions/ssr/src/main/Fallback.astro +0 -10
- package/ecomplus-stores/monocard/functions/ssr/src/main/Home.astro +0 -95
- package/ecomplus-stores/monocard/functions/ssr/src/main/Sections.astro +0 -52
- package/ecomplus-stores/monocard/functions/ssr/src/main/Wildcard.astro +0 -18
- package/ecomplus-stores/monocard/functions/ssr/src/pages/[...slug].astro +0 -42
- package/ecomplus-stores/monocard/functions/ssr/src/pages/_vue.ts +0 -10
- package/ecomplus-stores/monocard/functions/ssr/src/pages/app/account.astro +0 -34
- package/ecomplus-stores/monocard/functions/ssr/src/pages/app/index.astro +0 -62
- package/ecomplus-stores/monocard/functions/ssr/src/pages/comprar/index.astro +0 -52
- package/ecomplus-stores/monocard/functions/ssr/src/pages/index.astro +0 -32
- package/ecomplus-stores/monocard/functions/ssr/src/pages/~fallback.astro +0 -23
- package/ecomplus-stores/monocard/functions/ssr/src/scripts/InlineScripts.astro +0 -10
- package/ecomplus-stores/monocard/functions/ssr/tailwind.config.cjs +0 -18
- package/ecomplus-stores/monocard/functions/ssr/tsconfig.json +0 -12
- package/ecomplus-stores/monocard/functions/ssr/uno.config.cjs +0 -5
- package/ecomplus-stores/monocard/functions/with-apps/index.js +0 -12
- package/ecomplus-stores/monocard/functions/with-apps/package.json +0 -22
- package/ecomplus-stores/monocard/package.json +0 -31
- package/ecomplus-stores/monocard/scripts/install.sh +0 -24
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import type { Products } from '@cloudcommerce/api/types';
|
|
3
|
-
import ecomUtils from '@ecomplus/utils';
|
|
4
|
-
|
|
5
|
-
export interface Props {
|
|
6
|
-
monocard: Partial<Products>;
|
|
7
|
-
monocardWithLogo?: Partial<Products>;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const { price: getPrice, formatMoney } = ecomUtils;
|
|
11
|
-
// eslint-disable-next-line vue/no-setup-props-destructure
|
|
12
|
-
const {
|
|
13
|
-
monocard,
|
|
14
|
-
monocardWithLogo,
|
|
15
|
-
} = withDefaults(defineProps<Props>(), {
|
|
16
|
-
monocard: typeof window === 'object'
|
|
17
|
-
? (window as any).monocard
|
|
18
|
-
: {},
|
|
19
|
-
monocardWithLogo: typeof window === 'object'
|
|
20
|
-
? (window as any).monocardWithLogo
|
|
21
|
-
: {},
|
|
22
|
-
});
|
|
23
|
-
const cardVariants: Array<{ bgColor: string, textColor: string }> = [];
|
|
24
|
-
monocard.variations?.forEach(({ specifications: { colors } }) => {
|
|
25
|
-
if (colors && colors.length) {
|
|
26
|
-
const { value: bgColor } = colors[0];
|
|
27
|
-
if (
|
|
28
|
-
!cardVariants.find((cardVariant) => cardVariant.bgColor === bgColor)
|
|
29
|
-
&& colors[1]?.value !== bgColor
|
|
30
|
-
) {
|
|
31
|
-
cardVariants.push({
|
|
32
|
-
bgColor,
|
|
33
|
-
textColor: colors[1]?.value || (bgColor.startsWith('#f') ? '#000' : '#fff'),
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
const cardBgColor = ref(cardVariants[0]?.bgColor || '#000');
|
|
39
|
-
const cardTextColor = ref(cardVariants[0]?.textColor || '#fff');
|
|
40
|
-
const selectCardVariant = ({ bgColor, textColor }: typeof cardVariants[0]) => {
|
|
41
|
-
cardBgColor.value = bgColor;
|
|
42
|
-
cardTextColor.value = textColor;
|
|
43
|
-
};
|
|
44
|
-
const isLogoEnabled = ref(typeof window === 'object'
|
|
45
|
-
&& /[?&]logomarca(&|$)/.test(window.location.search));
|
|
46
|
-
const enablingLogoTimer = ref(null);
|
|
47
|
-
watch(isLogoEnabled, (_isLogoEnabled) => {
|
|
48
|
-
if (_isLogoEnabled) {
|
|
49
|
-
clearTimeout(enablingLogoTimer.value);
|
|
50
|
-
enablingLogoTimer.value = setTimeout(() => {
|
|
51
|
-
enablingLogoTimer.value = null;
|
|
52
|
-
}, 3000);
|
|
53
|
-
} else {
|
|
54
|
-
enablingLogoTimer.value = null;
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
const customLogoUrl = ref('');
|
|
58
|
-
const isLoadingLogo = ref(false);
|
|
59
|
-
const upload = (ev) => {
|
|
60
|
-
isLoadingLogo.value = true;
|
|
61
|
-
const image = ev.target.files[0];
|
|
62
|
-
const reader = new FileReader();
|
|
63
|
-
reader.readAsDataURL(image);
|
|
64
|
-
reader.onload = (loadEv) => {
|
|
65
|
-
customLogoUrl.value = loadEv.target.result.toString();
|
|
66
|
-
setTimeout(() => {
|
|
67
|
-
isLoadingLogo.value = false;
|
|
68
|
-
}, 3000);
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
const isLogoInputFocus = ref(false);
|
|
72
|
-
const isNameInputFocus = ref(false);
|
|
73
|
-
const cardAnimationClass = computed(() => {
|
|
74
|
-
if (!isLogoEnabled.value) {
|
|
75
|
-
return 'card--no-back';
|
|
76
|
-
}
|
|
77
|
-
return !isNameInputFocus.value
|
|
78
|
-
&& (isLoadingLogo.value || enablingLogoTimer.value || isLogoInputFocus.value)
|
|
79
|
-
? 'card--show-back' : null;
|
|
80
|
-
});
|
|
81
|
-
const logoInput = ref(null);
|
|
82
|
-
const cardsBag = ref([{
|
|
83
|
-
holderName: '',
|
|
84
|
-
quantity: 1,
|
|
85
|
-
}]);
|
|
86
|
-
const focusedCard = ref(0);
|
|
87
|
-
const holderName = computed(() => {
|
|
88
|
-
return cardsBag.value[focusedCard.value].holderName;
|
|
89
|
-
});
|
|
90
|
-
const removeCard = (index: number) => {
|
|
91
|
-
cardsBag.value.splice(index, 1);
|
|
92
|
-
if (focusedCard.value === index) {
|
|
93
|
-
focusedCard.value = 0;
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
const totalQuantity = computed(() => {
|
|
97
|
-
return cardsBag.value.reduce((acc, { quantity }) => (acc + quantity), 0);
|
|
98
|
-
});
|
|
99
|
-
const price = computed(() => {
|
|
100
|
-
if (isLogoEnabled.value && customLogoUrl.value && monocardWithLogo) {
|
|
101
|
-
return getPrice(monocardWithLogo) as number;
|
|
102
|
-
}
|
|
103
|
-
return getPrice(monocard) as number;
|
|
104
|
-
});
|
|
105
|
-
const logoAdditionalPrice = monocardWithLogo
|
|
106
|
-
? getPrice(monocardWithLogo) - getPrice(monocard) as number : 30;
|
|
107
|
-
</script>
|
|
108
|
-
|
|
109
|
-
<template>
|
|
110
|
-
<div class="container">
|
|
111
|
-
<article class="mx-auto max-w-4xl gap-5 lg:flex">
|
|
112
|
-
<div class="order-2 mb-10 basis-1/2 lg:mb-0">
|
|
113
|
-
<div class="mb-3 mr-5 inline-block">
|
|
114
|
-
<i class="i-checkbox-circle-fill bg-primary mr-1"></i> Frete grátis
|
|
115
|
-
</div>
|
|
116
|
-
<div class="mb-3 inline-block">
|
|
117
|
-
<i class="i-checkbox-circle-fill bg-primary mr-1"></i> Sem mensalidade
|
|
118
|
-
</div>
|
|
119
|
-
<a name="comprar"></a>
|
|
120
|
-
<h1 class="mb-3">Seu cartão de visitas eletrônico personalizado</h1>
|
|
121
|
-
<h4 class="mb-10 text-sm">
|
|
122
|
-
<a href="#como-funciona">
|
|
123
|
-
<i class="i-play-circle-line mr-1"></i>Como o Monocard funciona?
|
|
124
|
-
</a>
|
|
125
|
-
</h4>
|
|
126
|
-
<form>
|
|
127
|
-
<div
|
|
128
|
-
v-for="(card, i) in cardsBag"
|
|
129
|
-
:key="i"
|
|
130
|
-
class="mb-3 flex gap-2"
|
|
131
|
-
>
|
|
132
|
-
<input
|
|
133
|
-
id="login-form-email"
|
|
134
|
-
type="text"
|
|
135
|
-
class="mb-0 uppercase"
|
|
136
|
-
placeholder="Nome no cartão"
|
|
137
|
-
@focus="focusedCard = i"
|
|
138
|
-
@focusin="isNameInputFocus = true"
|
|
139
|
-
@focusout="isNameInputFocus = false"
|
|
140
|
-
v-model="card.holderName"
|
|
141
|
-
required
|
|
142
|
-
>
|
|
143
|
-
<div class="flex basis-1/3 items-center">
|
|
144
|
-
<input
|
|
145
|
-
class="mb-0"
|
|
146
|
-
type="number"
|
|
147
|
-
min="1"
|
|
148
|
-
v-model="card.quantity"
|
|
149
|
-
@change="ev => (ev as any).target.value <= 0 ? card.quantity = 1 : null"
|
|
150
|
-
required
|
|
151
|
-
>
|
|
152
|
-
<div v-if="cardsBag.length > 1" class="flex-auto">
|
|
153
|
-
<div
|
|
154
|
-
class="i-close-fill ml-1 bg-red-400 text-xl"
|
|
155
|
-
role="button"
|
|
156
|
-
:aria-label="`Remover cartão ${(i + 1)}`"
|
|
157
|
-
@click="removeCard(i)"
|
|
158
|
-
></div>
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
</div>
|
|
162
|
-
<div class="gap-8 lg:flex">
|
|
163
|
-
<div class="order-last flex-none">
|
|
164
|
-
<button
|
|
165
|
-
class="secondary inline-block w-auto flex-none text-sm leading-none"
|
|
166
|
-
type="button"
|
|
167
|
-
@click="cardsBag.push({ holderName: '', quantity: 1 })"
|
|
168
|
-
>
|
|
169
|
-
<i class="i-add-circle-fill mr-1"></i>
|
|
170
|
-
Adicionar cartão
|
|
171
|
-
</button>
|
|
172
|
-
</div>
|
|
173
|
-
<div class="grow">
|
|
174
|
-
<div class="mb-5 mt-6">
|
|
175
|
-
<strong class="block text-4xl">
|
|
176
|
-
{{ formatMoney(price * totalQuantity) }}
|
|
177
|
-
</strong>
|
|
178
|
-
<span v-if="totalQuantity > 1">{{ formatMoney(price) }} /cartão</span>
|
|
179
|
-
</div>
|
|
180
|
-
<button class="rounded-full text-xl font-bold uppercase" type="submit">
|
|
181
|
-
Comprar
|
|
182
|
-
</button>
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
185
|
-
</form>
|
|
186
|
-
</div>
|
|
187
|
-
<div class="order-1 basis-1/2">
|
|
188
|
-
<div
|
|
189
|
-
class="card mb-5 mt-2"
|
|
190
|
-
:class="cardAnimationClass"
|
|
191
|
-
:style="{
|
|
192
|
-
'--background-color': cardBgColor,
|
|
193
|
-
'--color': cardTextColor,
|
|
194
|
-
}"
|
|
195
|
-
>
|
|
196
|
-
<div class="card__front card__part">
|
|
197
|
-
<div class="card__front-square card__square">
|
|
198
|
-
<div class="i-qr-code-line text-5xl"></div>
|
|
199
|
-
</div>
|
|
200
|
-
<div class="card__front-logo card__logo">
|
|
201
|
-
<div class="text-sm font-bold">monocard</div>
|
|
202
|
-
</div>
|
|
203
|
-
<div class="card__space-75">
|
|
204
|
-
<p class="card__info">{{ holderName || 'Seu nome aqui' }}</p>
|
|
205
|
-
</div>
|
|
206
|
-
<div class="card__space-25">
|
|
207
|
-
<p class="card__info">
|
|
208
|
-
<i class="i-wifi-fill rotate-90 text-lg"></i>
|
|
209
|
-
</p>
|
|
210
|
-
</div>
|
|
211
|
-
</div>
|
|
212
|
-
<div class="card__back card__part">
|
|
213
|
-
<img
|
|
214
|
-
:src="(isLogoEnabled && customLogoUrl) || '/img/uploads/sua-logo-aqui.png'"
|
|
215
|
-
class="cursor-pointer"
|
|
216
|
-
@click="logoInput.click()"
|
|
217
|
-
>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
<button
|
|
221
|
-
v-for="{ bgColor, textColor } in cardVariants"
|
|
222
|
-
:key="bgColor"
|
|
223
|
-
class="border-1 border-gray relative mr-2 inline-block h-5
|
|
224
|
-
w-5 rounded-full p-0 shadow drop-shadow"
|
|
225
|
-
:style="{ background: bgColor }"
|
|
226
|
-
@click="selectCardVariant({ bgColor, textColor })"
|
|
227
|
-
>
|
|
228
|
-
<i
|
|
229
|
-
v-if="cardBgColor === bgColor"
|
|
230
|
-
class="i-checkbox-fill absolute bg-green-300 text-xs"
|
|
231
|
-
></i>
|
|
232
|
-
</button>
|
|
233
|
-
<div class="mt-5">
|
|
234
|
-
<label for="switch-logo" class="inline-block">
|
|
235
|
-
<input
|
|
236
|
-
id="switch-logo"
|
|
237
|
-
type="checkbox"
|
|
238
|
-
name="switch"
|
|
239
|
-
role="switch"
|
|
240
|
-
v-model="isLogoEnabled"
|
|
241
|
-
>
|
|
242
|
-
Imagem no verso
|
|
243
|
-
<small class="mb-2 text-sm" v-if="logoAdditionalPrice">
|
|
244
|
-
<br>+ {{ formatMoney(logoAdditionalPrice) }} por cartão
|
|
245
|
-
</small>
|
|
246
|
-
</label>
|
|
247
|
-
</div>
|
|
248
|
-
<input
|
|
249
|
-
v-if="isLogoEnabled"
|
|
250
|
-
type="file"
|
|
251
|
-
class="w-auto"
|
|
252
|
-
accept="image/*"
|
|
253
|
-
ref="logoInput"
|
|
254
|
-
@change="upload"
|
|
255
|
-
@mouseenter="isLogoInputFocus = true"
|
|
256
|
-
@mouseout="isLogoInputFocus = false"
|
|
257
|
-
>
|
|
258
|
-
</div>
|
|
259
|
-
</article>
|
|
260
|
-
</div>
|
|
261
|
-
</template>
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="relative z-20 bg-black uppercase">
|
|
3
|
-
<div class="bg-primary/20">
|
|
4
|
-
<div class="container mx-auto px-3 py-1 md:w-2/3">
|
|
5
|
-
<Carousel :autoplay="countValidSlides > 1 ? 7000 : undefined">
|
|
6
|
-
<li
|
|
7
|
-
v-for="(slide, i) in slides"
|
|
8
|
-
:key="i"
|
|
9
|
-
class="h-full shrink-0 basis-full text-center"
|
|
10
|
-
>
|
|
11
|
-
<component
|
|
12
|
-
:is="slide.href ? 'ALink' : 'span'"
|
|
13
|
-
:href="slide.href"
|
|
14
|
-
:target="slide.target"
|
|
15
|
-
class="inline-block px-8"
|
|
16
|
-
:class="slide.href ? 'hover:underline' : null"
|
|
17
|
-
>
|
|
18
|
-
<span
|
|
19
|
-
v-if="parsedContents[i]"
|
|
20
|
-
v-html="parsedContents[i]"
|
|
21
|
-
class="prose text-primary-100 text-sm"
|
|
22
|
-
></span>
|
|
23
|
-
</component>
|
|
24
|
-
</li>
|
|
25
|
-
<template #controls>
|
|
26
|
-
<div
|
|
27
|
-
v-show="countValidSlides > 1"
|
|
28
|
-
class="text-primary-400 text-xl leading-none"
|
|
29
|
-
>
|
|
30
|
-
<CarouselControl
|
|
31
|
-
:direction="-1"
|
|
32
|
-
class="hover:text-primary-200 pr-2"
|
|
33
|
-
/>
|
|
34
|
-
<CarouselControl class="hover:text-primary-200 pl-2" />
|
|
35
|
-
</div>
|
|
36
|
-
</template>
|
|
37
|
-
</Carousel>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
</template>
|
|
42
|
-
|
|
43
|
-
<script setup lang="ts">
|
|
44
|
-
import usePitchBar from '@@sf/composables/use-pitch-bar';
|
|
45
|
-
import Carousel from '@@sf/components/Carousel.vue';
|
|
46
|
-
import CarouselControl from '@@sf/components/CarouselControl.vue';
|
|
47
|
-
|
|
48
|
-
export interface Props {
|
|
49
|
-
slides: Array<{
|
|
50
|
-
href?: string;
|
|
51
|
-
target?: string;
|
|
52
|
-
html: string;
|
|
53
|
-
}>;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const props = defineProps<Props>();
|
|
57
|
-
const {
|
|
58
|
-
parsedContents,
|
|
59
|
-
countValidSlides,
|
|
60
|
-
} = usePitchBar(props);
|
|
61
|
-
</script>
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
class="text-base-600
|
|
4
|
-
[&>div]:[font-size:90%] [&_small]:lowercase [&_small]:[font-size:92%]"
|
|
5
|
-
:class="isBig ? 'text-lg' : null"
|
|
6
|
-
>
|
|
7
|
-
<span v-if="comparePrice" class="text-base-500 mr-1 text-[87%]">
|
|
8
|
-
<small v-if="isLiteral">
|
|
9
|
-
{{ `${$t.i19from} ` }}
|
|
10
|
-
</small>
|
|
11
|
-
<s>{{ $money(comparePrice) }}</s>
|
|
12
|
-
<small v-if="isLiteral">
|
|
13
|
-
{{ ` ${$t.i19to}` }}
|
|
14
|
-
</small>
|
|
15
|
-
</span>
|
|
16
|
-
<strong
|
|
17
|
-
class="text-base-800"
|
|
18
|
-
:class="isBig ? 'text-4xl block' : 'inline-block'"
|
|
19
|
-
>
|
|
20
|
-
<small v-if="hasVariedPrices">
|
|
21
|
-
{{ `${$t.i19asOf} ` }}
|
|
22
|
-
</small>
|
|
23
|
-
{{ $money(salePrice) }}
|
|
24
|
-
</strong>
|
|
25
|
-
<Fade slide="down">
|
|
26
|
-
<div v-if="cashbackValue && hasCashback" class="relative z-10">
|
|
27
|
-
<span :data-tooltip="$t.i19get$1back
|
|
28
|
-
.replace('$1', $percentage(cashbackPercentage))">
|
|
29
|
-
<i class="i-arrow-go-back-fill mr-1"></i>
|
|
30
|
-
<span class="font-medium">
|
|
31
|
-
{{ $money(cashbackValue) }}
|
|
32
|
-
</span>
|
|
33
|
-
<small> cashback</small>
|
|
34
|
-
</span>
|
|
35
|
-
</div>
|
|
36
|
-
</Fade>
|
|
37
|
-
<Fade slide="down">
|
|
38
|
-
<div v-if="installmentValue && hasPriceOptions">
|
|
39
|
-
<small v-if="isLiteral">
|
|
40
|
-
{{ `${$t.i19upTo} ` }}
|
|
41
|
-
</small>
|
|
42
|
-
{{ installmentsNumber }}x
|
|
43
|
-
<small v-if="isLiteral">
|
|
44
|
-
{{ ` ${$t.i19of} ` }}
|
|
45
|
-
</small>
|
|
46
|
-
<span>{{ $money(installmentValue) }}</span>
|
|
47
|
-
<small v-if="!monthlyInterest && isLiteral">
|
|
48
|
-
{{ ` ${$t.i19interestFree}` }}
|
|
49
|
-
</small>
|
|
50
|
-
</div>
|
|
51
|
-
</Fade>
|
|
52
|
-
<Fade slide="down">
|
|
53
|
-
<div v-if="priceWithDiscount < salePrice && hasPriceOptions">
|
|
54
|
-
<small v-if="!discountLabel">
|
|
55
|
-
{{ `${$t.i19asOf} ` }}
|
|
56
|
-
</small>
|
|
57
|
-
<span>{{ $money(priceWithDiscount) }}</span>
|
|
58
|
-
<small v-if="discountLabel">
|
|
59
|
-
{{ ` ${discountLabel}` }}
|
|
60
|
-
</small>
|
|
61
|
-
</div>
|
|
62
|
-
</Fade>
|
|
63
|
-
</div>
|
|
64
|
-
</template>
|
|
65
|
-
|
|
66
|
-
<script setup lang="ts">
|
|
67
|
-
import {
|
|
68
|
-
type Props as UsePricesProps,
|
|
69
|
-
usePrices,
|
|
70
|
-
} from '@@sf/composables/use-prices';
|
|
71
|
-
|
|
72
|
-
export interface Props extends UsePricesProps {
|
|
73
|
-
isBig?: boolean;
|
|
74
|
-
isLiteral?: boolean;
|
|
75
|
-
hasCashback?: boolean;
|
|
76
|
-
hasPriceOptions?: boolean;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
80
|
-
hasCashback: true,
|
|
81
|
-
hasPriceOptions: true,
|
|
82
|
-
});
|
|
83
|
-
const {
|
|
84
|
-
hasVariedPrices,
|
|
85
|
-
salePrice,
|
|
86
|
-
comparePrice,
|
|
87
|
-
cashbackPercentage,
|
|
88
|
-
cashbackValue,
|
|
89
|
-
installmentsNumber,
|
|
90
|
-
monthlyInterest,
|
|
91
|
-
installmentValue,
|
|
92
|
-
priceWithDiscount,
|
|
93
|
-
discountLabel,
|
|
94
|
-
} = usePrices(props);
|
|
95
|
-
</script>
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<article
|
|
3
|
-
ref="card"
|
|
4
|
-
:data-sku="product.sku"
|
|
5
|
-
class="group relative mx-auto h-full max-w-[350px] py-3"
|
|
6
|
-
>
|
|
7
|
-
<ALink
|
|
8
|
-
:href="link"
|
|
9
|
-
class="flex h-full flex-col overflow-hidden rounded
|
|
10
|
-
ring-black/5 group-hover:shadow group-hover:ring-1"
|
|
11
|
-
>
|
|
12
|
-
<div class="aspect-square p-2
|
|
13
|
-
transition-transform motion-safe:group-hover:scale-110">
|
|
14
|
-
<div class="relative h-full w-full overflow-hidden rounded bg-white
|
|
15
|
-
group-hover:rounded-none">
|
|
16
|
-
<span v-if="images?.length" class="text-xs text-opacity-70">
|
|
17
|
-
<AImg
|
|
18
|
-
:picture="images[0]"
|
|
19
|
-
:alt="title"
|
|
20
|
-
class="absolute left-0 top-0 block h-full w-full object-cover"
|
|
21
|
-
/>
|
|
22
|
-
<AImg
|
|
23
|
-
v-if="images[1] && wasHoveredOnce"
|
|
24
|
-
:picture="images[1]"
|
|
25
|
-
:alt="title"
|
|
26
|
-
class="absolute left-0 top-0 z-10 block h-full w-full
|
|
27
|
-
object-cover text-transparent opacity-0
|
|
28
|
-
transition-opacity group-hover:opacity-100 motion-safe:duration-300"
|
|
29
|
-
/>
|
|
30
|
-
</span>
|
|
31
|
-
<div
|
|
32
|
-
v-else
|
|
33
|
-
class="from-base-50/20 to-base-100 h-full w-full bg-gradient-to-br"
|
|
34
|
-
/>
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
37
|
-
<span
|
|
38
|
-
v-if="discountPercentage"
|
|
39
|
-
class=":uno: bg-secondary/70 text-on-secondary absolute
|
|
40
|
-
right-2 top-9 py-0.5
|
|
41
|
-
pl-3 pr-1.5 text-xs
|
|
42
|
-
transition-transform [clip-path:polygon(20%_0,100%_0,100%_100%,0_100%)]
|
|
43
|
-
group-hover:translate-x-2 group-hover:scale-110"
|
|
44
|
-
>
|
|
45
|
-
-<strong>{{ discountPercentage }}</strong>%
|
|
46
|
-
</span>
|
|
47
|
-
<div class="relative z-10 flex grow flex-col justify-between
|
|
48
|
-
bg-white/40 p-4 group-hover:backdrop-blur-md">
|
|
49
|
-
<component
|
|
50
|
-
:is="headingTag"
|
|
51
|
-
class="ui-link line-clamp-2 no-underline"
|
|
52
|
-
:class="[
|
|
53
|
-
isActive ? 'text-base-700' : 'text-base-500',
|
|
54
|
-
link ? 'group-hover:text-primary group-hover:underline' : null,
|
|
55
|
-
]"
|
|
56
|
-
>
|
|
57
|
-
{{ title }}
|
|
58
|
-
</component>
|
|
59
|
-
<div class="pt-2">
|
|
60
|
-
<div v-if="isActive">
|
|
61
|
-
<Prices :product="product" />
|
|
62
|
-
</div>
|
|
63
|
-
<span v-else class="ui-badge bg-warning-100 text-warning-700">
|
|
64
|
-
{{ !isInStock ? $t.i19outOfStock : $t.i19inactive }}
|
|
65
|
-
</span>
|
|
66
|
-
</div>
|
|
67
|
-
<button
|
|
68
|
-
v-if="isActive && !hasVariations"
|
|
69
|
-
class=":uno: ui-btn-sm ui-btn-primary absolute -top-6
|
|
70
|
-
left-0 -z-10 hidden w-full rounded-none
|
|
71
|
-
opacity-0 transition group-hover:z-10 group-hover:opacity-100 md:block"
|
|
72
|
-
@click.prevent="addProductToCart(product)"
|
|
73
|
-
>
|
|
74
|
-
<span class="bg-on-primary text-primary mr-1 inline-block h-4 w-4
|
|
75
|
-
rounded-full text-center text-base leading-none opacity-80">
|
|
76
|
-
+
|
|
77
|
-
</span>
|
|
78
|
-
{{ $t.i19addToCart }}
|
|
79
|
-
</button>
|
|
80
|
-
</div>
|
|
81
|
-
</ALink>
|
|
82
|
-
</article>
|
|
83
|
-
</template>
|
|
84
|
-
|
|
85
|
-
<script setup lang="ts">
|
|
86
|
-
import { watchOnce, useElementHover } from '@vueuse/core';
|
|
87
|
-
import { addProductToCart } from '@@sf/state/shopping-cart';
|
|
88
|
-
import {
|
|
89
|
-
type Props as UseProductCardProps,
|
|
90
|
-
useProductCard,
|
|
91
|
-
} from '@@sf/composables/use-product-card';
|
|
92
|
-
import Prices from '~/components/Prices.vue';
|
|
93
|
-
|
|
94
|
-
export type Props = UseProductCardProps & {
|
|
95
|
-
headingTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
99
|
-
headingTag: 'h3',
|
|
100
|
-
});
|
|
101
|
-
const {
|
|
102
|
-
product,
|
|
103
|
-
title,
|
|
104
|
-
link,
|
|
105
|
-
images,
|
|
106
|
-
isInStock,
|
|
107
|
-
isActive,
|
|
108
|
-
discountPercentage,
|
|
109
|
-
hasVariations,
|
|
110
|
-
} = useProductCard(props as UseProductCardProps);
|
|
111
|
-
const card = ref<HTMLElement | null>(null);
|
|
112
|
-
const isHovered = useElementHover(card);
|
|
113
|
-
const wasHoveredOnce = ref(false);
|
|
114
|
-
watchOnce(isHovered, () => {
|
|
115
|
-
wasHoveredOnce.value = true;
|
|
116
|
-
});
|
|
117
|
-
</script>
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<section class="ui-section relative grid grid-cols-1 items-start
|
|
3
|
-
gap-5 md:gap-4 lg:grid-cols-4 2xl:gap-6">
|
|
4
|
-
<div class="w-full lg:col-span-3">
|
|
5
|
-
<template v-if="product.pictures?.length">
|
|
6
|
-
<ImagesGallery :pictures="product.pictures" />
|
|
7
|
-
</template>
|
|
8
|
-
</div>
|
|
9
|
-
<div class="top-0 py-4 lg:sticky">
|
|
10
|
-
<h1 class="ui-text-brand text-base-700 text-xl">
|
|
11
|
-
{{ title }}
|
|
12
|
-
</h1>
|
|
13
|
-
<div v-if="isActive" class="mt-5">
|
|
14
|
-
<Prices :product="product" is-big is-literal />
|
|
15
|
-
<SkuSelector
|
|
16
|
-
v-if="product.variations"
|
|
17
|
-
:variations="product.variations"
|
|
18
|
-
v-model:variation-id="variationId"
|
|
19
|
-
class="my-4"
|
|
20
|
-
/>
|
|
21
|
-
<Fade slide="down">
|
|
22
|
-
<div v-if="hasSkuSelectionAlert" class="ui-alert inline-block">
|
|
23
|
-
{{ $t.i19selectVariationMsg }}
|
|
24
|
-
<i class="i-arrow-right ml-1 -rotate-90"></i>
|
|
25
|
-
</div>
|
|
26
|
-
</Fade>
|
|
27
|
-
<div class="mt-5 flex flex-wrap items-center gap-x-4 gap-y-2
|
|
28
|
-
overflow-hidden md:flex-nowrap lg:mt-4 lg:flex-wrap">
|
|
29
|
-
<QuantitySelector
|
|
30
|
-
v-model="quantity"
|
|
31
|
-
:min="product.min_quantity"
|
|
32
|
-
:max="product.quantity"
|
|
33
|
-
class="border-base-100 rounded md:mr-5
|
|
34
|
-
lg:mb-2 lg:mr-auto lg:border-2"
|
|
35
|
-
/>
|
|
36
|
-
<CheckoutLink
|
|
37
|
-
class="ui-btn-lg ui-btn-primary grow text-center"
|
|
38
|
-
to="checkout"
|
|
39
|
-
:cart-item="{
|
|
40
|
-
product_id: product._id,
|
|
41
|
-
quantity,
|
|
42
|
-
variation_id: variationId || undefined,
|
|
43
|
-
}"
|
|
44
|
-
:data-tooltip="!isSkuSelected ? $t.i19chooseProductDetailsToBuy : null"
|
|
45
|
-
@click="checkVariation"
|
|
46
|
-
>
|
|
47
|
-
<i class="i-chevron-double-right mr-1"></i>
|
|
48
|
-
{{ $t.i19buy }}
|
|
49
|
-
</CheckoutLink>
|
|
50
|
-
<button
|
|
51
|
-
class="ui-btn-lg ui-btn-contrast grow"
|
|
52
|
-
@click.prevent="addToCart"
|
|
53
|
-
:data-tooltip="!isSkuSelected ? $t.i19chooseProductDetailsToBuy : null"
|
|
54
|
-
>
|
|
55
|
-
{{ $t.i19addToCart }}
|
|
56
|
-
</button>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
<div class="w-full lg:col-span-3">
|
|
61
|
-
<slot name="description" />
|
|
62
|
-
</div>
|
|
63
|
-
</section>
|
|
64
|
-
</template>
|
|
65
|
-
|
|
66
|
-
<script setup lang="ts">
|
|
67
|
-
import type { ResourceId, Products } from '@cloudcommerce/api/types';
|
|
68
|
-
import { useUrlSearchParams } from '@vueuse/core';
|
|
69
|
-
import { addProductToCart } from '@@sf/state/shopping-cart';
|
|
70
|
-
import { useProductCard } from '@@sf/composables/use-product-card';
|
|
71
|
-
import CheckoutLink from '@@sf/components/CheckoutLink.vue';
|
|
72
|
-
import QuantitySelector from '@@sf/components/QuantitySelector.vue';
|
|
73
|
-
import Prices from '~/components/Prices.vue';
|
|
74
|
-
import ImagesGallery from '~/components/ImagesGallery.vue';
|
|
75
|
-
import SkuSelector from '~/components/SkuSelector.vue';
|
|
76
|
-
|
|
77
|
-
export interface Props {
|
|
78
|
-
product?: Products;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
82
|
-
product: () => globalThis.$storefront.apiContext?.doc as Products,
|
|
83
|
-
});
|
|
84
|
-
const {
|
|
85
|
-
product,
|
|
86
|
-
title,
|
|
87
|
-
isActive,
|
|
88
|
-
} = useProductCard<Products>(props);
|
|
89
|
-
const quantity = ref(product.min_quantity || 1);
|
|
90
|
-
const params = useUrlSearchParams('history');
|
|
91
|
-
const hasSkuSelectionAlert = ref(false);
|
|
92
|
-
const variationId = ref<ResourceId | null>(null);
|
|
93
|
-
watch(variationId, (_variationId) => {
|
|
94
|
-
if (_variationId) {
|
|
95
|
-
params.var = _variationId;
|
|
96
|
-
hasSkuSelectionAlert.value = false;
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
onMounted(() => {
|
|
100
|
-
watch(params, ({ var: variation }) => {
|
|
101
|
-
if (typeof variation === 'string' && variation) {
|
|
102
|
-
variationId.value = variation as ResourceId;
|
|
103
|
-
}
|
|
104
|
-
}, { immediate: true });
|
|
105
|
-
});
|
|
106
|
-
const isSkuSelected = computed(() => {
|
|
107
|
-
return Boolean(!product.variations?.length || variationId.value);
|
|
108
|
-
});
|
|
109
|
-
const checkVariation = (ev?: Event) => {
|
|
110
|
-
if (!isSkuSelected.value) {
|
|
111
|
-
if (ev) ev.preventDefault();
|
|
112
|
-
hasSkuSelectionAlert.value = true;
|
|
113
|
-
} else {
|
|
114
|
-
hasSkuSelectionAlert.value = false;
|
|
115
|
-
}
|
|
116
|
-
return !hasSkuSelectionAlert.value;
|
|
117
|
-
};
|
|
118
|
-
const addToCart = () => {
|
|
119
|
-
if (!checkVariation()) return;
|
|
120
|
-
addProductToCart(product, variationId.value ? variationId.value : undefined);
|
|
121
|
-
};
|
|
122
|
-
</script>
|