@ecomplus/widget-product 0.5.1 → 1.0.0-beta.100

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 (48) hide show
  1. package/CHANGELOG.md +822 -11
  2. package/README.md +1 -1
  3. package/cms.config.js +67 -0
  4. package/dist/public/widget-product.1.min.js +5 -0
  5. package/dist/public/widget-product.1.min.js.map +1 -0
  6. package/dist/public/widget-product.2.min.js +5 -0
  7. package/dist/public/widget-product.2.min.js.map +1 -0
  8. package/dist/public/widget-product.var.min.js +1 -1
  9. package/dist/public/widget-product.var.min.js.map +1 -1
  10. package/dist/widget-product.1.min.js +5 -0
  11. package/dist/widget-product.1.min.js.map +1 -0
  12. package/dist/widget-product.2.min.js +5 -0
  13. package/dist/widget-product.2.min.js.map +1 -0
  14. package/dist/widget-product.min.js +1 -1
  15. package/dist/widget-product.min.js.map +1 -1
  16. package/package.json +6 -10
  17. package/src/index.js +68 -11
  18. package/webpack.config.js +1 -0
  19. package/__tests__/index.js +0 -10
  20. package/src/components/EcGallery.vue +0 -3
  21. package/src/components/EcImage.vue +0 -3
  22. package/src/components/EcPrices.vue +0 -3
  23. package/src/components/EcProduct.vue +0 -3
  24. package/src/components/EcShipping.vue +0 -3
  25. package/src/components/EcShippingLine.vue +0 -2
  26. package/src/components/EcVariations.vue +0 -3
  27. package/src/components/html/EcGallery.html +0 -51
  28. package/src/components/html/EcImage.html +0 -29
  29. package/src/components/html/EcPrices.html +0 -46
  30. package/src/components/html/EcProduct.html +0 -113
  31. package/src/components/html/EcShipping.html +0 -71
  32. package/src/components/html/EcShippingLine.html +0 -14
  33. package/src/components/html/EcVariations.html +0 -19
  34. package/src/components/js/EcGallery.js +0 -86
  35. package/src/components/js/EcImage.js +0 -62
  36. package/src/components/js/EcPrices.js +0 -145
  37. package/src/components/js/EcProduct.js +0 -230
  38. package/src/components/js/EcShipping.js +0 -180
  39. package/src/components/js/EcShippingLine.js +0 -39
  40. package/src/components/js/EcVariations.js +0 -103
  41. package/src/components/scss/EcGallery.scss +0 -117
  42. package/src/components/scss/EcImage.scss +0 -4
  43. package/src/components/scss/EcPrices.scss +0 -40
  44. package/src/components/scss/EcProduct.scss +0 -26
  45. package/src/components/scss/EcShipping.scss +0 -20
  46. package/src/components/scss/EcVariations.scss +0 -49
  47. package/src/lib/dictionary.js +0 -75
  48. package/src/lib/get-scoped-slots.js +0 -27
