@hulkapps/app-manager-vue 2.0.4 → 2.0.7

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.
@@ -0,0 +1,461 @@
1
+ <template>
2
+ <PPage
3
+ class="app-manager-plan-page custom-title"
4
+ title="Choose plan"
5
+ :subtitle = "subtitleContent"
6
+ >
7
+
8
+ <PStack slot="primaryAction">
9
+ <PStackItem style="margin-top: 20px">
10
+ <PButtonGroup class="btn-group" segmented>
11
+ <PButton v-if="monthlyPlan.length && yearlyPlan.length" :style="selectedPlan === 'monthly' ? monthlySelectedStyle : monthlyStyle " @click="selectPlan('monthly')">
12
+ <p style="font-size: 17px; font-weight: 500" slot="default">{{('Monthly')}}</p>
13
+ </PButton>
14
+
15
+ <PButton v-if="yearlyPlan.length && monthlyPlan.length" :style="selectedPlan === 'annually' ? yearlySelectedStyle : yearlyStyle " @click="selectPlan('annually')" :primary="selectedPlan === 'annually' " >
16
+ <YearlyPlanPromotion />
17
+ </PButton>
18
+ </PButtonGroup>
19
+ </PStackItem>
20
+ </PStack>
21
+ <hr style="width: 100%; margin-right: auto;margin-left: auto;margin-bottom: 20px;" />
22
+ <!--=======================================================-->
23
+
24
+ <PLayout class="custom-plan">
25
+ <PLayoutSection style="display: flex;border-radius: 20px;">
26
+ <template style="margin-bottom: 20px; display: flex !important;">
27
+ <template >
28
+ <div class="Polaris-ResourceList__ResourceListWrapper features" style="width: 30%">
29
+ <div class="plan__price"></div>
30
+ <ul class="Polaris-ResourceList">
31
+ <li class="Polaris-ResourceList__ItemWrapper pro_title" v-for="(feature, key) in features" :key="key">
32
+ <div class="Polaris-ResourceList-Item__Container">
33
+ <div class="Polaris-ResourceList-Item__Content">
34
+ <h1 class="for-price-per-month"><span>{{ feature.name }}</span></h1>
35
+ </div>
36
+ </div>
37
+ </li>
38
+ </ul>
39
+ </div>
40
+ </template>
41
+ <carousel style="width: 70%" :per-page="perPage" :mouseDrag="false" :navigation-enabled="true" :paginationEnabled="false" :navigateTo="[this.currentSlide,true]" @transition-start="handleNavigationClick($event)">
42
+ <template>
43
+ <slide :id="key" :class="`slide-${key}`" v-for="(plan, key) in selectedPlan === 'monthly' ? monthlyPlan : yearlyPlan" :key="`slide-${key}`" >
44
+ <div class="plan__price" :style="activePlanStyle(plan)">
45
+ <b style="font-size: 16px">{{(plan.name)}}</b>
46
+ <div v-if="plan.discount && plan.discount > 0" >
47
+ <p style="display: flex;margin-top: 10px">
48
+ <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(calculateDiscountedPrice(plan)).toFixed(2)}}</PHeading>
49
+ <b style="margin-top: 5px;font-size: 17px">/{{selectedPlan === 'monthly' ? ("mo") : ("year")}}</b>
50
+ </p>
51
+ <p style="display: flex;margin-top: 7px">
52
+ <PHeading style="font-size: 18px;font-weight: 500; text-decoration:line-through;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
53
+ <b style="margin-top: 3px;font-size: 14px">/{{selectedPlan === 'monthly' ? ("mo") : ("year")}}</b>
54
+ </p>
55
+ </div>
56
+ <div v-else>
57
+ <p style="display: flex;margin-top: 10px">
58
+ <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
59
+ <b style="margin-top: 5px;font-size: 17px">/{{selectedPlan === 'monthly' ? ("mo") : ("year")}}</b>
60
+ </p>
61
+ </div>
62
+ </div>
63
+ <div>
64
+ <ul v-if="plan.features">
65
+ <li v-for="(feature, key) in features" :key="key" :class="activePlanClass(plan)" :style="activePlanStyle(plan)">
66
+ <div>
67
+ <template v-if="plan.features[feature.uuid]" style="display: flex">
68
+ <template v-if="plan.features[feature.uuid].value_type === 'boolean'">
69
+ <PIcon v-if="parseInt(plan.features[feature.uuid].value) === 1" color="success" source="TickMinor"/>
70
+ <PIcon v-else color="subdued" source="MinusMinor"/>
71
+ </template>
72
+ <template v-else style="display: flex">
73
+ <span v-if="plan.features[feature.uuid].value">{{ format(plan.features[feature.uuid]) }}</span>
74
+ <PIcon v-else color="subdued" source="MinusMinor"/>
75
+ </template>
76
+ </template>
77
+ <template v-else>
78
+ <PIcon color="subdued" source="MinusMinor"/>
79
+ </template>
80
+ </div>
81
+ </li>
82
+ <li>
83
+ <PButton v-if="isCurrentPlan(plan)" :disabled="isCurrentPlan(plan)"
84
+ full-width
85
+ :pressed="isCurrentPlan(plan)">
86
+ {{ ('Current Plan') }}
87
+ </PButton>
88
+ <PButton v-else-if="!plan.store_base_plan || plan.shopify_plans.includes(shop.shopify_plan)"
89
+ full-width
90
+ @click="plan ? getPlanUrl(plan):'javascript:void'"
91
+ :primary="true" >
92
+ {{ ('Choose Plan') }}
93
+ </PButton>
94
+ <PButton v-else :disabled="true"
95
+ full-width
96
+ :pressed="true">
97
+ {{ ('Not applicable') }}
98
+ </PButton>
99
+ </li>
100
+ </ul>
101
+ </div>
102
+ </slide>
103
+ </template>
104
+ </carousel>
105
+ </template>
106
+ </PLayoutSection>
107
+ </PLayout>
108
+ <!--====================================================================-->
109
+ <PStack v-if="onboard && !shop.has_plan" class="choose-plan-btn" alignment="center" distribution="center" vertical>
110
+ <PStackItem fill>
111
+ <PButton plain @click="activePlan">{{ ('I will choose the plan later') }}</PButton>
112
+ </PStackItem>
113
+ </PStack>
114
+ </PPage>
115
+ </template>
116
+
117
+ <script>
118
+
119
+ import axios from "axios";
120
+ import PlanBanners from "./PlanBanners";
121
+ import YearlyPlanPromotion from "./YearlyPlanPromotion";
122
+ import PPage from "../polaris-vue/src/components/PPage/PPage";
123
+ import PStack from "../polaris-vue/src/components/PStack/PStack";
124
+ import PStackItem from "../polaris-vue/src/components/PStack/components/PStackItem/PStackItem";
125
+ import {PButton} from "../polaris-vue/src/components/PButton";
126
+ import {PButtonGroup} from "../polaris-vue/src/components/PButtonGroup";
127
+ import {PHeading} from "../polaris-vue/src/components/PHeading";
128
+ import {PLayout} from "../polaris-vue/src/components/PLayout";
129
+ import {PLayoutSection} from "../polaris-vue/src/components/PLayout/components/PLayoutSection";
130
+ import {PTextContainer} from "../polaris-vue/src/components/PTextContainer";
131
+ import {PDataTable} from "../polaris-vue/src/components/PDataTable";
132
+ import {PDataTableCol} from "../polaris-vue/src/components/PDataTable/components/PDataTableCol";
133
+ import {PDataTableRow} from "../polaris-vue/src/components/PDataTable/components/PDataTableRow";
134
+ import {PIcon} from "../polaris-vue/src/components/PIcon";
135
+ import {PTextStyle} from "../polaris-vue/src/components/PTextStyle";
136
+ import {Carousel, Slide} from 'vue-carousel';
137
+
138
+ export default {
139
+ name: "AppManagerSliderPlan",
140
+ components: { Carousel, Slide, YearlyPlanPromotion, PlanBanners, PPage, PStack, PStackItem, PButton, PButtonGroup, PHeading, PLayout, PLayoutSection, PTextContainer, PDataTable, PDataTableCol, PDataTableRow, PIcon, PTextStyle },
141
+ props: ['shop_domain'],
142
+ data() {
143
+ return {
144
+ perPage: 4,
145
+ currentSlide: 0,
146
+ plan: {},
147
+ plans: [],
148
+ features: [],
149
+ shopify_plan: '',
150
+ default_plan_id: null,
151
+ onboard: true,
152
+ subtitleContent: '',
153
+ checkList: [
154
+ "60 days free trial",
155
+ ],
156
+ selectedPlan:'monthly',
157
+ monthlySelectedStyle:{
158
+ height: '60px',
159
+ backgroundColor:'#257f60',
160
+ color:'#fff',
161
+ position:'relative',
162
+ right:'-5px',
163
+ borderRadius:'8px',
164
+ zIndex: 1,
165
+ },
166
+ yearlySelectedStyle:{
167
+ height: '60px',
168
+ backgroundColor:'#257f60',
169
+ position:'relative',
170
+ left:'-5px',
171
+ borderRadius:'8px'
172
+ },
173
+ monthlyStyle:{
174
+ height: '55px',
175
+ backgroundColor:'#f0f8f5',
176
+ boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px',
177
+ border:'none',
178
+ borderRadius:'8px',
179
+ ZIndex: 11,
180
+ },
181
+ yearlyStyle:{
182
+ color:'#258060',
183
+ height: '55px',
184
+ backgroundColor:'#f0f8f5',
185
+ boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px',
186
+ border:'none',
187
+ borderRadius:'8px'
188
+ },
189
+ }
190
+ },
191
+ computed: {
192
+ shop() {
193
+ return {
194
+ "name": this.shop_domain,
195
+ "shopify_plan": this.shopify_plan,
196
+ "has_plan": !!this.plan,
197
+ "plan": this.plan,
198
+ "default_plan_id": this.default_plan_id,
199
+ };
200
+ },
201
+ headings() {
202
+ let headings = [('Plans & Features')];
203
+ this.plans.forEach(plan => {
204
+
205
+ let heading = (plan.name);
206
+ if (plan.price > 0) heading += ` ($${plan.price}/mo)`;
207
+ headings.push(heading);
208
+ });
209
+ return headings;
210
+ },
211
+ monthlyPlan() {
212
+ const plans = [];
213
+ for(let planKey in this.plans) {
214
+ if(this.plans[planKey].interval === 'EVERY_30_DAYS') {
215
+ plans.push(this.plans[planKey]);
216
+ }
217
+ }
218
+ return plans;
219
+ },
220
+ yearlyPlan() {
221
+ const plans = [];
222
+ for(let planKey in this.plans) {
223
+ if(this.plans[planKey].interval === 'ANNUAL') {
224
+ plans.push(this.plans[planKey]);
225
+ }
226
+ }
227
+ return plans;
228
+ },
229
+ },
230
+ methods: {
231
+ handleNavigationClick($event) {
232
+ const activeSlideIds = [];
233
+ let activeSlides = document.getElementsByClassName('VueCarousel-slide-active')
234
+ for (let i=0, max=activeSlides.length; i < max; i++) {
235
+ activeSlideIds.push(parseInt(activeSlides[i].id))
236
+ }
237
+ let last = activeSlideIds.pop();
238
+ let first = last - (this.perPage - 1)
239
+
240
+ let allSlides = document.getElementsByClassName('VueCarousel-slide');
241
+ for (let i=0, max=allSlides.length; i < max; i++) {
242
+ let slide = document.getElementById(allSlides[i].id);
243
+ slide.classList.remove('first-slide')
244
+ slide.classList.remove('last-slide')
245
+ }
246
+
247
+ let firstSlideClassName = '.slide-' + first
248
+ let element = document.querySelector(firstSlideClassName);
249
+ element.classList.add('first-slide')
250
+
251
+ let lastSlideClassName = '.slide-' + last
252
+ element = document.querySelector(lastSlideClassName);
253
+ element.classList.add('last-slide')
254
+
255
+ document.querySelector('.VueCarousel-navigation-button.VueCarousel-navigation-prev').style.left = -document.querySelector('.Polaris-ResourceList__ResourceListWrapper.features').offsetWidth + 'px';
256
+ },
257
+ activePlanStyle(plan) {
258
+ return [plan.shopify_plans.includes(this.shop.shopify_plan) || !plan.store_base_plan ? {backgroundColor: '#f0f8f5', color: '#257f60'} : {}];
259
+ },
260
+ activePlanClass(plan) {
261
+ return plan.shopify_plans.includes(this.shop.shopify_plan) || !plan.store_base_plan ? 'active-plan' : '';
262
+ },
263
+ isCurrentPlan(plan) {
264
+ return this.shop.plan && (plan.id === this.shop.plan.id || (!plan.is_custom && plan.base_plan === this.shop.plan.id));
265
+ },
266
+ isSamePlanInOtherInterval(plan) {
267
+ return this.shop.plan && (plan.shopify_plans === this.shop.plan.shopify_plans)
268
+ },
269
+ format(feature) {
270
+ if (['double', 'integer'].includes(feature?.value_type)) {
271
+ if (feature.format === 'percentage') {
272
+ return `${feature.value}%`
273
+ } else if (feature.format === 'count') {
274
+ return (feature.value < 0 ? (`Unlimited`) : feature.value)
275
+ } else return feature.value
276
+ }
277
+ else if(feature?.value_type === 'array') {
278
+ return JSON.parse(feature.value).join(',')
279
+ }
280
+ else if(feature?.value_type === 'string') {
281
+ return feature.value
282
+ }
283
+ },
284
+ calculateDiscountedPrice(plan) {
285
+ if (plan.discount_type === 'percentage') {
286
+ return plan.price - (plan.price * plan.discount)/100
287
+ }
288
+ else if (plan.discount_type === 'amount') {
289
+ return plan.price - plan.discount
290
+ }
291
+ },
292
+ async getPlanUrl(plan) {
293
+ let shopName = this.shop.name;
294
+ const response = await axios.get(`${this.app_manager_config.baseUrl}/api/app-manager/plan/process/${plan.id}?shop=${shopName}`).catch(error => {
295
+ console.error(error)
296
+ });
297
+ let redirectUrl = response.data.redirect_url;
298
+ if (redirectUrl) {
299
+ window.top.location.href = redirectUrl;
300
+ }
301
+ },
302
+ async activePlan() {
303
+ const response = await this.activeWithoutPlan()
304
+ if (response.data.status === true && this.onboard) {
305
+ // Create the event
306
+ this.$emit('handlePlanSelect', {chose_later: true})
307
+ this.onboard = false;
308
+ }
309
+ },
310
+ async activeWithoutPlan() {
311
+ return await axios.post(`${this.app_manager_config.baseUrl}/api/app-manager/active-without-plan`, {
312
+ shop_domain: this.shop.name,
313
+ plan_id: this.shop.default_plan_id
314
+ }).catch(error => {
315
+ console.error(error)
316
+ });
317
+ },
318
+ async selectPlan(value){
319
+ this.selectedPlan= value;
320
+ setTimeout(function() {
321
+ let element = document.querySelector('.slide-0');
322
+ element.classList.add('first-slide')
323
+ element = document.querySelector('.slide-3');
324
+ element.classList.add('last-slide')
325
+ document.querySelector('.VueCarousel-navigation-button.VueCarousel-navigation-prev').style.left = -document.querySelector('.Polaris-ResourceList__ResourceListWrapper.features').offsetWidth + 'px';
326
+ },400)
327
+ },
328
+ headerClasses(firstColumn) {
329
+ return {
330
+ 'Polaris-DataTable__Cell': true,
331
+ 'Polaris-DataTable__Cell--header': true,
332
+ 'Polaris-DataTable__Cell--verticalAlignMiddle': true,
333
+ 'Polaris-DataTable__Cell--firstColumn': Boolean(firstColumn),
334
+ };
335
+ },
336
+ },
337
+ async mounted() {
338
+
339
+ const featuresData = await axios.get(`${this.app_manager_config.baseUrl}/api/app-manager/plan-features`).catch(error => {
340
+ console.error(error)
341
+ });
342
+ this.features = featuresData.data.features;
343
+ this.features = this.features.sort((featureA, featureB) => parseInt(featureA.display_order) - parseInt(featureB.display_order))
344
+
345
+ const plansData = await axios.get(`${this.app_manager_config.baseUrl}/api/app-manager/plans`, { params: { 'shop_domain': this.shop_domain } }).catch(error => {
346
+ console.error(error)
347
+ });
348
+ this.plans = plansData.data.plans;
349
+ this.plans = this.plans.sort((planA, planB) => parseFloat(planA.price) - parseFloat(planB.price));
350
+ if (this.plans && this.plans[0].store_base_plan) {
351
+ this.subtitleContent = 'App plans are based on your existing shopify plan';
352
+ }
353
+ this.shopify_plan = plansData.data.shopify_plan;
354
+ this.plan = plansData.data.plan;
355
+ if (this.plan?.interval === 'ANNUAL') {
356
+ this.selectedPlan = 'annually'
357
+ }
358
+ this.default_plan_id = plansData.data.default_plan_id;
359
+ this.onboard = !this.plan
360
+ },
361
+
362
+ created() {
363
+ let initializeSliderComponent = setInterval(() => {
364
+ let element = document.querySelector('.slide-0');
365
+ if (element) {
366
+ element.classList.add('first-slide')
367
+ element = document.querySelector('.slide-3');
368
+ element.classList.add('last-slide')
369
+ document.querySelector('.VueCarousel-navigation-button.VueCarousel-navigation-prev').style.left = -document.querySelector('.Polaris-ResourceList__ResourceListWrapper.features').offsetWidth + 'px';
370
+ clearInterval(initializeSliderComponent);
371
+ }
372
+ }, 100);
373
+ },
374
+
375
+ }
376
+ </script>
377
+
378
+ <style lang="scss">
379
+
380
+ @import url('https://fonts.googleapis.com/css2?family=Satisfy&display=swap');
381
+
382
+ .app-manager .app-manager-plan-page ul
383
+ {
384
+ list-style: none;
385
+ margin: 0;
386
+ padding: 0;
387
+ }
388
+ .app-manager .app-manager-plan-page .Polaris-ResourceList__ResourceListWrapper.features li,
389
+ .app-manager .app-manager-plan-page .Polaris-Layout__Section .VueCarousel-slide li,
390
+ .app-manager .app-manager-plan-page .plan__price
391
+ {
392
+ padding: 16px 16px 16px 20px;
393
+ }
394
+ .app-manager .app-manager-plan-page .Polaris-ResourceList__ResourceListWrapper.features li,
395
+ .app-manager .app-manager-plan-page .Polaris-Layout__Section .VueCarousel-slide li:not(:last-child),
396
+ .app-manager .app-manager-plan-page .Polaris-Layout.custom-plan .VueCarousel .plan__price
397
+ {
398
+ border-top: 1px solid #dddddd;
399
+ border-right: 1px solid #dddddd;
400
+ background: #fff;
401
+ }
402
+ .app-manager .app-manager-plan-page .Polaris-ResourceList__ResourceListWrapper.features li{
403
+ border-right: none;
404
+ border-left: 1px solid #dddddd;
405
+ }
406
+ .app-manager .app-manager-plan-page .plan__price{
407
+ min-height:121px;
408
+ }
409
+ .app-manager .app-manager-plan-page .Polaris-ResourceList__ResourceListWrapper.features li:last-child,
410
+ .app-manager .app-manager-plan-page .Polaris-Layout__Section .VueCarousel-slide li:nth-last-child(2)
411
+ {
412
+ border-bottom: 1px solid #dddddd;
413
+ }
414
+ .app-manager .app-manager-plan-page .Polaris-ResourceList__ResourceListWrapper.features li:first-child
415
+ {
416
+ border-top-left-radius: 12px;
417
+ }
418
+ .app-manager .app-manager-plan-page .Polaris-ResourceList__ResourceListWrapper.features li:last-child
419
+ {
420
+ border-bottom-left-radius: 12px;
421
+ }
422
+ .app-manager .app-manager-plan-page .VueCarousel-inner .VueCarousel-slide.first-slide ul li:not(:last-child)
423
+ {
424
+ border-left: 1px solid #dddddd;
425
+ }
426
+ .app-manager .app-manager-plan-page .VueCarousel-inner .VueCarousel-slide.first-slide .plan__price
427
+ {
428
+ border-left: 1px solid #dddddd;
429
+ box-shadow: none;
430
+ border-top-left-radius: 12px;
431
+ overflow: hidden;
432
+ }
433
+ .app-manager .app-manager-plan-page .VueCarousel-inner .VueCarousel-slide.last-slide ul li:nth-last-child(2)
434
+ {
435
+ border-bottom-right-radius: 12px;
436
+ }
437
+ .app-manager .app-manager-plan-page .VueCarousel-inner .VueCarousel-slide.last-slide .plan__price
438
+ {
439
+ border-right: 1px solid #dddddd;
440
+ box-shadow: none;
441
+ border-top-right-radius: 12px;
442
+ overflow: hidden;
443
+ }
444
+ .app-manager .app-manager-plan-page .VueCarousel-inner .VueCarousel-slide.last-slide
445
+ {
446
+ border-top-right-radius: 12px;
447
+ }
448
+ .app-manager .app-manager-plan-page .VueCarousel-inner .VueCarousel-slide.first-slide
449
+ {
450
+ border-top-left-radius: 12px;
451
+ }
452
+ .app-manager .app-manager-plan-page .VueCarousel .VueCarousel-inner li
453
+ {
454
+ text-align: center;
455
+ }
456
+ .app-manager .app-manager-plan-page .VueCarousel-navigation-button
457
+ {
458
+ color: #257f60;
459
+ }
460
+
461
+ </style>