@ecomplus/widget-martan 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/README.md +11 -0
  3. package/cms.config.js +264 -0
  4. package/dist/public/widget-martan.1.min.js +2 -0
  5. package/dist/public/widget-martan.1.min.js.map +1 -0
  6. package/dist/public/widget-martan.2.min.js +2 -0
  7. package/dist/public/widget-martan.2.min.js.map +1 -0
  8. package/dist/public/widget-martan.3.min.js +2 -0
  9. package/dist/public/widget-martan.3.min.js.map +1 -0
  10. package/dist/public/widget-martan.4.min.js +2 -0
  11. package/dist/public/widget-martan.4.min.js.map +1 -0
  12. package/dist/public/widget-martan.5.min.js +2 -0
  13. package/dist/public/widget-martan.5.min.js.map +1 -0
  14. package/dist/public/widget-martan.var.min.js +71 -0
  15. package/dist/public/widget-martan.var.min.js.map +1 -0
  16. package/dist/widget-martan.1.min.js +2 -0
  17. package/dist/widget-martan.1.min.js.map +1 -0
  18. package/dist/widget-martan.2.min.js +2 -0
  19. package/dist/widget-martan.2.min.js.map +1 -0
  20. package/dist/widget-martan.3.min.js +2 -0
  21. package/dist/widget-martan.3.min.js.map +1 -0
  22. package/dist/widget-martan.4.min.js +2 -0
  23. package/dist/widget-martan.4.min.js.map +1 -0
  24. package/dist/widget-martan.5.min.js +2 -0
  25. package/dist/widget-martan.5.min.js.map +1 -0
  26. package/dist/widget-martan.min.js +71 -0
  27. package/dist/widget-martan.min.js.map +1 -0
  28. package/package.json +36 -0
  29. package/src/append/body.ejs +79 -0
  30. package/src/append/head.ejs +5 -0
  31. package/src/append/product-block.ejs +5 -0
  32. package/src/append/product-card-slots.ejs +3 -0
  33. package/src/append/product-slots.ejs +25 -0
  34. package/src/append/stamps.ejs +3 -0
  35. package/src/index.js +22 -0
  36. package/src/utils/get-width.js +11 -0
  37. package/src/utils/textToNumber.js +31 -0
  38. package/src/utils/time-ago.js +35 -0
  39. package/src/widgets/reviews/AuthorAndRating.vue +30 -0
  40. package/src/widgets/reviews/AverageScore.vue +160 -0
  41. package/src/widgets/reviews/AverageTotal.vue +35 -0
  42. package/src/widgets/reviews/CardReview.vue +87 -0
  43. package/src/widgets/reviews/GridView.vue +113 -0
  44. package/src/widgets/reviews/HeaderExpanded.vue +84 -0
  45. package/src/widgets/reviews/HeaderMinimal.vue +110 -0
  46. package/src/widgets/reviews/ListView.vue +47 -0
  47. package/src/widgets/reviews/Quickview.vue +398 -0
  48. package/src/widgets/reviews/ReviewBody.vue +39 -0
  49. package/src/widgets/reviews/ReviewReply.vue +57 -0
  50. package/src/widgets/reviews/Reviews.vue +496 -0
  51. package/src/widgets/reviews/Score.vue +186 -0
  52. package/src/widgets/reviews/Sort.vue +76 -0
  53. package/src/widgets/reviews/ThumbsPictures.vue +135 -0
  54. package/src/widgets/reviews/Total.vue +79 -0
  55. package/src/widgets/reviews/VerifiedPurchase.vue +111 -0
  56. package/src/widgets/reviews/VideoPlayer.vue +136 -0
  57. package/src/widgets/reviews/index.js +52 -0
  58. package/src/widgets/reviews/isRecommended.vue +44 -0
  59. package/src/widgets/snippets/Rating.vue +71 -0
  60. package/src/widgets/snippets/Snippets.vue +311 -0
  61. package/src/widgets/snippets/index.js +45 -0
  62. package/webpack.config.js +1 -0