@@ -1,145 +0,0 @@
1
- import {
2
- $ecomConfig,
3
- price as getPrice,
4
- onPromotion as checkOnPromotion,
5
- formatMoney
6
- } from '@ecomplus/utils'
7
- import dictionary from './../../lib/dictionary'
8
-
9
- const getPriceWithDiscount = (price, discount) => {
10
- const { type, value } = discount
11
- if (value) {
12
- if (type === 'percentage') {
13
- return price * (100 - value) / 100
14
- } else {
15
- return price - value
16
- }
17
- }
18
- }
19
-
20
- export default {
21
- name: 'EcPrices',
22
-
23
- props: {
24
- lang: {
25
- type: String,
26
- default: $ecomConfig.get('lang')
27
- },
28
- product: {
29
- type: Object,
30
- required: true
31
- },
32
- literal: {
33
- type: Boolean
34
- },
35
- big: {
36
- type: Boolean
37
- },
38
- installmentsOption: {
39
- type: Object
40
- },
41
- discountOption: {
42
- type: Object
43
- },
44
- discountText: {
45
- type: [String, Boolean],
46
- default: ''
47
- }
48
- },
49
-
50
- data () {
51
- return {
52
- interestFreeInstallments: 0,
53
- discount: {
54
- type: null,
55
- value: 0
56
- },
57
- extraDiscount: {
58
- type: null,
59
- value: 0
60
- },
61
- discountLabel: this.discountText
62
- }
63
- },
64
-
65
- methods: {
66
- dictionary,
67
- formatMoney,
68
-
69
- updateInstallments (installments) {
70
- if (installments && !installments.monthly_interest) {
71
- const minInstallment = installments.min_installment || 5
72
- const installmentsNumber = parseInt(this.price / minInstallment, 10)
73
- this.interestFreeInstallments = Math.min(installmentsNumber, installments.max_number)
74
- }
75
- },
76
-
77
- updateDiscount (discount) {
78
- if (discount && (!discount.min_amount || discount.min_amount <= this.price)) {
79
- this.discount = discount
80
- if (!this.discountText && this.discountText !== false && discount.label) {
81
- this.discountLabel = `via ${discount.label}`
82
- }
83
- }
84
- }
85
- },
86
-
87
- computed: {
88
- price () {
89
- const price = getPrice(this.product)
90
- if (this.extraDiscount.value) {
91
- return getPriceWithDiscount(price, this.extraDiscount)
92
- }
93
- return price
94
- },
95
-
96
- comparePrice () {
97
- if (checkOnPromotion(this.product)) {
98
- return this.product.base_price
99
- } else if (this.extraDiscount.value) {
100
- return getPrice(this.product)
101
- }
102
- },
103
-
104
- priceWithDiscount () {
105
- return getPriceWithDiscount(this.price, this.discount)
106
- }
107
- },
108
-
109
- created () {
110
- if (!this.installmentsOption && !this.discountOption) {
111
- const { storefront } = window
112
- if (storefront) {
113
- const getPaymentInfo = () => {
114
- const paymentInfo = storefront.info && storefront.info.list_payments
115
- if (paymentInfo) {
116
- this.updateInstallments(paymentInfo.installments_option)
117
- this.updateDiscount(paymentInfo.discount_option)
118
- return Object.keys(paymentInfo).length > 0
119
- }
120
- return false
121
- }
122
- if (!getPaymentInfo()) {
123
- storefront.on('info:list_payments', getPaymentInfo)
124
- }
125
- const getExtraDiscount = () => {
126
- const discountCampaign = storefront.info && storefront.info.apply_discount
127
- if (discountCampaign) {
128
- const discount = discountCampaign.available_extra_discount
129
- if (discount) {
130
- this.extraDiscount = discount
131
- }
132
- return Object.keys(discountCampaign).length > 0
133
- }
134
- return false
135
- }
136
- if (!getExtraDiscount()) {
137
- storefront.on('info:apply_discount', getExtraDiscount)
138
- }
139
- }
140
- } else {
141
- this.updateInstallments(this.installmentsOption)
142
- this.updateDiscount(this.discountOption)
143
- }
144
- }
145
- }
@@ -1,230 +0,0 @@
1
- import {
2
- $ecomConfig,
3
- name,
4
- inStock,
5
- onPromotion,
6
- price,
7
- variationsGrids,
8
- specValueByText
9
- } from '@ecomplus/utils'
10
-
11
- import { store } from '@ecomplus/client'
12
- import ecomCart from '@ecomplus/shopping-cart'
13
- import EcPrices from './../EcPrices.vue'
14
- import EcVariations from './../EcVariations.vue'
15
- import EcGallery from './../EcGallery.vue'
16
- import EcShipping from './../EcShipping.vue'
17
- import dictionary from './../../lib/dictionary'
18
-
19
- const { storefront } = window
20
- const getContextBody = () => storefront
21
- ? storefront.context && storefront.context.body
22
- : {}
23
- const getContextId = () => getContextBody()._id
24
-
25
- export default {
26
- name: 'EcProduct',
27
-
28
- components: {
29
- EcPrices,
30
- EcGallery,
31
- EcVariations,
32
- EcShipping
33
- },
34
-
35
- props: {
36
- lang: {
37
- type: String,
38
- default: $ecomConfig.get('lang')
39
- },
40
- storeId: {
41
- type: Number,
42
- default: $ecomConfig.get('store_id')
43
- },
44
- productId: {
45
- type: String,
46
- default: getContextId()
47
- },
48
- product: Object,
49
- buyText: String,
50
- canAddToCart: {
51
- type: Boolean,
52
- default: true
53
- },
54
- maxQuantityWarn: {
55
- type: Number,
56
- default: 13
57
- }
58
- },
59
-
60
- data () {
61
- return {
62
- body: {},
63
- selectedVariationId: null,
64
- currentGalleyImg: 1,
65
- hasClickedBuy: false
66
- }
67
- },
68
-
69
- computed: {
70
- selectedVariation () {
71
- return this.selectedVariationId
72
- ? this.body.variations.find(({ _id }) => _id === this.selectedVariationId)
73
- : {}
74
- },
75
-
76
- name () {
77
- return this.selectedVariation.name || name(this.body)
78
- },
79
-
80
- productQuantity () {
81
- if (this.selectedVariation.quantity) {
82
- return this.selectedVariation.quantity
83
- } else if (this.body.quantity) {
84
- return this.body.quantity
85
- }
86
- },
87
-
88
- almostDoneQuantity () {
89
- return (this.productQuantity > 0 && this.productQuantity < this.maxQuantityWarn) ? this.productQuantity : false
90
- },
91
-
92
- strBuy () {
93
- return this.buyText || this.dictionary('buy')
94
- },
95
-
96
- discount () {
97
- const { body } = this
98
- return onPromotion(body)
99
- ? Math.round(((body.base_price - price(body)) * 100) / body.base_price)
100
- : 0
101
- },
102
-
103
- hasVariations () {
104
- return this.body.variations && this.body.variations.length
105
- },
106
-
107
- photoswipeImages () {
108
- const { name, pictures } = this.body
109
- const psImages = []
110
- if (pictures) {
111
- pictures.forEach(({ zoom }) => {
112
- if (zoom && zoom.size) {
113
- const sizes = zoom.size.split('x')
114
- if (sizes.length === 2) {
115
- psImages.push({
116
- src: zoom.url,
117
- title: name,
118
- w: parseInt(sizes[0], 10),
119
- h: parseInt(sizes[1], 10)
120
- })
121
- }
122
- }
123
- })
124
- }
125
- return psImages
126
- }
127
- },
128
-
129
- methods: {
130
- dictionary,
131
- inStock,
132
- variationsGrids,
133
- specValueByText,
134
-
135
- setBody (data) {
136
- this.body = data
137
- this.$emit('update:product', data)
138
- },
139
-
140
- fetchProduct (isRetry = false) {
141
- const vm = this
142
- const { storeId } = vm
143
- store({
144
- url: `/products/${vm.productId}.json`,
145
- storeId,
146
- axiosConfig: {
147
- timeout: isRetry ? 2500 : 6000
148
- }
149
- })
150
- .then(({ data }) => {
151
- this.setBody(data)
152
- if (getContextId() === vm.productId) {
153
- storefront.context.body = data
154
- }
155
- })
156
- .catch(err => {
157
- console.error(err)
158
- const { response } = err
159
- if (!response || !(response.status >= 400 && response.status < 500)) {
160
- if (!isRetry) {
161
- this.fetchProduct(true)
162
- } else {
163
- this.setBody(getContextBody())
164
- if (!this.body.name || !this.body.price || !this.body.pictures) {
165
- const errorMsg = vm.lang === 'pt_br'
166
- ? 'Não foi possível carregar informações do produto, por favor verifique sua conexão'
167
- : 'Unable to load product information, please check your internet connection'
168
- vm.$bvToast.toast(errorMsg, {
169
- title: 'Offline',
170
- variant: 'danger',
171
- noAutoHide: true,
172
- solid: true
173
- })
174
- }
175
- }
176
- }
177
- })
178
- },
179
-
180
- openPhotoswipe ({ index }) {
181
- if (storefront && typeof storefront.photoswipe === 'function') {
182
- storefront.photoswipe(this.photoswipeImages, index)
183
- }
184
- },
185
-
186
- buy () {
187
- this.hasClickedBuy = true
188
- const product = Object.assign({}, this.body)
189
- delete product.body_html
190
- delete product.body_text
191
- delete product.specifications
192
- let variationId
193
- if (this.hasVariations) {
194
- if (this.selectedVariationId) {
195
- variationId = this.selectedVariationId
196
- } else {
197
- return
198
- }
199
- }
200
- this.$emit('buy', { product, variationId })
201
- if (this.canAddToCart) {
202
- ecomCart.addProduct(product, variationId)
203
- }
204
- }
205
- },
206
-
207
- created () {
208
- if (this.product) {
209
- this.body = this.product
210
- } else {
211
- this.fetchProduct()
212
- }
213
- },
214
-
215
- watch: {
216
- selectedVariationId (id) {
217
- if (id) {
218
- if (this.hasClickedBuy) {
219
- this.hasClickedBuy = false
220
- }
221
- if (this.selectedVariation.picture_id) {
222
- const pictureIndex = this.body.pictures.findIndex(({ _id }) => {
223
- return _id === this.selectedVariation.picture_id
224
- })
225
- this.currentGalleyImg = pictureIndex + 1
226
- }
227
- }
228
- }
229
- }
230
- }
@@ -1,180 +0,0 @@
1
- import { $ecomConfig, price, formatMoney } from '@ecomplus/utils'
2
- import { modules } from '@ecomplus/client'
3
- import EcShippingLine from './../EcShippingLine.vue'
4
- import CleaveInput from 'vue-cleave-component'
5
- import dictionary from './../../lib/dictionary'
6
-
7
- const { localStorage } = window
8
- const zipStorageKey = 'ec-shipping-zip'
9
-
10
- const reduceItemBody = itemOrProduct => {
11
- const shippedItem = {}
12
- ;[
13
- 'product_id',
14
- 'variation_id',
15
- 'sku',
16
- 'name',
17
- 'quantity',
18
- 'currency_id',
19
- 'currency_symbol',
20
- 'price',
21
- 'final_price',
22
- 'dimensions',
23
- 'weight'
24
- ].forEach(field => {
25
- if (itemOrProduct[field] !== undefined) {
26
- shippedItem[field] = itemOrProduct[field]
27
- }
28
- })
29
- return shippedItem
30
- }
31
-
32
- export default {
33
- name: 'EcShipping',
34
-
35
- components: {
36
- EcShippingLine,
37
- CleaveInput
38
- },
39
-
40
- props: {
41
- lang: {
42
- type: String,
43
- default: $ecomConfig.get('lang')
44
- },
45
- countryCode: {
46
- type: String,
47
- default: $ecomConfig.get('country_code')
48
- },
49
- storeId: {
50
- type: Number,
51
- default: $ecomConfig.get('store_id')
52
- },
53
- zipInput: {
54
- type: Boolean,
55
- default: true
56
- },
57
- zipCode: {
58
- type: String
59
- },
60
- selectServices: {
61
- type: Boolean
62
- },
63
- shippedItems: {
64
- type: Array,
65
- default: () => []
66
- },
67
- shippingResult: {
68
- type: Array,
69
- default: () => []
70
- },
71
- shippingData: {
72
- type: Object,
73
- default: () => ({})
74
- }
75
- },
76
-
77
- data () {
78
- return {
79
- zipCodeValue: this.zipCode,
80
- shippingServices: [],
81
- selectedService: null,
82
- waiting: false
83
- }
84
- },
85
-
86
- methods: {
87
- dictionary,
88
- formatMoney,
89
-
90
- updateZipCode () {
91
- this.$emit('update:zipCode', this.zipCodeValue)
92
- },
93
-
94
- parseShippingOptions (shippingResult = [], isRetry) {
95
- this.shippingServices = []
96
- let canRetry
97
- if (shippingResult.length) {
98
- shippingResult.forEach(appResult => {
99
- const { validated, error, response } = appResult
100
- if (validated && !error) {
101
- response.shipping_services.forEach(service => {
102
- this.shippingServices.push({
103
- app_id: appResult.app_id,
104
- ...service
105
- })
106
- })
107
- } else if (isRetry !== true && (!response || !response.error)) {
108
- canRetry = true
109
- }
110
- })
111
- if (!this.shippingServices.length) {
112
- if (canRetry) {
113
- this.fetchShippingServices(true)
114
- }
115
- } else {
116
- this.setSelectedService(0)
117
- }
118
- }
119
- },
120
-
121
- fetchShippingServices (isRetry) {
122
- const { storeId } = this
123
- const url = '/calculate_shipping.json'
124
- const method = 'POST'
125
- const data = {
126
- ...this.shippingData,
127
- to: {
128
- zip: this.zipCodeValue,
129
- ...this.shippingData.to
130
- }
131
- }
132
- if (this.shippedItems.length) {
133
- data.items = this.shippedItems.map(reduceItemBody)
134
- const itemsToSubtotal = (subtotal, item) => subtotal + price(item) * item.quantity
135
- data.subtotal = data.items.reduce(itemsToSubtotal, 0)
136
- }
137
- this.waiting = true
138
- modules({ url, method, storeId, data })
139
- .then(({ data }) => this.parseShippingOptions(data.result, isRetry))
140
- .catch(console.error)
141
- .finally(() => {
142
- this.waiting = false
143
- })
144
- },
145
-
146
- submitZipCode (e) {
147
- this.updateZipCode()
148
- if (localStorage) {
149
- localStorage.setItem(zipStorageKey, this.zipCodeValue)
150
- }
151
- this.fetchShippingServices()
152
- },
153
-
154
- setSelectedService (i) {
155
- if (this.selectServices) {
156
- this.$emit('serviceSelected', this.shippingServices[i])
157
- this.selectedService = i
158
- }
159
- }
160
- },
161
-
162
- created () {
163
- if (localStorage) {
164
- if (!this.zipCode) {
165
- const storedZip = localStorage.getItem(zipStorageKey)
166
- if (storedZip) {
167
- this.zipCodeValue = storedZip
168
- this.updateZipCode()
169
- }
170
- }
171
- if (!this.shippingResult.length) {
172
- if (this.zipCodeValue) {
173
- this.fetchShippingServices()
174
- }
175
- } else {
176
- this.parseShippingOptions(this.shippingResult)
177
- }
178
- }
179
- }
180
- }
@@ -1,39 +0,0 @@
1
- import { _config, formatMoney } from '@ecomplus/utils'
2
- import dictionary from './../../lib/dictionary'
3
-
4
- export default {
5
- name: 'EcShippingLine',
6
-
7
- props: {
8
- lang: {
9
- type: String,
10
- default: _config.get('lang')
11
- },
12
- shippingLine: {
13
- type: Object,
14
- required: true
15
- }
16
- },
17
-
18
- computed: {
19
- isWorkingDays () {
20
- const shipping = this.shippingLine
21
- return (shipping.posting_deadline && shipping.posting_deadline.working_days) ||
22
- (shipping.delivery_time && shipping.delivery_time.working_days)
23
- },
24
-
25
- deadline () {
26
- const shipping = this.shippingLine
27
- let days = shipping.posting_deadline ? shipping.posting_deadline.days : 0
28
- if (shipping.delivery_time) {
29
- days += shipping.delivery_time.days
30
- }
31
- return days
32
- }
33
- },
34
-
35
- methods: {
36
- dictionary,
37
- formatMoney
38
- }
39
- }
@@ -1,103 +0,0 @@
1
- import {
2
- inStock as checkStock,
3
- specValueByText as getSpecValueByText,
4
- specTextValue as getSpecTextValue,
5
- variationsGrids as getVariationsGrids,
6
- gridTitle as getGridTitle
7
- } from '@ecomplus/utils'
8
-
9
- const { storefront } = window
10
- const grids = (storefront && storefront.data && storefront.data.grids) || []
11
-
12
- export default {
13
- name: 'EcVariations',
14
-
15
- props: {
16
- product: {
17
- type: Object,
18
- required: true
19
- },
20
- selectedId: String
21
- },
22
-
23
- data () {
24
- return {
25
- selectedOptions: {},
26
- filteredGrids: getVariationsGrids(this.product, null, true)
27
- }
28
- },
29
-
30
- methods: {
31
- getColorOptionBg (optionText) {
32
- const rgbs = optionText.split(',').map(colorName => {
33
- return getSpecValueByText(this.product.variations, colorName.trim(), 'colors')
34
- })
35
- return rgbs.length > 1
36
- ? `background:linear-gradient(to right bottom, ${rgbs[0]} 50%, ${rgbs[1]} 50%)`
37
- : `background:${rgbs[0]}`
38
- },
39
-
40
- getSpecValue (optionText, grid) {
41
- const { variations } = this.product
42
- let values
43
- if (grid === 'colors') {
44
- const colorNames = optionText.split(',')
45
- if (colorNames.length > 1) {
46
- values = []
47
- colorNames.forEach(color => {
48
- values.push(getSpecValueByText(variations, color.trim(), grid))
49
- })
50
- }
51
- }
52
- return values || getSpecValueByText(variations, optionText, grid)
53
- },
54
-
55
- getGridTitle (grid) {
56
- return getGridTitle(grid, grids)
57
- },
58
-
59
- selectOption (optionText, grid, gridIndex) {
60
- const { product, selectedOptions, orderedGrids } = this
61
- this.$set(selectedOptions, grid, optionText)
62
- const filterGrids = {}
63
- for (let i = 0; i <= gridIndex; i++) {
64
- const grid = orderedGrids[i]
65
- if (selectedOptions[grid]) {
66
- filterGrids[grid] = selectedOptions[grid]
67
- }
68
- }
69
- const nextFilteredGrids = getVariationsGrids(product, filterGrids, true)
70
- for (let i = gridIndex + 1; i < orderedGrids.length; i++) {
71
- const grid = orderedGrids[i]
72
- this.filteredGrids[grid] = nextFilteredGrids[grid]
73
- }
74
- const variations = product.variations.slice(0)
75
- for (let i = 0; i < variations.length; i++) {
76
- const variation = variations[i]
77
- if (!checkStock(variation)) {
78
- variations.splice(i, 1)
79
- } else {
80
- const { specifications } = variation
81
- for (const grid in specifications) {
82
- if (selectedOptions[grid] !== getSpecTextValue(variation, grid)) {
83
- variations.splice(i, 1)
84
- i--
85
- break
86
- }
87
- }
88
- }
89
- }
90
- this.$emit('update:selectedId', variations.length ? variations[0]._id : null)
91
- }
92
- },
93
-
94
- computed: {
95
- variationsGrids () {
96
- return getVariationsGrids(this.product)
97
- },
98
-
99
- orderedGrids () {
100
- return Object.keys(this.variationsGrids)
101
- }
102
- }
103
- }