@hulkapps/app-manager-vue 3.1.23 → 3.2.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.
@@ -1,949 +0,0 @@
1
- <template>
2
- <!-- <PSkeletonPage :title="translateMe('Plans')"-->
3
- <!-- :fullWidth="false"-->
4
- <!-- primaryAction-->
5
- <!-- :secondaryActions="2"-->
6
- <!-- :breadcrumbs="false"-->
7
- <!-- v-if="planLoading">-->
8
- <!-- <PLayout>-->
9
- <!-- <PLayoutSection oneThird="">-->
10
- <!-- <PCard sectioned="">-->
11
- <!-- <PTextContainer>-->
12
- <!-- <PSkeletonDisplayText size="small" />-->
13
- <!-- <PSkeletonBodyText />-->
14
- <!-- </PTextContainer>-->
15
- <!-- </PCard>-->
16
- <!-- </PLayoutSection>-->
17
- <!-- <PLayoutSection oneThird="">-->
18
- <!-- <PCard sectioned="">-->
19
- <!-- <PTextContainer>-->
20
- <!-- <PSkeletonDisplayText size="small" />-->
21
- <!-- <PSkeletonBodyText />-->
22
- <!-- </PTextContainer>-->
23
- <!-- </PCard>-->
24
- <!-- </PLayoutSection>-->
25
- <!-- <PLayoutSection oneThird="">-->
26
- <!-- <PCard sectioned="">-->
27
- <!-- <PTextContainer>-->
28
- <!-- <PSkeletonDisplayText size="small" />-->
29
- <!-- <PSkeletonBodyText />-->
30
- <!-- </PTextContainer>-->
31
- <!-- </PCard>-->
32
- <!-- </PLayoutSection>-->
33
- <!-- </PLayout>-->
34
- <!-- <PLayout style="margin-top: 20px">-->
35
- <!-- <PLayoutSection>-->
36
- <!-- <PCard sectioned=""><PSkeletonBodyText /></PCard>-->
37
- <!-- <PCard sectioned=""><PSkeletonBodyText /></PCard>-->
38
- <!-- <PCard sectioned=""><PSkeletonBodyText /></PCard>-->
39
- <!-- <PCard sectioned=""><PSkeletonBodyText /></PCard>-->
40
- <!-- </PLayoutSection>-->
41
- <!-- </PLayout>-->
42
- <!-- </PSkeletonPage>-->
43
- <PEmptyState
44
- :heading="translateMe('No plans')"
45
- image="https://cdn.shopify.com/s/files/1/0262/4071/2726/files/emptystate-files.png"
46
- v-if="!this.planLoading && this.plans.length === 0"
47
- />
48
-
49
- <div v-else-if="!this.planLoading && this.plans.length > 0"> <PlanBanners position="header" @handlePlanBannerClose="handlePlanBannerClose" />
50
-
51
- <PPage
52
- class="app-manager-plan-page custom-title"
53
- :title="selectedPlan === 'bundle' ? '' : translateMe('Plans')"
54
- :subtitle="selectedPlan === 'bundle' ? '' : subtitleContent"
55
- >
56
-
57
- <PStack slot="primaryAction">
58
- <PStackItem style="margin-top: 20px">
59
- <!-- <PButtonGroup class="btn-group" segmented> -->
60
- <!-- <PButton v-if="monthlyPlan.length && yearlyPlan.length" :class="selectedPlan === 'monthly' ? 'plan-active-tab' : '' " :style="selectedPlan === 'monthly' ? monthlySelectedStyle : monthlyStyle " @click="selectPlan('monthly')">
61
- <p style="font-size: 17px; font-weight: 500" slot="default">{{translateMe('Monthly')}}</p>
62
- </PButton>
63
-
64
- <PButton v-if="yearlyPlan.length && monthlyPlan.length" :class="selectedPlan === 'annually'? 'plan-active-tab' : '' " :style="selectedPlan === 'annually' ? yearlySelectedStyle : yearlyStyle " @click="selectPlan('annually')" :primary="selectedPlan === 'annually' " >
65
- <YearlyPlanPromotion />
66
- </PButton> -->
67
- <div class="button-group-new">
68
- <VariantButton id="pricing-tab" :variant="selectedPlan === 'monthly' ? 'primary' : 'secondary'" @click="selectPlan('monthly')" :additionalText="'1 App'">
69
- {{ translateMe('Monthly') }}
70
- </VariantButton>
71
- <VariantButton id="pricing-tab" v-if="valid_annual_plans.length > 0" :variant="selectedPlan === 'annually' ? 'primary' : 'secondary'" @click="selectPlan('annually')">
72
- {{ translateMe('Annually') }}
73
- </VariantButton>
74
- <VariantButton id="pricing-tab" v-if="bundle_plan !== null" :variant="selectedPlan === 'bundle' ? 'primary' : 'secondary'" @click="selectPlan('bundle')" :additionalText=" totalBundleApps +' Apps'">
75
- {{ translateMe('Bundle') }}
76
- </VariantButton>
77
- </div>
78
- <!-- </PButtonGroup> -->
79
- </PStackItem>
80
- </PStack>
81
- <!-- <hr style="width: 100%; margin-right: auto;margin-left: auto;margin-bottom: 20px;" /> -->
82
- <div class="light-divider" style="margin: 20px 0;"></div>
83
- <!--=======================================================-->
84
- <PLayout class="custom-plan">
85
- <PLayoutSection>
86
- <template style="margin-bottom: 20px;">
87
- <template>
88
- <PDataTable class="plan-table">
89
- <template slot="head">
90
- <PDataTableRow v-if="selectedPlan === 'monthly'" style="box-shadow: none!important;">
91
- <PDataTableCol style="opacity: 0;visibility: hidden;border: 0 !important;" class="plan-heading">
92
- <b>{{translateMe('features')}}</b>
93
- </PDataTableCol>
94
- <template v-for="(plan, key) in monthlyPlan" >
95
- <PDataTableCol :class="{'first-column': key === 0, 'plan-heading': true, 'last-column': (key+1) === monthlyPlan.length}" :style="activePlanStyle(plan)">
96
- <b v-if="plan.name !== 'Free'" style="font-size: 16px">{{translateMe(plan.name)}}</b>
97
- <div v-if="plan.price === 0">
98
- <p style="display: flex;margin-top: 10px">
99
- <PHeading style="font-size: 25px;font-weight: 700;">{{ translateMe('Free') }}</PHeading>
100
- </p>
101
- </div>
102
- <div v-else-if="plan.discount && plan.discount > 0 && !isCurrentPlan(plan)" >
103
- <p style="display: flex;margin-top: 10px">
104
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(calculateDiscountedPrice(plan)).toFixed(2)}}</PHeading>
105
- <b style="margin-top: 5px;font-size: 17px">/{{translateMe("mo")}}</b>
106
- </p>
107
- <p style="display: flex;margin-top: 7px">
108
- <PHeading style="font-size: 18px;font-weight: 500; text-decoration:line-through;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
109
- <b style="margin-top: 3px;font-size: 14px">/{{translateMe("mo")}}</b>
110
- </p>
111
- </div>
112
- <div v-else-if="promotional_discount && promotional_discount.length !== 0 && !promotional_discount.errors && !plan.is_global && promotional_discount.plan_relation.length > 0 && promotional_discount.plan_relation.includes(plan.id) && !isCurrentPlan(plan)" >
113
- <p style="display: flex;margin-top: 10px">
114
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(calculatePromotionalDiscountedPrice(plan, promotional_discount)).toFixed(2)}}</PHeading>
115
- <b style="margin-top: 5px;font-size: 17px">/{{translateMe("mo")}}</b>
116
- </p>
117
- <p style="display: flex;margin-top: 7px">
118
- <PHeading style="font-size: 18px;font-weight: 500; text-decoration:line-through;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
119
- <b style="margin-top: 3px;font-size: 14px">/{{translateMe("mo")}}</b>
120
- </p>
121
- </div>
122
- <div v-else-if="promotional_discount && promotional_discount.length !== 0 && !promotional_discount.errors && !plan.is_global && promotional_discount.plan_relation.length === 0 && promotional_discount.value > 0 && !isCurrentPlan(plan)" >
123
- <p style="display: flex;margin-top: 10px">
124
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(calculatePromotionalDiscountedPrice(plan, promotional_discount)).toFixed(2)}}</PHeading>
125
- <b style="margin-top: 5px;font-size: 17px">/{{translateMe("mo")}}</b>
126
- </p>
127
- <p style="display: flex;margin-top: 7px">
128
- <PHeading style="font-size: 18px;font-weight: 500; text-decoration:line-through;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
129
- <b style="margin-top: 3px;font-size: 14px">/{{translateMe("mo")}}</b>
130
- </p>
131
- </div>
132
- <div v-else>
133
- <p style="display: flex;margin-top: 10px">
134
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
135
- <b style="margin-top: 5px;font-size: 17px">/{{translateMe("mo")}}</b>
136
- </p>
137
- </div>
138
- </PDataTableCol>
139
- </template>
140
- </PDataTableRow>
141
- <PDataTableRow v-else>
142
- <PDataTableCol style="opacity: 0;visibility: hidden; border: 0 !important;" class="plan-heading">
143
- <b>{{translateMe('features')}}</b>
144
- </PDataTableCol>
145
- <template v-for="(plan,key) in yearlyPlan">
146
- <PDataTableCol :class="{'first-column': key === 0, 'plan-heading': true, 'last-column': (key+1) === yearlyPlan.length}" :style="activePlanStyle(plan)">
147
- <b v-if="plan.name !== 'Free'" style="font-size: 16px">{{translateMe(plan.name)}}</b>
148
- <div v-if="plan.price === 0">
149
- <p style="display: flex;margin-top: 10px">
150
- <PHeading style="font-size: 25px;font-weight: 700;">{{ translateMe('Free') }}</PHeading>
151
- </p>
152
- </div>
153
- <div v-else-if="plan.discount && plan.discount > 0 && !isCurrentPlan(plan)" >
154
- <p style="display: flex;margin-top: 10px">
155
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(calculateDiscountedPrice(plan)).toFixed(2)}}</PHeading>
156
- <b style="margin-top: 5px;font-size: 17px">/{{translateMe("year")}}</b>
157
- </p>
158
- <p style="display: flex;margin-top: 7px">
159
- <PHeading style="font-size: 18px;font-weight: 500; text-decoration:line-through;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
160
- <b style="margin-top: 3px;font-size: 14px">/{{translateMe("year")}}</b>
161
- </p>
162
- </div>
163
- <div v-else-if="promotional_discount && promotional_discount.length !== 0 && !promotional_discount.errors && promotional_discount.plan_relation.length > 0 && promotional_discount.plan_relation.includes(plan.id) && !isCurrentPlan(plan)">
164
- <p style="display: flex;margin-top: 10px">
165
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(calculatePromotionalDiscountedPrice(plan, promotional_discount)).toFixed(2)}}</PHeading>
166
- <b style="margin-top: 5px;font-size: 17px">/{{translateMe("year")}}</b>
167
- </p>
168
- <p style="display: flex;margin-top: 7px">
169
- <PHeading style="font-size: 18px;font-weight: 500; text-decoration:line-through;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
170
- <b style="margin-top: 3px;font-size: 14px">/{{translateMe("year")}}</b>
171
- </p>
172
- </div>
173
- <div v-else-if="promotional_discount && promotional_discount.length !== 0 && !promotional_discount.errors && promotional_discount.plan_relation.length === 0 && promotional_discount.value > 0 && !isCurrentPlan(plan)" >
174
- <p style="display: flex;margin-top: 10px">
175
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(calculatePromotionalDiscountedPrice(plan, promotional_discount)).toFixed(2)}}</PHeading>
176
- <b style="margin-top: 5px;font-size: 17px">/{{translateMe("year")}}</b>
177
- </p>
178
- <p style="display: flex;margin-top: 7px">
179
- <PHeading style="font-size: 18px;font-weight: 500; text-decoration:line-through;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
180
- <b style="margin-top: 3px;font-size: 14px">/{{translateMe("year")}}</b>
181
- </p>
182
- </div>
183
- <div v-else>
184
- <p style="display: flex;margin-top: 10px">
185
- <PHeading style="font-size: 25px;font-weight: 700;">${{parseFloat(plan.price).toFixed(2)}}</PHeading>
186
- <b style="margin-top: 5px;font-size: 17px">/{{translateMe("year")}}</b>
187
- </p>
188
- </div>
189
- </PDataTableCol>
190
- </template>
191
- </PDataTableRow>
192
- </template>
193
- <template slot="body">
194
- <template v-for="(featureGroup, groupKey) in featuresByGroup">
195
- <PDataTableRow v-if="groupKey !== 'null'" class="app-manager-group-row">
196
- <PDataTableCol :colspan="selectedPlan === 'monthly' ? monthlyPlan.length + 1 : yearlyPlan.length + 1" class="app-manager-group-cell">{{ translateMe(groupKey) }}</PDataTableCol>
197
- </PDataTableRow>
198
- <PDataTableRow v-for="(feature, rIndex) in featureGroup" :key="`row-${rIndex + groupKey}`">
199
- <PDataTableCol :class="`feature__type__${feature.value_type} feature__class`">{{ translateMe(feature.name) }}</PDataTableCol>
200
- <PDataTableCol :class="`feature__type__${feature.value_type}`" v-for="(plan, cIndex) in selectedPlan === 'monthly' ? monthlyPlan : yearlyPlan" :key="`cell-${cIndex}-row-${rIndex}`" :style="activePlanStyle(plan)">
201
- <template v-if="plan.features">
202
- <template v-if="feature.value_type === 'boolean'">
203
- <PIcon v-if="plan.features[feature.uuid]" color="success"
204
- source="TickMinor"/>
205
- <PIcon v-else color="subdued" source="MinusMinor"/>
206
- </template>
207
- <template v-else>
208
- <span v-if="plan.features[feature.uuid]">{{ translateMe(format(plan.features[feature.uuid])) }}</span>
209
- <PIcon v-else color="subdued" source="MinusMinor"/>
210
- </template>
211
- </template>
212
- <template v-else>
213
- <PIcon color="subdued" source="MinusMinor"/>
214
- </template>
215
- </PDataTableCol>
216
- </PDataTableRow>
217
- </template>
218
- <PDataTableRow v-if="plans.length" class="row-alignment" >
219
- <PDataTableCol></PDataTableCol>
220
- <PDataTableCol v-for="(plan, cIndex) in selectedPlan === 'monthly' ? monthlyPlan : yearlyPlan" :key="`cell-${cIndex}-row-plan`" style="max-width: 0" >
221
- <PButton v-if="isCurrentPlan(plan)" :disabled="isCurrentPlan(plan)"
222
- full-width
223
- :pressed="isCurrentPlan(plan)">
224
- {{ translateMe('Current plan') }}
225
- </PButton>
226
- <PButton v-else-if="(!plan.store_base_plan || plan.shopify_plans.includes(shop.shopify_plan))"
227
- full-width
228
- :disabled="isActivePlanGlobal() && !isActiveGlobalCharge()"
229
- @click="plan ? getPlanUrl(plan) : 'javascript:void'"
230
- class="custom-choose-button">
231
- {{ isActivePlanGlobal() ? (!isActiveGlobalCharge() ? translateMe('Not applicable') : translateMe('Choose plan')) : translateMe('Choose plan') }}
232
- </PButton>
233
- <PButton v-else :disabled="true"
234
- full-width
235
- :pressed="true">
236
- {{ translateMe('Not applicable') }}
237
- </PButton>
238
- <PTextContainer v-if="plan.store_base_plan && shop.plan && plan.shopify_plans.includes(shop.shopify_plan) && !isCurrentPlan(plan)" class="footer-note-container">
239
- <PTextStyle class="text-break" v-if="plan.store_base_plan && !plan.shopify_plans.includes(shop.shopify_plan) && !(isCurrentPlan(plan)) && !isSamePlanInOtherInterval(plan)">{{ translateMe('Note: On account of your recent Shopify plan upgrade, you should consider upgrading your current app plan')}}</PTextStyle>
240
- </PTextContainer>
241
- </PDataTableCol>
242
- </PDataTableRow>
243
- </template>
244
- </PDataTable>
245
- </template>
246
- </template>
247
- <PStack v-if="onboard" class="choose-plan-btn" alignment="center" distribution="center" vertical>
248
- <PStackItem fill>
249
- <PButton plain @click="activePlan">{{ translateMe('I will choose the plan later') }}</PButton>
250
- </PStackItem>
251
- </PStack>
252
- <PlanBanners position="footer" @handlePlanBannerClose="handlePlanBannerClose" />
253
- </PLayoutSection>
254
- </PLayout>
255
- <div v-if="bundle_plan !== null" class="bundle-plan">
256
- <PlanShowcaseBanner useCardStyle="true" :bundleApps="totalBundleApps" :showcaseData="bundle_plan" :realPrice="parseFloat(calculateDiscountedPrice(bundle_plan)).toFixed(0)" :oldPrice="bundle_plan.price" @plan-clicked="handlePlanClicked(bundle_plan)" :isCurrentPlan="isCurrentPlanId(bundle_plan)"/>
257
- <div class="light-divider"></div>
258
- <div class="bundle-category" v-for="category in bundle_details">
259
- <CategoryHeading :headingData="category" />
260
- <div class="bundle-category-apps">
261
- <AppCard v-for="app in category.apps_relation" :appData="app" />
262
- </div>
263
- </div>
264
- <CategoryHeading :headingData="additionalBenefitsHeading" />
265
- <BenefitsBanner />
266
- <PlanShowcaseBanner style="margin-top: 20px;" :bundleApps="totalBundleApps" :showcaseData="bundle_plan" :realPrice="parseFloat(calculateDiscountedPrice(bundle_plan)).toFixed(0)" :oldPrice="bundle_plan.price" :showDescription="false" :isCurrentPlan="isCurrentPlanId(bundle_plan)" @plan-clicked="handlePlanClicked(bundle_plan)"/>
267
- </div>
268
- <!--====================================================================-->
269
- </PPage>
270
- </div>
271
- </template>
272
-
273
- <script>
274
-
275
- import axios from "axios";
276
- import PlanBanners from "./PlanBanners";
277
- import YearlyPlanPromotion from "./YearlyPlanPromotion";
278
- import PPage from "../polaris-vue/src/components/PPage/PPage";
279
- import PStack from "../polaris-vue/src/components/PStack/PStack";
280
- import PStackItem from "../polaris-vue/src/components/PStack/components/PStackItem/PStackItem";
281
- import {PButton} from "../polaris-vue/src/components/PButton";
282
- import {PButtonGroup} from "../polaris-vue/src/components/PButtonGroup";
283
- import {PHeading} from "../polaris-vue/src/components/PHeading";
284
- import {PLayout} from "../polaris-vue/src/components/PLayout";
285
- import {PLayoutSection} from "../polaris-vue/src/components/PLayout/components/PLayoutSection";
286
- import {PTextContainer} from "../polaris-vue/src/components/PTextContainer";
287
- import {PDataTable} from "../polaris-vue/src/components/PDataTable";
288
- import {PDataTableCol} from "../polaris-vue/src/components/PDataTable/components/PDataTableCol";
289
- import {PDataTableRow} from "../polaris-vue/src/components/PDataTable/components/PDataTableRow";
290
- import {PIcon} from "../polaris-vue/src/components/PIcon";
291
- import {PCard} from "../polaris-vue/src/components/PCard"
292
- import {PCardSection} from "../polaris-vue/src/components/PCard/components/PCardSection"
293
- import {PSkeletonPage} from "../polaris-vue/src/components/PSkeletonPage"
294
- import {PSkeletonDisplayText} from "../polaris-vue/src/components/PSkeletonDisplayText"
295
- import {PSkeletonBodyText} from "../polaris-vue/src/components/PSkeletonBodyText"
296
- import {PTextStyle} from "../polaris-vue/src/components/PTextStyle";
297
- import {PEmptyState} from "../polaris-vue/src/components/PEmptyState";
298
- import AppCard from "../PolarisNew/AppCard";
299
- import PlanShowcaseBanner from "../PolarisNew/PlanShowcaseBanner";
300
- import CategoryHeading from "../PolarisNew/CategoryHeading";
301
- import BenefitsBanner from "../PolarisNew/BenefitsBanner";
302
- import VariantButton from "../PolarisNew/VariantButton";
303
-
304
- export default {
305
- name: "AppManagerGroupPlan",
306
- components: { YearlyPlanPromotion, PlanBanners, PPage, PStack, PStackItem, PButton, PButtonGroup, PHeading, PLayout, PLayoutSection, PTextContainer, PDataTable, PDataTableCol, PDataTableRow, PIcon, PTextStyle, PCard, PCardSection, PSkeletonPage, PSkeletonBodyText, PSkeletonDisplayText, PEmptyState, AppCard, PlanShowcaseBanner, CategoryHeading, BenefitsBanner, VariantButton },
307
- props: ['shop_domain','host', 'discount_code'],
308
- data() {
309
- return {
310
- plan: {},
311
- plans: [],
312
- valid_annual_plans: [],
313
- promotional_discount: [],
314
- features: [],
315
- featureValues: [],
316
- featuresByGroup: [],
317
- shopify_plan: '',
318
- default_plan_id: null,
319
- onboard: true,
320
- choose_later: false,
321
- has_active_charge: false,
322
- global_plan_charge: false,
323
- planLoading: false,
324
- subtitleContent: '',
325
- checkList: [
326
- "60 days free trial",
327
- ],
328
- selectedPlan:'monthly',
329
- monthlySelectedStyle:{
330
- height: '60px',
331
- backgroundColor:'#257f60',
332
- color:'#fff',
333
- position:'relative',
334
- right:'-5px',
335
- borderRadius:'8px',
336
- zIndex: 1,
337
- },
338
- yearlySelectedStyle:{
339
- height: '60px',
340
- backgroundColor:'#257f60',
341
- position:'relative',
342
- left:'-5px',
343
- borderRadius:'8px'
344
- },
345
- monthlyStyle:{
346
- height: '55px',
347
- backgroundColor:'#FFFFFF',
348
- boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px',
349
- border:'none',
350
- borderRadius:'8px',
351
- ZIndex: 11,
352
- },
353
- yearlyStyle:{
354
- color:'#258060',
355
- height: '55px',
356
- backgroundColor:'#FFFFFF',
357
- boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px',
358
- border:'none',
359
- borderRadius:'8px'
360
- },
361
- bundleStyle:{
362
- color:'#258060',
363
- height: '55px',
364
- backgroundColor:'#FFFFFF',
365
- boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px',
366
- border:'none',
367
- borderRadius:'8px'
368
- },
369
- additionalBenefitsHeading:{
370
- category_name: "Unlock Additional Benefits"
371
- },
372
- "bundle_details": null,
373
- "bundle_plan": null
374
- }
375
- },
376
- computed: {
377
- shop() {
378
- return {
379
- "name": this.shop_domain,
380
- "shopify_plan": this.shopify_plan,
381
- "has_plan": !!this.plan,
382
- "plan": this.plan,
383
- "default_plan_id": this.default_plan_id,
384
- };
385
- },
386
- headings() {
387
- let headings = [this.translateMe('Plans & features')];
388
- this.plans.forEach(plan => {
389
-
390
- let heading = (plan.name);
391
- if (plan.price > 0) heading += ` ($${plan.price}/` + this.translateMe('mo') + ')';
392
- headings.push(heading);
393
- });
394
- return headings;
395
- },
396
- monthlyPlan() {
397
- const plans = [];
398
- for(let planKey in this.plans) {
399
- if(this.plans[planKey].interval === 'EVERY_30_DAYS') {
400
- plans.push(this.plans[planKey]);
401
- }
402
- }
403
- return plans;
404
- },
405
- yearlyPlan() {
406
- const plans = [];
407
- for(let planKey in this.plans) {
408
- if(this.plans[planKey].interval === 'ANNUAL') {
409
- plans.push(this.plans[planKey]);
410
- }
411
- }
412
- return plans;
413
- },
414
- totalBundleApps() {
415
- let totalApps = 0;
416
- if (this.bundle_details) {
417
- this.bundle_details.forEach(category => {
418
- totalApps += category.apps_relation.length;
419
- });
420
- }
421
- return totalApps;
422
- }
423
- },
424
- methods: {
425
- translateMe(message) {
426
- return this.$translations.hasOwnProperty(message) ? this.$translations[message] : message;
427
- },
428
- activePlanStyle(plan) {
429
- return [plan.shopify_plans.includes(this.shop.shopify_plan) || !plan.store_base_plan ? {backgroundColor: '#FFF', color: '#202223'} : {}];
430
- },
431
- isCurrentPlan(plan) {
432
- return this.has_active_charge && this.shop.plan && (plan.id === this.shop.plan.id || (!plan.is_custom && plan.base_plan === this.shop.plan.id));
433
- },
434
- isCurrentPlanId(plan) {
435
- return this.shop.plan && plan.id === this.shop.plan.id;
436
- },
437
- isActivePlanGlobal() {
438
- return Boolean(this.shop.plan?.is_global);
439
- },
440
- isActiveGlobalCharge() {
441
- return Boolean(this.global_plan_charge);
442
- },
443
- isSamePlanInOtherInterval(plan) {
444
- return this.shop.plan && (plan.shopify_plans === this.shop.plan.shopify_plans)
445
- },
446
- format(feature) {
447
- if (['double', 'integer'].includes(feature?.value_type)) {
448
- if (feature.format === 'percentage') {
449
- return `${feature.value}%`
450
- } else if (feature.format === 'count') {
451
- return (feature.value < 0 ? this.translateMe(`Unlimited`) : feature.value)
452
- } else return feature.value
453
- }
454
- else if(feature?.value_type === 'array') {
455
- let values= JSON.parse(feature.value);
456
- let that = this;
457
- values = values.map(function(value){
458
- return that.translateMe(that.featureValues[feature.feature_id][value]);
459
- });
460
- return values.join(', ')
461
- }
462
- else if(feature?.value_type === 'string') {
463
- return this.translateMe(feature.value.replace('"', '').replace('"', ''));
464
- }
465
- },
466
- calculateDiscountedPrice(plan) {
467
- if (plan.discount_type === 'percentage') {
468
- return plan.price - (plan.price * plan.discount)/100
469
- }
470
- else if (plan.discount_type === 'amount') {
471
- if(plan.discount > plan.price){
472
- return 0.00;
473
- }
474
- return plan.price - plan.discount
475
- }
476
- },
477
- calculatePromotionalDiscountedPrice(plan, promotional_discount) {
478
- if (promotional_discount.type === 'percentage') {
479
- return plan.price - (plan.price * promotional_discount.value)/100
480
- }
481
- else if (promotional_discount.type === 'amount') {
482
- if(promotional_discount.value > plan.price){
483
- return 0.00;
484
- }
485
- return plan.price - promotional_discount.value
486
- }
487
- },
488
- headerClasses(firstColumn) {
489
- return {
490
- 'Polaris-DataTable__Cell': true,
491
- 'Polaris-DataTable__Cell--header': true,
492
- 'Polaris-DataTable__Cell--verticalAlignMiddle': true,
493
- 'Polaris-DataTable__Cell--firstColumn': Boolean(firstColumn),
494
- };
495
- },
496
- groupBy(objectArray, property) {
497
- return objectArray.reduce((acc, obj) => {
498
- const key = obj[property];
499
- if (!acc[key]) {
500
- acc[key] = [];
501
- }
502
- acc[key].push(obj);
503
- return acc;
504
- }, {});
505
- },
506
- async getPlanUrl(plan) {
507
- let shopName = this.shop.name;
508
- let host = this.host;
509
- let discount_code = this.discount_code;
510
- let queryString = `shop=${shopName}`;
511
- if(host != null){
512
- queryString +=`&host=${host}`
513
- }
514
- if(discount_code != null){
515
- queryString +=`&discount_code=${discount_code}`
516
- }
517
- const response = await axios.get(`${this.app_manager_config.baseUrl}/api/app-manager/plan/process/${plan.id}?${queryString}`).catch(error => {
518
- console.error(error)
519
- });
520
- if(response.data.plan_type === 'free_plan'){
521
- this.$emit('handlePlanSelect', {free_plan: true})
522
- }else{
523
- let redirectUrl = response.data.redirect_url;
524
- if (redirectUrl) {
525
- window.top.location.href = redirectUrl;
526
- }
527
- }
528
- },
529
- async activePlan() {
530
- const response = await this.activeWithoutPlan()
531
- if (response.data.status === true && this.onboard) {
532
- // Create the event
533
- this.$emit('handlePlanSelect', {choose_later: true})
534
- this.onboard = false;
535
- }
536
- },
537
- async activeWithoutPlan() {
538
- return await axios.post(`${this.app_manager_config.baseUrl}/api/app-manager/active-without-plan`, {
539
- shop_domain: this.shop.name,
540
- plan_id: this.shop.default_plan_id
541
- }).catch(error => {
542
- console.error(error)
543
- });
544
- },
545
- async selectPlan(value){
546
- this.selectedPlan= value;
547
- if (this.bundle_plan !== null) {
548
- let planElement = document.querySelector('.custom-plan');
549
- let bundleElement = document.querySelector('.bundle-plan');
550
- if (this.selectedPlan == 'bundle') {
551
- planElement.style.display = 'none';
552
- bundleElement.style.display = 'flex';
553
- } else {
554
- bundleElement.style.display = 'none';
555
- planElement.style.display = 'flex';
556
- }
557
- }
558
- },
559
- async fetchFeatures() {
560
- let {data} = await axios.get(`${this.app_manager_config.baseUrl}/api/app-manager/plan-features`).catch(error => {
561
- console.error(error)
562
- });
563
- if (data.features.length) {
564
- this.features = data.features;
565
- this.features = this.features?.filter((item) => item.hidden_feature !== true)
566
- this.features = this.features?.sort((featureA, featureB) => parseInt(featureA.display_order) - parseInt(featureB.display_order))
567
- this.features = this.features?.sort((featureA, featureB) => parseInt(featureA.group_order) - parseInt(featureB.group_order))
568
- this.featuresByGroup = this.groupBy(this.features, 'group')
569
-
570
- //Get feature array time values
571
- this.features.forEach((feature) => {
572
- if(feature.value_type == 'array'){
573
- this.featureValues[feature.uuid] = feature.values;
574
- }
575
- });
576
- }
577
- },
578
- async fetchPlans() {
579
- let params = {
580
- 'shop_domain': this.shop_domain
581
- };
582
- if (this.discount_code !== null) {
583
- params['discount_code'] = this.discount_code;
584
- }
585
- let {data} = await axios.get(`${this.app_manager_config.baseUrl}/api/app-manager/plans`, { params: params }).catch(error => {
586
- console.error(error)
587
- });
588
- if (data.plans.length) {
589
- for (let i = 0; i < data.plans.length; i++) {
590
- if (data.plans[i].interval === 'ANNUAL') {
591
- this.valid_annual_plans.push(data.plans[i]);
592
- }
593
- }
594
- this.plans = data.plans;
595
- this.plans = this.plans?.sort((planA, planB) => parseFloat(planA.price) - parseFloat(planB.price));
596
-
597
- if (this.plans[0].store_base_plan) {
598
- this.subtitleContent = this.translateMe('App plans are based on your existing shopify plan');
599
- }
600
-
601
- this.plan = data.plan;
602
- if (this.plan?.interval === 'ANNUAL') {
603
- this.selectedPlan = 'annually'
604
-
605
- }
606
- if (this.plan?.is_global) {
607
- this.selectedPlan = 'bundle'
608
- }
609
- this.shopify_plan = data.shopify_plan;
610
- this.default_plan_id = data.default_plan_id;
611
- this.choose_later = data.choose_later;
612
- this.onboard = this.default_plan_id && this.choose_later;
613
- this.has_active_charge = data.has_active_charge;
614
- this.global_plan_charge = data.global_plan_charge;
615
- this.promotional_discount = (data.promotional_discount !== undefined)?data.promotional_discount:[];
616
- if (data.bundle_plan) {
617
- this.bundle_plan = data.bundle_plan;
618
- }
619
- if (data.bundle_details) {
620
- this.bundle_details = data.bundle_details;
621
- }
622
- }
623
- },
624
- /*cellColor(plan) {
625
- let greenCell = { backgroundColor: 'rgb(240, 248, 245)',color: 'rgb(37, 127, 96)'};
626
- let disableCell = { backgroundColor: '#fafbfb',color: 'rgb(37, 127, 96)'};
627
- if(this.has_active_charge && this.shop.plan){
628
- if((plan.id === this.shop.plan.id || (!plan.is_custom && plan.base_plan === this.shop.plan.id))){
629
- return disableCell;
630
- }else if(plan.price > this.shop.plan.price){
631
- return greenCell;
632
- }
633
- }
634
- return;
635
- },*/
636
- isPlanButtonColor(plan){
637
- if(this.has_active_charge && this.shop.plan){
638
- if(plan.price > this.shop.plan.price){
639
- return true;
640
- }
641
- }
642
- return false;
643
- },
644
- planChooseButtonClass(plan){
645
- if(this.has_active_charge && this.shop.plan){
646
- if(plan.price > this.shop.plan.price){
647
- return '';
648
- }
649
- }
650
- return 'custom-choose-button';
651
- },
652
- handlePlanBannerClose(payload) {
653
- this.$emit('handlePlanBannerClose', payload)
654
- this.$emit('handle-plan-banner-close', payload)
655
- },
656
- handlePlanClicked(plan) {
657
- this.getPlanUrl(plan);
658
- }
659
- },
660
- async mounted() {
661
- this.planLoading = true;
662
- await this.fetchFeatures();
663
- await this.fetchPlans();
664
- this.planLoading = false;
665
-
666
- this.$nextTick(() => {
667
- this.selectPlan(this.selectedPlan);
668
-
669
- });
670
-
671
- }
672
- }
673
- </script>
674
-
675
- <style lang="scss">
676
-
677
- @import url('https://fonts.googleapis.com/css2?family=Satisfy&display=swap');
678
-
679
- .app-manager .app-manager-plan-page .plan-table td:last-child>*[data-v-7d902277],
680
- .app-manager .app-manager-plan-page .plan-table td:last-child>*[data-v-5a078dbb] {
681
- float:none;
682
- }
683
- .app-manager .app-manager-plan-page .active {
684
- background: #f0f8f5;
685
- }
686
- .app-manager .app-manager-plan-page .plan-table td:last-child>*[data-v-0d1b0d63] {
687
- float:none;
688
- }
689
- .app-manager .app-manager-plan-page .plan-table td {
690
- border: 0.01px solid #ececee !important;
691
- border-collapse: collapse !important;
692
- }
693
- .app-manager .app-manager-plan-page .plan-table .Polaris-DataTable__ScrollContainer{
694
- border-radius:12px;
695
- overflow: visible;
696
- }
697
- .app-manager .app-manager-plan-page .plan-table table {
698
- border-collapse: collapse !important;
699
- }
700
- .app-manager .app-manager-plan-page .custom-plan table {
701
- border-collapse: collapse !important;
702
- }
703
- .app-manager .app-manager-plan-page .custom-plan table thead .first-column {
704
- border-radius: 12px 0 0 0;
705
- border-top: 0px !important;
706
- border-left: 0px !important;
707
- }
708
- .app-manager .app-manager-plan-page .custom-plan table thead .plan-heading.last-column {
709
- text-align: left !important;
710
- border-radius: 0 12px 0 0;
711
- border-top: 0px !important;
712
- }
713
- .app-manager .app-manager-plan-page .custom-plan table thead .plan-heading {
714
- background-color: rgb(255, 255, 255);
715
- box-shadow: rgb(23 24 24 / 5%) 1px 0px 8px, rgb(0 0 0 / 15%) 0px 0px 2px;
716
- }
717
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:first-child {
718
- background-color: #fff;
719
- box-shadow: 0 0 5px rgb(23 24 24 / 5%), 0 1px 2px rgb(0 0 0 / 15%);
720
- border-radius: 12px 0 0 0;
721
- overflow: hidden;
722
- }
723
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:not(:first-child :last-child ) {
724
- background-color: #fff;
725
- overflow: hidden;
726
- }
727
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:not(:first-child :last-child) {
728
- background-color: #fff;
729
- box-shadow: 0 0 5px rgb(23 24 24 / 5%), 0 1px 2px rgb(0 0 0 / 15%);
730
- overflow: hidden;
731
- }
732
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:not( :nth-last-child(2) ) {
733
- background-color: #fff;
734
- overflow: hidden;
735
- }
736
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:not( :nth-last-child(2) ) {
737
- border-bottom: 0;
738
- }
739
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:last-child {
740
- border-bottom: 0;
741
- background-color: transparent !important;
742
- box-shadow: none !important;
743
- }
744
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:not(:last-child) {
745
- pointer-events: none;
746
- }
747
- .app-manager .app-manager-plan-page .custom-plan table thead tr td{
748
- pointer-events: none;
749
- }
750
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:first-child td:first-child {
751
- overflow: hidden;
752
- border-radius: 12px 0 0 0;
753
- }
754
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:nth-last-child(2) {
755
- overflow: hidden;
756
- border-bottom-right-radius: 0;
757
- border-bottom-left-radius: 12px;
758
- }
759
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:nth-last-child(2) td:first-child {
760
- overflow: hidden;
761
- border-bottom: 0px !important;
762
- border-radius: 0 0 0 12px;
763
- }
764
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:nth-last-child(2) td:last-child {
765
- overflow: hidden;
766
- border-radius: 0 0 0;
767
- }
768
- .app-manager .app-manager-plan-page .custom-plan table tbody tr td:first-child {
769
- border-left: 0px !important;
770
- border-top: 0px !important;
771
- padding-left: 20px;
772
- }
773
- .app-manager .app-manager-plan-page .custom-plan table tbody tr td:last-child {
774
- text-align: center !important;
775
- }
776
- .app-manager .app-manager-plan-page .custom-plan table thead tr td:last-child {
777
-
778
- text-align: center !important;
779
- }
780
- .app-manager .app-manager-plan-page .custom-plan table tbody td:not(:first-child) {
781
- text-align: center !important;
782
- }
783
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:last-child td:last-child {
784
- background: transparent;
785
- border-radius: 0 0 12px 0;
786
- }
787
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:last-child td:nth-child(2){
788
- border-radius: 0 0 0 12px !important;
789
- }
790
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:last-child td {
791
- background: transparent;
792
- }
793
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:last-child td:hover {
794
- border: 0 !important;
795
- background: transparent;
796
- }
797
- .app-manager .app-manager-plan-page .custom-plan tbody tr:last-child td.Polaris-DataTable__Cell--verticalAlignTop{
798
- background: transparent !important;
799
- }
800
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:last-child {
801
- background: #fff!important;
802
- opacity:1.0;
803
- }
804
- .app-manager .app-manager-plan-page .custom-plan table tbody tr:last-child td:first-child{
805
- visibility: hidden;
806
- border-bottom: none!important;
807
- }
808
- .app-manager .app-manager-plan-page .plan-heading {
809
- padding-top: 30px;
810
- }
811
- .app-manager .app-manager-plan-page .custom-plan .Polaris-Layout__Section{
812
- max-width: calc(100% - 2rem) !important;
813
- }
814
- .app-manager .app-manager-plan-page .later-link {
815
- text-align: center;
816
- clear: both;
817
- padding-top: 15px;
818
- }
819
- .app-manager .app-manager-plan-page .plan-badge ul {
820
- text-align: center;
821
- padding-top: 2rem;
822
- border-top: 0.1rem solid #e1e3e5;
823
- }
824
- .app-manager .app-manager-plan-page .plan-badge ul li {
825
- list-style: none;
826
- display: inline-block;
827
- padding-right: 25px;
828
- }
829
- .app-manager .app-manager-plan-page .plan-badge ul li img {
830
- max-width: 133px;
831
- }
832
- .app-manager .app-manager-plan-page .btn-group .Polaris-ButtonGroup__Item{
833
- margin-left: 0px !important;
834
- z-index: unset !important;
835
- }
836
- .app-manager .Polaris-Button::after {
837
- box-shadow: none !important;
838
- }
839
- .app-manager .Polaris-Button:focus {
840
- box-shadow: none !important;
841
- border-color: black !important;
842
- }
843
- .app-manager .app-manager-plan-page.custom-title .Polaris-HorizontalDivider{
844
- background-color: #e2e3e4;
845
- }
846
- /*.app-manager .app-manager-plan-page .annual_heading{
847
- margin-top: 2px !important;
848
- color: #E2C138;
849
- border: 2px dotted #E2C138;
850
- padding: 5px;
851
- font-size: 16px !important;
852
- font-weight: normal !important;
853
- font-family: 'Satisfy', cursive;
854
- }*/
855
- .app-manager .app-manager-plan-page .Polaris-Page__Content hr{
856
- border: 1px solid #e2e3e4;
857
- }
858
-
859
- .app-manager .app-manager-plan-page .app-manager-group-row {
860
- background: transparent !important;
861
- padding: 16px 16px 16px 20px !important;
862
- }
863
-
864
- .app-manager .app-manager-plan-page .feature__type__array {
865
- vertical-align: middle !important;
866
- word-spacing: 999px;
867
- white-space: pre-line !important;
868
- }
869
-
870
- .app-manager .app-manager-plan-page .Polaris-DataTable__Table {
871
- table-layout: fixed !important;
872
- }
873
-
874
- .app-manager .app-manager-plan-page td {
875
- vertical-align: middle !important;
876
- }
877
-
878
- .app-manager .app-manager-plan-page td.feature__class {
879
- word-wrap:break-word !important;
880
- white-space: normal !important;
881
- }
882
- .app-manager .app-manager-plan-page .light-green-cell{
883
- background-color: rgb(240, 248, 245);
884
- color: rgb(37, 127, 96);
885
- }
886
-
887
- .app-manager .app-manager-plan-page .plan-heading b{
888
- overflow-wrap: break-word;
889
- word-wrap: break-word;
890
- white-space: initial;
891
- }
892
-
893
- .app-manager .app-manager-plan-page .custom-choose-button:hover{
894
- // background: #006e52;
895
- // border-color: transparent;
896
- // color: #fff;
897
- }
898
-
899
- .bundle-plan {
900
- display: none;
901
- flex-direction: column;
902
- gap: 20px;
903
- }
904
-
905
- .bundle-category {
906
- display: flex;
907
- flex-direction: column;
908
- gap: 20px;
909
- margin-bottom: 10px;
910
- }
911
-
912
- .bundle-category-apps {
913
- display: flex;
914
- flex-direction: column;
915
- gap: 10px;
916
- }
917
-
918
- .light-divider {
919
- border-top: 1px solid #E3E3E3;
920
- margin-top: 10px;
921
- margin-bottom: 10px;
922
- }
923
-
924
- .app-manager .Polaris-Icon--colorSuccess svg {
925
- fill: black !important;
926
- }
927
-
928
- .button-group-new {
929
- display: flex;
930
- align-items: center;
931
- justify-content: center;
932
- gap: 4px;
933
- }
934
-
935
- @media (min-width: 0px) and (max-width: 576px) {
936
- .app-manager .app-manager, .app-manager .app-manager-body {
937
- //overflow-x: scroll;
938
- }
939
- }
940
-
941
- @media (max-width: 700px) {
942
- .app-manager .Polaris-DataTable__Table{
943
- width: auto !important;
944
- }
945
- }
946
-
947
-
948
-
949
- </style>