@meeovi/layer-commerce 1.0.1 → 1.0.3
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/app/components/catalog/product/ProductAccordion/ProductAccordion.vue +39 -0
- package/app/components/catalog/product/ProductAccordion/__tests__/ProductAccordion.spec.ts +15 -0
- package/app/components/catalog/product/ProductAccordion/types.ts +5 -0
- package/app/components/catalog/product/ProductProperties/ProductProperties.vue +50 -0
- package/app/components/catalog/product/ProductProperties/__tests__/ProductProperties.spec.ts +15 -0
- package/app/components/catalog/product/ProductProperties/types.ts +5 -0
- package/app/components/catalog/product/ProductSlider/ProductSlider.vue +28 -0
- package/app/components/catalog/product/ProductSlider/__tests__/ProductSlider.spec.ts +14 -0
- package/app/components/catalog/product/ProductSlider/types.ts +7 -0
- package/app/components/catalog/product/RecommendedProducts/RecommendedProducts.vue +12 -0
- package/app/components/catalog/product/RecommendedProducts/types.ts +5 -0
- package/app/components/catalog/product/RenderContentProductSlider/RenderContentProductSlider.vue +11 -0
- package/app/components/catalog/product/add-attribute.vue +54 -0
- package/app/components/catalog/product/add-product-type.vue +54 -0
- package/app/components/catalog/product/add-product.vue +53 -0
- package/app/components/catalog/product/add-showcase.vue +52 -0
- package/app/components/catalog/product/add-station.vue +54 -0
- package/app/components/catalog/product/bestsellers.vue +69 -0
- package/app/components/catalog/product/bidding.vue +93 -0
- package/app/components/catalog/product/colorOptions.vue +58 -0
- package/app/components/catalog/product/deals.vue +61 -0
- package/app/components/catalog/product/exclusives.vue +58 -0
- package/app/components/catalog/product/featuredproducts.vue +69 -0
- package/app/components/catalog/product/giftCard.vue +63 -0
- package/app/components/catalog/product/latestproducts.vue +58 -0
- package/app/components/catalog/product/productCard.vue +71 -0
- package/app/components/catalog/product/productCompare.vue +60 -0
- package/app/components/catalog/product/productCompareTable.vue +441 -0
- package/app/components/catalog/product/productDetails.vue +120 -0
- package/app/components/catalog/product/productFaqs.vue +17 -0
- package/app/components/catalog/product/productGallery.vue +16 -0
- package/app/components/catalog/product/productQty.vue +54 -0
- package/app/components/catalog/product/productReviews.vue +56 -0
- package/app/components/catalog/product/productSpecs.vue +116 -0
- package/app/components/catalog/product/radiostation.vue +36 -0
- package/app/components/catalog/product/recentlyviewed.vue +43 -0
- package/app/components/catalog/product/relatedbrands.vue +54 -0
- package/app/components/catalog/product/relatedproducts.vue +58 -0
- package/app/components/catalog/product/relatedstations.vue +40 -0
- package/app/components/catalog/product/shippingOptions.vue +41 -0
- package/app/components/catalog/product/sizeOptions.vue +47 -0
- package/app/components/catalog/product/update-attribute-set.vue +209 -0
- package/app/components/catalog/product/update-attribute.vue +118 -0
- package/app/components/catalog/product/update-product.vue +372 -0
- package/app/components/catalog/product/update-showcase.vue +153 -0
- package/app/components/catalog/shops/relatedstores.vue +52 -0
- package/app/components/catalog/shops/restaurant.vue +66 -0
- package/app/components/catalog/shops/stores.vue +44 -0
- package/app/components/catalog/vendor/README.md +3 -0
- package/app/components/catalog/vendor/blocks/biggestcustomers.vue +33 -0
- package/app/components/catalog/vendor/blocks/lowestselling.vue +33 -0
- package/app/components/catalog/vendor/blocks/topcategories.vue +33 -0
- package/app/components/catalog/vendor/blocks/topproducts.vue +27 -0
- package/app/components/catalog/vendor/pages/attributes.vue +43 -0
- package/app/components/catalog/vendor/pages/commissions.vue +43 -0
- package/app/components/catalog/vendor/pages/crm.vue +67 -0
- package/app/components/catalog/vendor/pages/dashboard.vue +46 -0
- package/app/components/catalog/vendor/pages/emails.vue +43 -0
- package/app/components/catalog/vendor/pages/enquiries.vue +43 -0
- package/app/components/catalog/vendor/pages/invoices.vue +43 -0
- package/app/components/catalog/vendor/pages/orders.vue +68 -0
- package/app/components/catalog/vendor/pages/products.vue +55 -0
- package/app/components/catalog/vendor/pages/reviews.vue +48 -0
- package/app/components/catalog/vendor/pages/shipments.vue +43 -0
- package/app/components/catalog/vendor/pages/stores.vue +43 -0
- package/app/components/content/blocks/breadcrumbs.vue +0 -0
- package/app/components/content/blocks/currencySwitcher.vue +0 -0
- package/app/components/content/blocks/languageSwitcher.vue +0 -0
- package/app/components/content/blocks/videoproduct.vue +9 -0
- package/app/components/content/pages/checkout.vue +118 -0
- package/app/components/content/pages/meeoviGlobal.vue +68 -0
- package/app/components/content/pages/pickup-locations.vue +238 -0
- package/app/components/content/pages/showcases.vue +90 -0
- package/app/components/content/pages/success.vue +60 -0
- package/app/components/marketing/add-brand.vue +54 -0
- package/app/components/marketing/add-incentive.vue +54 -0
- package/app/components/marketing/promotions/giftcards.vue +127 -0
- package/app/components/marketing/promotions/subscriptions.vue +134 -0
- package/app/components/marketing/update-incentive.vue +326 -0
- package/app/components/menus/lowernav.vue +78 -0
- package/app/components/partials/LocaleSelector.vue +24 -0
- package/app/components/partials/ShoppingCart.vue +128 -0
- package/app/components/partials/StripePayment.vue +149 -0
- package/app/components/partials/addToCartBtn.vue +40 -0
- package/app/components/partials/cartItem.vue +124 -0
- package/app/components/partials/checkoutButton.vue +44 -0
- package/app/components/partials/compareBtn.vue +68 -0
- package/app/components/partials/ratings.vue +13 -0
- package/app/components/partials/store/CurrencySelector.vue +133 -0
- package/app/components/partials/store/StoreSwitcher.vue +13 -0
- package/app/components/related/brandCard.vue +41 -0
- package/app/components/related/incentiveCard.vue +44 -0
- package/app/components/related/invoiceCard.vue +43 -0
- package/app/components/related/orderCard.vue +43 -0
- package/app/components/related/relatedproducts.vue +17 -0
- package/app/components/sales/CartPageContent/CartPageContent.vue +37 -0
- package/app/components/sales/CheckoutAddress/CheckoutAddress.vue +50 -0
- package/app/components/sales/CheckoutAddress/__tests__/CheckoutAddress.spec.ts +16 -0
- package/app/components/sales/CheckoutAddress/types.ts +15 -0
- package/app/components/sales/CheckoutPayment/CheckoutPayment.vue +68 -0
- package/app/components/sales/CheckoutPayment/__tests__/CheckoutPayment.spec.ts +14 -0
- package/app/components/sales/CheckoutPayment/types.ts +12 -0
- package/app/components/sales/OrderSummary/OrderSummary.vue +57 -0
- package/app/components/sales/OrderSummary/__tests__/ContactInformation.spec.ts +52 -0
- package/app/components/sales/OrderSummary/types.ts +5 -0
- package/app/components/sales/incentives.vue +247 -0
- package/app/components/sales/invoices.vue +107 -0
- package/app/components/sales/orders.vue +378 -0
- package/app/components/sales/shipments.vue +65 -0
- package/app/components/sales/transactions.vue +109 -0
- package/app/components/shop/add-shop.vue +54 -0
- package/app/components/shop/cart/cartItem.vue +182 -0
- package/app/components/shop/cart/checkout.vue +415 -0
- package/app/components/shop/checkout/StripeCardElement.vue +206 -0
- package/app/components/shop/checkout/StripeCheckout.vue +49 -0
- package/app/components/shop/checkout/addressBilling.vue +263 -0
- package/app/components/shop/checkout/addressShipping.vue +175 -0
- package/app/components/shop/checkout/cart/ProductItem.vue +56 -0
- package/app/components/shop/checkout/cart/PromotionItem.vue +53 -0
- package/app/composables/_types.ts +17 -0
- package/app/composables/adapters/abstract/cartAdapter.ts +0 -0
- package/app/composables/adapters/abstract/categoryAdapter.ts +0 -0
- package/app/composables/adapters/abstract/customerAdapter.ts +0 -0
- package/app/composables/adapters/abstract/inventoryAdapter.ts +0 -0
- package/app/composables/adapters/abstract/orderAdapter.ts +0 -0
- package/app/composables/adapters/abstract/productAdapter.ts +7 -0
- package/app/composables/cart/registry.ts +13 -0
- package/app/composables/cart/types.ts +18 -0
- package/app/composables/cart/useCart.ts +15 -0
- package/app/composables/config.ts +19 -0
- package/app/composables/defs/apiDefinitions.ts +55 -0
- package/app/composables/defs/extension.feature +40 -0
- package/app/composables/defs/extension.mocks.ts +39 -0
- package/app/composables/defs/extension.test.ts +280 -0
- package/app/composables/defs/extension.ts +236 -0
- package/app/composables/defs/index.ts +3 -0
- package/app/composables/defs/types.ts +136 -0
- package/app/composables/domain/cart.ts +0 -0
- package/app/composables/domain/category.ts +0 -0
- package/app/composables/domain/order.ts +0 -0
- package/app/composables/domain/price.ts +0 -0
- package/app/composables/domain/product.ts +8 -0
- package/app/composables/domain/reward.ts +0 -0
- package/app/composables/domain/transactions.ts +0 -0
- package/app/composables/helpers/contextualizedNormalizers.feature +14 -0
- package/app/composables/helpers/contextualizedNormalizers.test.ts +85 -0
- package/app/composables/helpers/contextualizedNormalizers.ts +20 -0
- package/app/composables/helpers/index.ts +1 -0
- package/app/composables/index.ts +5 -0
- package/app/composables/methods/auth.ts +83 -0
- package/app/composables/methods/cart.ts +119 -0
- package/app/composables/methods/category.ts +27 -0
- package/app/composables/methods/checkout.ts +54 -0
- package/app/composables/methods/customer.ts +52 -0
- package/app/composables/methods/helpers.ts +5 -0
- package/app/composables/methods/index.ts +75 -0
- package/app/composables/methods/order.ts +39 -0
- package/app/composables/methods/product.ts +95 -0
- package/app/composables/methods/settings.ts +16 -0
- package/app/composables/models/cart.ts +95 -0
- package/app/composables/models/category.ts +13 -0
- package/app/composables/models/checkout.ts +17 -0
- package/app/composables/models/customer.ts +16 -0
- package/app/composables/models/facets.ts +25 -0
- package/app/composables/models/index.ts +94 -0
- package/app/composables/models/order.ts +43 -0
- package/app/composables/models/product.ts +73 -0
- package/app/composables/models/shared.ts +75 -0
- package/app/composables/products/registry.ts +13 -0
- package/app/composables/products/types.ts +13 -0
- package/app/composables/products/useEvents.ts +0 -0
- package/app/composables/products/useGiftCards.ts +0 -0
- package/app/composables/products/useProducts.ts +12 -0
- package/app/composables/products/useSubscriptions.ts +0 -0
- package/app/composables/stores/cart.ts +218 -0
- package/app/composables/stores/cartStore.ts +300 -0
- package/app/composables/stores/checkout.ts +19 -0
- package/app/composables/stores/compare.ts +65 -0
- package/app/composables/stores/currency.js +29 -0
- package/app/composables/stores/digital-products.js +11 -0
- package/app/composables/stores/index.js +0 -0
- package/app/composables/stores/orders.ts +161 -0
- package/app/composables/stores/product.ts +26 -0
- package/app/composables/stores/productList.ts +0 -0
- package/app/composables/stores/productListInfo.ts +0 -0
- package/app/composables/stores/products.ts +112 -0
- package/app/composables/stores/recentlyViewedProducts.ts +0 -0
- package/app/composables/stores/review.ts +25 -0
- package/app/composables/stores/storeInPickUp.ts +22 -0
- package/app/composables/stores/user.ts +20 -0
- package/app/composables/stores/wishlist.ts +19 -0
- package/app/composables/types/Order.type.ts +181 -0
- package/app/composables/types/index.ts +285 -0
- package/app/composables/types/product.ts +14 -0
- package/app/composables/useBreakpoints/index.ts +1 -0
- package/app/composables/useBreakpoints/useBreakpoints.ts +28 -0
- package/app/composables/useCart/__tests__/useCart.spec.ts +11 -0
- package/app/composables/useCart/index.ts +1 -0
- package/app/composables/useCart/types.ts +17 -0
- package/app/composables/useCart/useCart.ts +46 -0
- package/app/composables/useCartShippingMethods/__tests__/useCartShippingMethods.spec.ts +11 -0
- package/app/composables/useCartShippingMethods/index.ts +1 -0
- package/app/composables/useCartShippingMethods/types.ts +17 -0
- package/app/composables/useCartShippingMethods/useCartShippingMethods.ts +47 -0
- package/app/composables/useContent/index.ts +1 -0
- package/app/composables/useContent/types.ts +44 -0
- package/app/composables/useContent/useContent.ts +45 -0
- package/app/composables/useCustomer/__tests__/useCustomer.spec.ts +25 -0
- package/app/composables/useCustomer/index.ts +2 -0
- package/app/composables/useCustomer/types.ts +17 -0
- package/app/composables/useCustomer/useCustomer.ts +40 -0
- package/app/composables/useCustomerAddress/__tests__/useCustomerAddress.spec.ts +11 -0
- package/app/composables/useCustomerAddress/index.ts +2 -0
- package/app/composables/useCustomerAddress/types.ts +17 -0
- package/app/composables/useCustomerAddress/useCustomerAddress.ts +55 -0
- package/app/composables/useCustomerOrder/__tests__/useCustomerOrder.spec.ts +11 -0
- package/app/composables/useCustomerOrder/adress.ts +10 -0
- package/app/composables/useCustomerOrder/index.ts +2 -0
- package/app/composables/useCustomerOrder/product.ts +37 -0
- package/app/composables/useCustomerOrder/types.ts +40 -0
- package/app/composables/useCustomerOrder/useCustomerOrder.ts +63 -0
- package/app/composables/useCustomerOrders/__tests__/useCustomerOrders.spec.ts +11 -0
- package/app/composables/useCustomerOrders/index.ts +2 -0
- package/app/composables/useCustomerOrders/types.ts +20 -0
- package/app/composables/useCustomerOrders/useCustomerOrders.ts +56 -0
- package/app/composables/useCustomerReturns/__tests__/useCustomerReturns.spec.ts +11 -0
- package/app/composables/useCustomerReturns/index.ts +2 -0
- package/app/composables/useCustomerReturns/types.ts +17 -0
- package/app/composables/useCustomerReturns/useCustomerReturns.ts +41 -0
- package/app/composables/useHandleError/index.ts +1 -0
- package/app/composables/useHandleError/types.ts +11 -0
- package/app/composables/useHandleError/useHandleError.ts +27 -0
- package/app/composables/usePageTitle.ts +16 -0
- package/app/composables/useProduct/index.ts +2 -0
- package/app/composables/useProduct/types.ts +17 -0
- package/app/composables/useProduct/useProduct.ts +42 -0
- package/app/composables/useProductAttribute/__tests__/useProduct.mock.ts +31 -0
- package/app/composables/useProductAttribute/__tests__/useProductAttribute.spec.ts +14 -0
- package/app/composables/useProductAttribute/index.ts +1 -0
- package/app/composables/useProductAttribute/useProductAttribute.ts +37 -0
- package/app/composables/useProductRecommended/__tests__/useProductRecommended.spec.ts +12 -0
- package/app/composables/useProductRecommended/index.ts +1 -0
- package/app/composables/useProductRecommended/types.ts +17 -0
- package/app/composables/useProductRecommended/useProductRecommended.ts +43 -0
- package/app/composables/useProductReviews/__tests__/productReviews.mock.ts +20 -0
- package/app/composables/useProductReviews/__tests__/useProductReviews.spec.ts +22 -0
- package/app/composables/useProductReviews/index.ts +2 -0
- package/app/composables/useProductReviews/types.ts +17 -0
- package/app/composables/useProductReviews/useProductReviews.ts +46 -0
- package/app/composables/useProducts/__tests__/useProducts.spec.ts +11 -0
- package/app/composables/useProducts/types.ts +17 -0
- package/app/composables/useProducts/useProducts.ts +41 -0
- package/app/composables/utils/countryList.ts +14 -0
- package/app/composables/utils/currency.js +56 -0
- package/app/composables/utils/glossary.ts +0 -0
- package/app/composables/utils/importExport.ts +0 -0
- package/app/composables/utils/index.js +0 -0
- package/app/composables/utils/print.ts +0 -0
- package/app/composables/utils/shopThemes.ts +0 -0
- package/app/composables/utils/statistics.ts +0 -0
- package/app/composables/utils/stock.ts +0 -0
- package/app/composables/utils/stripe.ts +16 -0
- package/app/composables/utils/taxation.ts +0 -0
- package/app/composables/utils/tellFriends.ts +0 -0
- package/app/composables/validationRules/index.ts +1 -0
- package/app/composables/validationRules/password.feature +67 -0
- package/app/composables/validationRules/password.test.ts +89 -0
- package/app/composables/validationRules/password.ts +25 -0
- package/app/composables/vendors/index.ts +0 -0
- package/app/composables/vendors/registry.ts +0 -0
- package/app/composables/vendors/useAffiliates.ts +0 -0
- package/app/composables/vendors/useCommission.ts +0 -0
- package/app/pages/brand/[...slug].vue +92 -0
- package/app/pages/brands.vue +90 -0
- package/app/pages/cart.vue +142 -0
- package/app/pages/compare.vue +166 -0
- package/app/pages/incentive/[...id].vue +66 -0
- package/app/pages/invoice/[id].vue +309 -0
- package/app/pages/order/[id].vue +327 -0
- package/app/pages/product/[...id].vue +309 -0
- package/app/pages/product/showcases/index.vue +86 -0
- package/app/pages/shipment/[...id].vue +176 -0
- package/app/pages/shop/[...slug].vue +164 -0
- package/app/pages/shops.vue +83 -0
- package/app/pages/subscription/[...id].vue +147 -0
- package/app/pages/transaction/[...id].vue +74 -0
- package/app/types/shims-imports.d.ts +13 -0
- package/app/utils/client.ts +26 -0
- package/app/utils/index.ts +53 -0
- package/app/utils/normalizer.ts +23 -0
- package/app/utils/normalizers/magento.ts +29 -0
- package/app/utils/normalizers/shopify.ts +29 -0
- package/dist/client.js +1 -1
- package/nuxt.config.ts +11 -0
- package/package.json +3 -17
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format a price amount according to the given currency
|
|
3
|
+
* @param {number} amount - The price amount to format
|
|
4
|
+
* @param {string} currency - The currency code (e.g., 'USD', 'EUR')
|
|
5
|
+
* @param {Object} exchangeRates - Object containing exchange rates
|
|
6
|
+
* @returns {string} Formatted price string
|
|
7
|
+
*/
|
|
8
|
+
export const formatPrice = (amount, currency, exchangeRates) => {
|
|
9
|
+
if (!amount || !currency) return ''
|
|
10
|
+
|
|
11
|
+
const rate = exchangeRates[currency] || 1
|
|
12
|
+
const convertedAmount = amount * rate
|
|
13
|
+
|
|
14
|
+
return new Intl.NumberFormat(undefined, {
|
|
15
|
+
style: 'currency',
|
|
16
|
+
currency: currency
|
|
17
|
+
}).format(convertedAmount)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Convert price from one currency to another
|
|
22
|
+
* @param {number} amount - The price amount to convert
|
|
23
|
+
* @param {string} fromCurrency - Source currency code
|
|
24
|
+
* @param {string} toCurrency - Target currency code
|
|
25
|
+
* @param {Object} exchangeRates - Object containing exchange rates
|
|
26
|
+
* @returns {number} Converted price amount
|
|
27
|
+
*/
|
|
28
|
+
export const convertPrice = (amount, fromCurrency, toCurrency, exchangeRates) => {
|
|
29
|
+
if (!amount || !fromCurrency || !toCurrency || !exchangeRates) return amount
|
|
30
|
+
|
|
31
|
+
const fromRate = exchangeRates[fromCurrency] || 1
|
|
32
|
+
const toRate = exchangeRates[toCurrency] || 1
|
|
33
|
+
|
|
34
|
+
return (amount * toRate) / fromRate
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get currency symbol for a currency code
|
|
39
|
+
* @param {string} code - Currency code
|
|
40
|
+
* @returns {string} Currency symbol
|
|
41
|
+
*/
|
|
42
|
+
export const getCurrencySymbol = (code) => {
|
|
43
|
+
const symbols = {
|
|
44
|
+
USD: '$',
|
|
45
|
+
EUR: '€',
|
|
46
|
+
GBP: '£',
|
|
47
|
+
JPY: '¥',
|
|
48
|
+
AUD: 'A$',
|
|
49
|
+
CAD: 'C$',
|
|
50
|
+
CHF: 'CHF',
|
|
51
|
+
CNY: '¥',
|
|
52
|
+
INR: '₹',
|
|
53
|
+
// Add more currency symbols as needed
|
|
54
|
+
}
|
|
55
|
+
return symbols[code] || code
|
|
56
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// utils/stripe.ts
|
|
2
|
+
import { loadStripe, type Stripe } from '@stripe/stripe-js';
|
|
3
|
+
|
|
4
|
+
let stripePromise: Promise<Stripe | null> | null = null;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns a Stripe instance (singleton per publishable key)
|
|
8
|
+
* @param {string} publishableKey - Your Stripe publishable key
|
|
9
|
+
* @returns {Promise<Stripe | null>}
|
|
10
|
+
*/
|
|
11
|
+
export function getStripe(publishableKey: string): Promise<Stripe | null> {
|
|
12
|
+
if (!stripePromise) {
|
|
13
|
+
stripePromise = loadStripe(publishableKey);
|
|
14
|
+
}
|
|
15
|
+
return stripePromise;
|
|
16
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./password";
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Feature: Password validation rule
|
|
2
|
+
|
|
3
|
+
Scenario Outline: New password can't be too easy (<newPassword>)
|
|
4
|
+
Given the <newPassword> as password
|
|
5
|
+
When the method is called
|
|
6
|
+
Then a false should be returned
|
|
7
|
+
|
|
8
|
+
Examples:
|
|
9
|
+
|
|
10
|
+
| newPassword |
|
|
11
|
+
| 12345 |
|
|
12
|
+
| password |
|
|
13
|
+
| password1 |
|
|
14
|
+
| Password1 |
|
|
15
|
+
| Password@ |
|
|
16
|
+
| Password123567890 |
|
|
17
|
+
|
|
18
|
+
Scenario Outline: New password must be complex enough (<newPassword>)
|
|
19
|
+
Given the <newPassword> as password
|
|
20
|
+
When the method is called
|
|
21
|
+
Then a true should be returned
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
|
|
25
|
+
| newPassword |
|
|
26
|
+
| Password1!3 |
|
|
27
|
+
| L0ngEnough$ |
|
|
28
|
+
| L0ngEnough@ |
|
|
29
|
+
| L0ngEnough# |
|
|
30
|
+
| L0ngEnough% |
|
|
31
|
+
| L0ngEnough^ |
|
|
32
|
+
| L0ngEnough* |
|
|
33
|
+
| L0ngEnough( |
|
|
34
|
+
| L0ngEnough) |
|
|
35
|
+
| L0ngEnough: |
|
|
36
|
+
| L0ngEnough; |
|
|
37
|
+
| L0ngEnough, |
|
|
38
|
+
| L0ngEnough. |
|
|
39
|
+
|
|
40
|
+
Scenario Outline: New password can't have some special signs (<newPassword>)
|
|
41
|
+
Given the <newPassword> as password
|
|
42
|
+
When the method is called
|
|
43
|
+
Then a false should be returned
|
|
44
|
+
|
|
45
|
+
Examples:
|
|
46
|
+
|
|
47
|
+
| newPassword |
|
|
48
|
+
| L0ngEnough& |
|
|
49
|
+
| L0ngEnough[ |
|
|
50
|
+
| L0ngEnough] |
|
|
51
|
+
| L0ngEnough" |
|
|
52
|
+
| L0ngEnough' |
|
|
53
|
+
| L0ngEnough/ |
|
|
54
|
+
| L0ngEnough> |
|
|
55
|
+
| L0ngEnough< |
|
|
56
|
+
|
|
57
|
+
Scenario: New password match with confirmation
|
|
58
|
+
Given the password is "Password1!"
|
|
59
|
+
And the confirmation is "Password1!"
|
|
60
|
+
When the method is called
|
|
61
|
+
Then a true should be returned
|
|
62
|
+
|
|
63
|
+
Scenario: New password mismatch with confirmation
|
|
64
|
+
Given the password is "Password1!"
|
|
65
|
+
And the confirmation is "Password1"
|
|
66
|
+
When the method is called
|
|
67
|
+
Then a false should be returned
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { expect } from "vitest";
|
|
2
|
+
import type { DefineStepFunction } from "jest-cucumber";
|
|
3
|
+
import { defineFeature, loadFeature } from "jest-cucumber";
|
|
4
|
+
import { validatePassword } from "./password";
|
|
5
|
+
|
|
6
|
+
const feature = loadFeature("./password.feature", { loadRelativePath: true });
|
|
7
|
+
|
|
8
|
+
defineFeature(feature, (test) => {
|
|
9
|
+
let password: string;
|
|
10
|
+
let confirmation: string;
|
|
11
|
+
let output: boolean;
|
|
12
|
+
|
|
13
|
+
function whenTheMethodIsCalled(when: DefineStepFunction) {
|
|
14
|
+
when("the method is called", () => {
|
|
15
|
+
output = validatePassword(password, confirmation);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
test("New password can't be too easy (<newPassword>)", ({ given, when, then }) => {
|
|
20
|
+
given(/^the (.*) as password$/, (givenPassword) => {
|
|
21
|
+
password = givenPassword;
|
|
22
|
+
confirmation = givenPassword;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
whenTheMethodIsCalled(when);
|
|
26
|
+
|
|
27
|
+
then("a false should be returned", () => {
|
|
28
|
+
expect(output).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("New password must be complex enough (<newPassword>)", ({ given, when, then }) => {
|
|
33
|
+
given(/^the (.*) as password$/, (givenPassword) => {
|
|
34
|
+
password = givenPassword;
|
|
35
|
+
confirmation = givenPassword;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
whenTheMethodIsCalled(when);
|
|
39
|
+
|
|
40
|
+
then("a true should be returned", () => {
|
|
41
|
+
expect(output).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("New password can't have some special signs (<newPassword>)", ({ given, when, then }) => {
|
|
46
|
+
given(/^the (.*) as password$/, (givenPassword) => {
|
|
47
|
+
password = givenPassword;
|
|
48
|
+
confirmation = givenPassword;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
whenTheMethodIsCalled(when);
|
|
52
|
+
|
|
53
|
+
then("a false should be returned", () => {
|
|
54
|
+
expect(output).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("New password match with confirmation", ({ given, and, when, then }) => {
|
|
59
|
+
given(/^the password is (.*)$/, (givenPassword) => {
|
|
60
|
+
password = givenPassword;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
and(/^the confirmation is (.*)$/, (givenConfirmation) => {
|
|
64
|
+
confirmation = givenConfirmation;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
whenTheMethodIsCalled(when);
|
|
68
|
+
|
|
69
|
+
then("a true should be returned", () => {
|
|
70
|
+
expect(output).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("New password mismatch with confirmation", ({ given, and, when, then }) => {
|
|
75
|
+
given(/^the password is (.*)$/, (givenPassword) => {
|
|
76
|
+
password = givenPassword;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
and(/^the confirmation is (.*)$/, (givenConfirmation) => {
|
|
80
|
+
confirmation = givenConfirmation;
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
whenTheMethodIsCalled(when);
|
|
84
|
+
|
|
85
|
+
then("a false should be returned", () => {
|
|
86
|
+
expect(output).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* eslint-disable sonarjs/prefer-single-boolean-return */
|
|
2
|
+
/* eslint-disable max-statements */
|
|
3
|
+
export function validatePassword(firstInput: string, confirmationInput: string): boolean {
|
|
4
|
+
if (firstInput !== confirmationInput) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (firstInput.length < 8) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (/[A-Z]+/.test(firstInput) === false) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (/\d+/.test(firstInput) === false) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (/[!#$%()*,.:;@^]+/.test(firstInput) === false) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="accountPage" v-if="brand">
|
|
3
|
+
<section data-bs-version="5.1" class="info3 cid-tuzqZ1PJf1" id="info3-39"
|
|
4
|
+
:style="`background-image: url(${$directus.url}/assets/${brand.image?.filename_disk});`">
|
|
5
|
+
<div class="mbr-overlay" style="opacity: 0.6; background-color: rgb(68, 121, 217);">
|
|
6
|
+
</div>
|
|
7
|
+
<div class="container">
|
|
8
|
+
<div class="row justify-content-center">
|
|
9
|
+
<div class="card col-12 col-lg-10">
|
|
10
|
+
<div class="card-wrapper">
|
|
11
|
+
<div class="card-box align-center">
|
|
12
|
+
<h4 class="card-title mbr-fonts-style align-center mb-4 display-1">
|
|
13
|
+
<strong>{{ brand.name }}</strong>
|
|
14
|
+
</h4>
|
|
15
|
+
<p class="mbr-text mbr-fonts-style mb-4 display-7">{{ brand.code }}</p>
|
|
16
|
+
<p class="mbr-text mbr-fonts-style mb-4 display-7">{{ brand.description }}</p>
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</section>
|
|
24
|
+
<!--Brand Products-->
|
|
25
|
+
<v-row style="padding: 10px;">
|
|
26
|
+
<v-col cols="3" v-for="brand in brand?.shorts" :key="brand.id">
|
|
27
|
+
<shorts :short="brand?.shorts_id" />
|
|
28
|
+
</v-col>
|
|
29
|
+
</v-row>
|
|
30
|
+
|
|
31
|
+
<!--Brand Products-->
|
|
32
|
+
<v-row style="padding: 10px;">
|
|
33
|
+
<v-col cols="3" v-for="brand in brand?.products" :key="brand.id">
|
|
34
|
+
<productCard :product="brand?.products_id" />
|
|
35
|
+
</v-col>
|
|
36
|
+
</v-row>
|
|
37
|
+
|
|
38
|
+
<relatedbrands />
|
|
39
|
+
</div>
|
|
40
|
+
<div v-else>
|
|
41
|
+
Loading brand...
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup>
|
|
46
|
+
import shorts from '#social/app/components/features/vibeSections/shorts.vue'
|
|
47
|
+
import productCard from '@/components/catalog/product/productCard.vue'
|
|
48
|
+
import relatedbrands from '@/components/catalog/product/relatedbrands.vue'
|
|
49
|
+
import {
|
|
50
|
+
useRuntimeConfig
|
|
51
|
+
} from '#imports';
|
|
52
|
+
|
|
53
|
+
const route = useRoute();
|
|
54
|
+
const {
|
|
55
|
+
$directus,
|
|
56
|
+
$readItem,
|
|
57
|
+
$readItems
|
|
58
|
+
} = useNuxtApp()
|
|
59
|
+
|
|
60
|
+
const slug = computed(() => {
|
|
61
|
+
const s = route.params.slug
|
|
62
|
+
return Array.isArray(s) ? s[0] : s
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const {
|
|
66
|
+
data: brandRaw
|
|
67
|
+
} = await useAsyncData('brand', () => {
|
|
68
|
+
return $directus.request(
|
|
69
|
+
$readItems('brands', {
|
|
70
|
+
fields: [
|
|
71
|
+
'*',
|
|
72
|
+
'products.products_id.*',
|
|
73
|
+
'products.products_id.image.*',
|
|
74
|
+
'shorts.shorts_id.*',
|
|
75
|
+
'image.*'
|
|
76
|
+
],
|
|
77
|
+
filter: {
|
|
78
|
+
slug: {
|
|
79
|
+
_eq: slug.value
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
limit: 1
|
|
83
|
+
})
|
|
84
|
+
)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const brand = computed(() => brandRaw.value?.[0] || null)
|
|
88
|
+
|
|
89
|
+
useHead({
|
|
90
|
+
title: computed(() => brand.value?.name || 'Brand Page')
|
|
91
|
+
})
|
|
92
|
+
</script>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="contentPage">
|
|
3
|
+
<v-card elevation="0">
|
|
4
|
+
<v-toolbar :title="brandbar?.name" color="green"></v-toolbar>
|
|
5
|
+
<v-tabs v-model="tab" bg-color="green">
|
|
6
|
+
<div v-for="(menu, index) in brandbar?.menus" :key="index">
|
|
7
|
+
<v-tab :value="menu?.value">{{ menu?.name }}</v-tab>
|
|
8
|
+
</div>
|
|
9
|
+
</v-tabs>
|
|
10
|
+
|
|
11
|
+
<v-card-text>
|
|
12
|
+
<v-tabs-window v-model="tab">
|
|
13
|
+
<v-tabs-window-item value="one">
|
|
14
|
+
<v-row>
|
|
15
|
+
<v-col cols="4" v-for="brand in brands" :key="brand.brand_id">
|
|
16
|
+
<brand :brand="brand" />
|
|
17
|
+
</v-col>
|
|
18
|
+
</v-row>
|
|
19
|
+
</v-tabs-window-item>
|
|
20
|
+
|
|
21
|
+
<v-tabs-window-item value="two">
|
|
22
|
+
<v-row>
|
|
23
|
+
<v-col cols="4" v-for="brand in meebrands" :key="brand.brand_id">
|
|
24
|
+
<brand :brand="brand" />
|
|
25
|
+
</v-col>
|
|
26
|
+
</v-row>
|
|
27
|
+
</v-tabs-window-item>
|
|
28
|
+
|
|
29
|
+
<v-tabs-window-item value="three">
|
|
30
|
+
<v-row>
|
|
31
|
+
<v-col cols="4" v-for="brand in brands" :key="brand.brand_id">
|
|
32
|
+
<brand :brand="brand" />
|
|
33
|
+
</v-col>
|
|
34
|
+
</v-row>
|
|
35
|
+
</v-tabs-window-item>
|
|
36
|
+
</v-tabs-window>
|
|
37
|
+
</v-card-text>
|
|
38
|
+
</v-card>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<script setup>
|
|
43
|
+
import {
|
|
44
|
+
ref,
|
|
45
|
+
onMounted
|
|
46
|
+
} from 'vue'
|
|
47
|
+
import brand from '~/app/components/catalog/product/brands.vue'
|
|
48
|
+
|
|
49
|
+
const tab = ref(null)
|
|
50
|
+
const {
|
|
51
|
+
$directus,
|
|
52
|
+
$readItems,
|
|
53
|
+
$readItem
|
|
54
|
+
} = useNuxtApp()
|
|
55
|
+
|
|
56
|
+
const {
|
|
57
|
+
data: brands
|
|
58
|
+
} = await useAsyncData('brands', () => {
|
|
59
|
+
return $directus.request($readItems('brands', {
|
|
60
|
+
fields: ['*', {
|
|
61
|
+
'*': ['*']
|
|
62
|
+
}]
|
|
63
|
+
}))
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
data: meebrands
|
|
68
|
+
} = await useAsyncData('meebrands', () => {
|
|
69
|
+
return $directus.request($readItems('brands', {
|
|
70
|
+
filter: {
|
|
71
|
+
code: {
|
|
72
|
+
_eq: 'Mee'
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
fields: ['*', {
|
|
76
|
+
'*': ['*']
|
|
77
|
+
}]
|
|
78
|
+
}))
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const {
|
|
82
|
+
data: brandbar
|
|
83
|
+
} = await useAsyncData('brandbar', () => {
|
|
84
|
+
return $directus.request($readItem('navigation', '40', {
|
|
85
|
+
fields: ['*', {
|
|
86
|
+
'*': ['*']
|
|
87
|
+
}]
|
|
88
|
+
}))
|
|
89
|
+
})
|
|
90
|
+
</script>
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
<!-- pages/cart.vue -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="cartPage">
|
|
4
|
+
<h2>Shopping Cart</h2>
|
|
5
|
+
|
|
6
|
+
<div v-if="cart.items.length === 0" class="empty-cart">
|
|
7
|
+
Your cart is empty
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div v-else>
|
|
11
|
+
<div v-for="item in cart.items" :key="item.id" class="cart-item">
|
|
12
|
+
<div class="item-details">
|
|
13
|
+
<h3>{{ item.name }}</h3>
|
|
14
|
+
<p>Price: ${{ item.price }}</p>
|
|
15
|
+
<p>Quantity: {{ item.quantity }}</p>
|
|
16
|
+
</div>
|
|
17
|
+
<v-btn @click="cart.removeItem(item.id)" color="error">
|
|
18
|
+
Remove
|
|
19
|
+
</v-btn>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="cart-total">
|
|
23
|
+
<h3>Total: ${{ cart.total }}</h3>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<!-- Shipping selection -->
|
|
27
|
+
<div class="cart-shipping my-4">
|
|
28
|
+
<ShippingOptions v-model="selectedShipping" />
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="cart-actions mt-4">
|
|
32
|
+
<v-btn
|
|
33
|
+
color="primary"
|
|
34
|
+
:disabled="cart.items.length === 0 || loading"
|
|
35
|
+
@click="startCheckout"
|
|
36
|
+
>
|
|
37
|
+
<span v-if="!loading">Checkout</span>
|
|
38
|
+
<span v-else>Preparing...</span>
|
|
39
|
+
</v-btn>
|
|
40
|
+
|
|
41
|
+
<PayPalButtons
|
|
42
|
+
@payment-success="handlePaymentSuccess"
|
|
43
|
+
@payment-error="handlePaymentError"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<script setup>
|
|
51
|
+
import { useCartStore } from '~/stores/cart'
|
|
52
|
+
|
|
53
|
+
import ShippingOptions from '../components/catalog/product/shippingOptions.vue'
|
|
54
|
+
import { ref, computed } from 'vue'
|
|
55
|
+
|
|
56
|
+
const cart = useCartStore()
|
|
57
|
+
const loading = ref(false)
|
|
58
|
+
|
|
59
|
+
const selectedShipping = computed({
|
|
60
|
+
get: () => cart.cart?.shipping_method_id ?? cart.cart?.shipping_method ?? null,
|
|
61
|
+
set: async (val) => {
|
|
62
|
+
try {
|
|
63
|
+
// Let the component/composable persist to the cart store; call store as a fallback
|
|
64
|
+
if (cart && cart.setShippingOption) {
|
|
65
|
+
await cart.setShippingOption({ id: val })
|
|
66
|
+
}
|
|
67
|
+
} catch (e) {
|
|
68
|
+
// eslint-disable-next-line no-console
|
|
69
|
+
console.warn('Failed to set shipping from cart page', e)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const handlePaymentSuccess = (order) => {
|
|
75
|
+
console.log('Payment successful:', order)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const handlePaymentError = (error) => {
|
|
79
|
+
console.error('Payment failed:', error)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const startCheckout = async () => {
|
|
83
|
+
if (!cart || !cart.createCheckoutSession) return
|
|
84
|
+
try {
|
|
85
|
+
loading.value = true
|
|
86
|
+
const data = await cart.createCheckoutSession(cart.cart?.id)
|
|
87
|
+
const url = data?.url || (data?.id ? `https://checkout.stripe.com/pay/${data.id}` : null)
|
|
88
|
+
if (url) {
|
|
89
|
+
window.location.href = url
|
|
90
|
+
} else if (data && data.id) {
|
|
91
|
+
// fallback: use injected Stripe instance from plugin if available
|
|
92
|
+
const nuxtApp = useNuxtApp()
|
|
93
|
+
const injectedStripe = nuxtApp?.$stripe || null
|
|
94
|
+
if (injectedStripe && typeof injectedStripe.redirectToCheckout === 'function') {
|
|
95
|
+
await injectedStripe.redirectToCheckout({ sessionId: data.id })
|
|
96
|
+
} else if (window && window.Stripe) {
|
|
97
|
+
// last-resort: use global Stripe if present
|
|
98
|
+
const publishable = (useRuntimeConfig() || {}).public?.stripe?.publishableKey || null
|
|
99
|
+
if (publishable) {
|
|
100
|
+
const stripe = window.Stripe(publishable)
|
|
101
|
+
await stripe.redirectToCheckout({ sessionId: data.id })
|
|
102
|
+
} else {
|
|
103
|
+
console.warn('No Stripe publishable key available for client-side redirect')
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
console.warn('No client Stripe instance available for redirect')
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
console.warn('No checkout url returned from server')
|
|
110
|
+
}
|
|
111
|
+
} catch (e) {
|
|
112
|
+
console.error('Failed to start checkout', e)
|
|
113
|
+
} finally {
|
|
114
|
+
loading.value = false
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<style scoped>
|
|
120
|
+
.cartPage {
|
|
121
|
+
padding: 20px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.cart-item {
|
|
125
|
+
display: flex;
|
|
126
|
+
justify-content: space-between;
|
|
127
|
+
align-items: center;
|
|
128
|
+
padding: 15px;
|
|
129
|
+
border-bottom: 1px solid #eee;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.cart-total {
|
|
133
|
+
margin-top: 20px;
|
|
134
|
+
text-align: right;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.empty-cart {
|
|
138
|
+
text-align: center;
|
|
139
|
+
padding: 50px;
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
142
|
+
|