@@ -0,0 +1,57 @@
1
+ <template>
2
+ <div
3
+ v-if="reply"
4
+ class="mt-reply__wrapper"
5
+ >
6
+ <div style="margin-right: 10px">
7
+ <svg
8
+ width="24px"
9
+ height="24px"
10
+ viewBox="0 0 24 24"
11
+ xmlns="http://www.w3.org/2000/svg"
12
+ style="transform: rotate(180deg)"
13
+ >
14
+ <path
15
+ d="M10.53 5.03a.75.75 0 10-1.06-1.06l-6.25 6.25a.75.75 0 000 1.06l6.25 6.25a.75.75 0 101.06-1.06L5.56 11.5H17a3.248 3.248 0 013.25 3.248v4.502a.75.75 0 001.5 0v-4.502A4.748 4.748 0 0017 10H5.56l4.97-4.97z"
16
+ />
17
+ </svg>
18
+ </div>
19
+
20
+ <div class="mt-reply">
21
+ <span class="mt-reply__body"
22
+ >{{ i19storeResponse }} ·
23
+ <span
24
+ class="mt-reply__date"
25
+ :title="'Respondido em ' + formatDate(reply.created_at)"
26
+ >{{ timeAgo(reply.created_at) }}</span
27
+ ></span
28
+ >
29
+ <span>{{ reply.body }}</span>
30
+ </div>
31
+ </div>
32
+ </template>
33
+
34
+ <script>
35
+ import { formatDate } from "@ecomplus/utils";
36
+ import { timeAgo } from "../../utils/time-ago";
37
+
38
+ export default {
39
+
40
+ name: "ReviewReply",
41
+
42
+ props: {
43
+ reply: {
44
+ type: Object,
45
+ }
46
+ },
47
+
48
+ computed: {
49
+ i19storeResponse: () => 'Resposta da loja'
50
+ },
51
+
52
+ methods: {
53
+ formatDate,
54
+ timeAgo
55
+ }
56
+ };
57
+ </script>
@@ -0,0 +1,496 @@
1
+ <template>
2
+ <div
3
+ :data-header="headerLayout"
4
+ :data-layout="reviewsLayout"
5
+ >
6
+ <div class="mt-reviews container" :class="'mt-theme--' + headerLayout">
7
+ <p class="lead">
8
+ <a href="#reviews" :name="title || 'reviews'">#</a>
9
+ {{ title }}
10
+ </p>
11
+
12
+ <total v-if="headerLayout !== 'header-expanded' && headerLayout !== 'header-minimal'"
13
+ @onSort="onSort" :reviews="{ list, orderRating, total }" />
14
+
15
+ <component @updateOrderByAverage="updateOrderBy" @onSort="onSort" :is="headerLayout"
16
+ :reviews="{ averageTotal, average, total, orderRating }" :starColor="starColor"></component>
17
+
18
+ <total v-if="headerLayout === 'header-expanded'"
19
+ @onSort="onSort" :reviews="{ list, orderRating, total }" />
20
+
21
+ <component :reviews="{ list, orderRating, total }" :starColor="starColor" @openQuickview="openQuickview"
22
+ :is="reviewsLayout"></component>
23
+
24
+ <div class="mt-questions__actions" v-if="showLoadMore()">
25
+ <div class="mt-questions__pagination" id="mt-more-questions">
26
+ <button class="btn btn-primary" @click="loadMore" :disabled="loading">
27
+ {{ loading ? "Carregando.." : "Carregar mais" }}
28
+ </button>
29
+ </div>
30
+ </div>
31
+ </div>
32
+
33
+ <quickview @onClose="onCloseQuickview" :isOpen="isOpenQuickView"
34
+ :review="selectedReview" :starColor="starColor" />
35
+ </div>
36
+ </template>
37
+
38
+ <script>
39
+
40
+ import ListView from "./ListView.vue";
41
+ import GridView from "./GridView.vue";
42
+ import Total from "./Total.vue";
43
+ import Quickview from "./Quickview.vue";
44
+ import { MARTAN_API } from '../..';
45
+
46
+ export default {
47
+ name: "Reviews",
48
+
49
+ props: {
50
+ storeId: {
51
+ type: Number,
52
+ required: true
53
+ },
54
+ webId: {
55
+ type: String,
56
+ required: true
57
+ },
58
+ product: {
59
+ type: String,
60
+ required: true
61
+ },
62
+ backgroundColor: {
63
+ type: String,
64
+ default: "#fff",
65
+ },
66
+ starColor: {
67
+ type: String,
68
+ default: "#212529",
69
+ },
70
+ primaryColor: {
71
+ type: String,
72
+ default: "#212529",
73
+ },
74
+ headerLayout: {
75
+ type: String,
76
+ default: "header-minimal",
77
+ },
78
+ reviewsLayout: {
79
+ type: String,
80
+ default: "list-grid",
81
+ },
82
+ title: {
83
+ type: String,
84
+ },
85
+ showTitle: {
86
+ type: Boolean,
87
+ default: true,
88
+ },
89
+ },
90
+
91
+ data() {
92
+ return {
93
+ list: [],
94
+ total: 0,
95
+ limit: 5,
96
+ offset: 0,
97
+ loading: false,
98
+ orderRating: null,
99
+ orderReviews: null,
100
+ averageTotal: 0,
101
+
102
+ $isSorting: false,
103
+ $count: null,
104
+
105
+ average: {
106
+ one: 0,
107
+ two: 0,
108
+ three: 0,
109
+ four: 0,
110
+ five: 0,
111
+ },
112
+
113
+ isOpenQuickView: false,
114
+ selectedReview: null,
115
+ };
116
+ },
117
+
118
+ watch: {
119
+ orderRating: function (oldOrder, newOrder) {
120
+ if (oldOrder !== newOrder) {
121
+ this.list = [];
122
+ this.fetchReviews();
123
+ }
124
+ },
125
+
126
+ orderReviews: function (oldOrder, newOrder) {
127
+ if (oldOrder !== newOrder) {
128
+ this.list = [];
129
+ this.fetchReviews();
130
+ }
131
+ },
132
+
133
+ limit: function () {
134
+ this.fetchReviews();
135
+ },
136
+
137
+ offset: function () {
138
+ this.fetchReviews();
139
+ },
140
+ },
141
+
142
+ methods: {
143
+ fetchReviews() {
144
+ const params = {
145
+ limit: this.limit,
146
+ offset: this.offset,
147
+ sku: this.product,
148
+ };
149
+
150
+ if (this.orderReviews) {
151
+ params.orderBy = this.orderReviews;
152
+ params.limit = this.limit;
153
+ params.offset = 0;
154
+ }
155
+
156
+ if (this.orderRating) {
157
+ params.rating = this.orderRating;
158
+ }
159
+
160
+ this.$count = null;
161
+ this.loading = true;
162
+
163
+ axios({
164
+ url: MARTAN_API + '/reviews.json',
165
+ headers: {
166
+ "X-Store-Id": this.storeId,
167
+ "X-Web-Id": this.webId,
168
+ },
169
+ params,
170
+ })
171
+ .then(({ data }) => {
172
+ const { result, count } = data;
173
+ let list = [];
174
+ if (
175
+ (Array.isArray(this.list) && !this.orderReviews) ||
176
+ (this.orderReviews && this.$isSorting)
177
+ ) {
178
+ for (const element of result) {
179
+ const isIn = this.list.some((review) => review.id === element.id);
180
+
181
+ if (!isIn) {
182
+ this.list.push(element);
183
+ }
184
+ }
185
+
186
+ list = [...this.list, ...list];
187
+ } else if (
188
+ (Array.isArray(this.list) && this.orderReviews) ||
189
+ this.orderRating
190
+ ) {
191
+ list = result;
192
+ this.$isSorting = false;
193
+ }
194
+
195
+ return { count, list };
196
+ })
197
+
198
+ .then(({ count, list }) => {
199
+ if (this.orderRating) {
200
+ this.$count = count;
201
+ } else {
202
+ this.total = count;
203
+ }
204
+
205
+ this.list = list;
206
+
207
+ return list;
208
+ })
209
+
210
+ .catch((err) => {
211
+ console.error("Failed to load resource from Martan", err);
212
+ })
213
+
214
+ .finally(() => {
215
+ this.loading = false;
216
+ });
217
+ },
218
+
219
+ fetchAverage() {
220
+ axios({
221
+ url: MARTAN_API + '/average.json',
222
+ headers: {
223
+ "X-Store-Id": this.storeId,
224
+ "X-Web-Id": this.webId,
225
+ },
226
+ params: {
227
+ sku: this.product,
228
+ },
229
+ })
230
+ .then(({ data }) => {
231
+ if (data.length) {
232
+ const { average, rating } = data[0];
233
+ Object.assign(this.average, rating);
234
+ this.averageTotal = average;
235
+ }
236
+ })
237
+
238
+ .finally(() => {
239
+ this.loading = false;
240
+ });
241
+ },
242
+
243
+ loadMore() {
244
+ if (this.orderReviews) {
245
+ this.limit = this.limit + this.limit;
246
+ } else {
247
+ this.offset++;
248
+ }
249
+ },
250
+
251
+ showLoadMore() {
252
+ if (
253
+ !this.orderRating &&
254
+ this.total > 0 &&
255
+ this.list.length < this.total
256
+ ) {
257
+ return true;
258
+ }
259
+
260
+ if (
261
+ this.orderRating &&
262
+ this.$count > 0 &&
263
+ this.list.length < this.$count
264
+ ) {
265
+ return true;
266
+ }
267
+ },
268
+
269
+ updateOrderBy({ rating }) {
270
+ if (rating === this.orderRating) {
271
+ this.orderRating = null;
272
+ } else {
273
+ this.offset = 0;
274
+ this.orderRating = rating;
275
+ }
276
+ },
277
+
278
+ onSort({ order }) {
279
+ this.orderReviews = order;
280
+ },
281
+
282
+ openQuickview: function ({ review }) {
283
+ this.selectedReview = review;
284
+ this.isOpenQuickView = true;
285
+ },
286
+
287
+ onCloseQuickview: function () {
288
+ this.isOpenQuickView = false;
289
+ this.selectedReview = null;
290
+ },
291
+ },
292
+
293
+ mounted() {
294
+ Promise.all([this.fetchAverage(), this.fetchReviews()]);
295
+ },
296
+
297
+ components: {
298
+ "list-grid": () => import("./GridView.vue"),
299
+ "list-expanded": () => import("./ListView.vue"),
300
+ "header-expanded": () => import("./HeaderExpanded.vue"),
301
+ "header-minimal": () => import("./HeaderMinimal.vue"),
302
+ Total,
303
+ ListView,
304
+ GridView,
305
+ Quickview
306
+ },
307
+ };
308
+ </script>
309
+
310
+ <style lang="scss">
311
+ .mt-review {
312
+ padding: 25px 0 22px;
313
+
314
+ &:first-child {
315
+ padding-top: 0;
316
+ }
317
+ }
318
+
319
+ .mt-review__title {
320
+ color: #6b6d76;
321
+ font-size: 16px;
322
+ }
323
+
324
+ .mt-review__date {
325
+ font-size: 10px;
326
+ color: #475569;
327
+ color: #777;
328
+ }
329
+
330
+ .mt-review__body {
331
+ opacity: 0.9;
332
+ margin-top: 10px;
333
+ font-size: 16px;
334
+ line-height: 1.6;
335
+ text-align: justify;
336
+ }
337
+
338
+ .mt-rating__group {
339
+ width: 100%;
340
+ display: flex;
341
+ flex-direction: column;
342
+ gap: 5px;
343
+ }
344
+
345
+ .mt-review__author {
346
+ font-size: 14px;
347
+ color: #333;
348
+ font-weight: bolder;
349
+ display: flex;
350
+ align-items: center;
351
+ justify-content: center;
352
+ gap: 5px;
353
+ }
354
+
355
+ .mt-review__reactions svg {
356
+ width: 18px;
357
+ cursor: pointer;
358
+ }
359
+
360
+ .mt-review__reactions {
361
+ display: flex;
362
+ align-items: center;
363
+ font-size: 11px;
364
+ margin-top: 0.75rem;
365
+ color: #777;
366
+ border: 1px solid #777;
367
+ border-radius: 50px;
368
+ max-width: 100px;
369
+ justify-content: space-evenly;
370
+ height: 30px;
371
+ }
372
+
373
+ .mt-reviews__list {
374
+ padding: 5px 0;
375
+ }
376
+
377
+ .mt-reviews__votesdown,
378
+ .mt-reviews__votesup {
379
+ display: flex;
380
+ align-items: center;
381
+ }
382
+
383
+ .mt-reviews__votesup {
384
+ margin-right: 10px;
385
+ }
386
+
387
+ .mt-reply {
388
+ margin: 10px 0 0;
389
+ display: flex;
390
+ flex-direction: column;
391
+ background: rgb(241, 241, 241);
392
+ padding: 20px;
393
+ border-radius: 12px;
394
+ font-size: 15px;
395
+ line-height: 1.6;
396
+ gap: 10px;
397
+ border-right: 1px solid #1717171a;
398
+ border-left: 3px solid rgb(230, 230, 230);
399
+ }
400
+
401
+ @media (max-width: 580px) {
402
+ .mt-reply {
403
+ margin: 10px 0;
404
+ }
405
+ }
406
+
407
+ .mt-reply__date {
408
+ font-weight: normal;
409
+ font-size: 14px;
410
+ text-decoration: none;
411
+ color: #475569;
412
+ color: #777;
413
+ }
414
+
415
+ .mt-reply__body {
416
+ font-weight: 600;
417
+ font-size: 14px;
418
+ text-decoration: none;
419
+ }
420
+
421
+ .mt-is__recomended {
422
+ font-size: 12px;
423
+ font-weight: 600;
424
+ color: #6b6d76;
425
+ }
426
+
427
+ .mt-questions__actions {
428
+ padding: 20px;
429
+ display: flex;
430
+ justify-content: center;
431
+ }
432
+
433
+ .mt-rating__option {
434
+ background-color: #fff;
435
+ height: 35px;
436
+ width: 140px;
437
+ border-radius: 20px;
438
+ color: #777;
439
+ border: 1px solid #777;
440
+ cursor: pointer;
441
+ transition: all 0.5s ease;
442
+ }
443
+
444
+ .mt-rating__option:hover {
445
+ background-color: #777;
446
+ color: #fff;
447
+ }
448
+
449
+ .mt-reviews.mt-theme--vertical .mt-header--vertical {
450
+ width: 30%;
451
+ }
452
+
453
+ .mt-reviews.mt-theme--vertical .mt-reviews__list {
454
+ width: 70%;
455
+ }
456
+
457
+ @media (max-width: 580px) {
458
+ .mt-reviews.mt-theme--vertical .mt-reviews__list {
459
+ width: 100%;
460
+ }
461
+
462
+ .mt-reviews.mt-theme--vertical .mt-header--vertical {
463
+ width: 100%;
464
+ border-right: none;
465
+ }
466
+
467
+ .mt-reviews.mt-theme--vertical .mt-reviews__rating {
468
+ flex-direction: column;
469
+ }
470
+
471
+ .mt-reviews.mt-theme--vertical .mt-header--vertical .mt-rating__options {
472
+ max-width: inherit;
473
+ }
474
+ }
475
+
476
+ .mt-rating__user {
477
+ position: relative;
478
+ max-width: 40px;
479
+ height: fit-content;
480
+ width: 100%;
481
+ margin-right: 8px;
482
+ border-radius: 50%;
483
+ background: #858585;
484
+ display: inline-flex;
485
+ align-items: center;
486
+ justify-content: center;
487
+ color: #fff;
488
+ font-size: 25px;
489
+ font-weight: 500;
490
+ }
491
+
492
+ .mt-reviews.mt-theme--vertical .mt-rating__average__sort {
493
+ border-bottom: 1px solid #eee;
494
+ padding-bottom: 1rem;
495
+ }
496
+ </style>