mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-13 20:57:24 +01:00
* refactor sending jobs to worker server * remove unused imports * add delete button to adminpanel * June 2025 content build (#15437) * chore: June 2025 content build * chore: typo fixing * chore: corrections to summer 2025 mage armor, spritesheet * fix(css): rebuild spritesmith-main --------- Co-authored-by: Kalista Payne <sabrecat@gmail.com> * fix(script): don't use extremely costly regex * fix(logging): don't spam empty error events * Translated using Weblate (Ukrainian) Currently translated at 100.0% (134 of 134 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (280 of 280 strings) Translated using Weblate (French) Currently translated at 100.0% (280 of 280 strings) Translated using Weblate (Spanish) Currently translated at 99.6% (279 of 280 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.4% (840 of 862 strings) Translated using Weblate (German) Currently translated at 99.8% (907 of 908 strings) Translated using Weblate (Dutch) Currently translated at 79.3% (219 of 276 strings) Translated using Weblate (Dutch) Currently translated at 28.1% (69 of 245 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.4% (840 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.5% (402 of 412 strings) Translated using Weblate (Dutch) Currently translated at 91.5% (377 of 412 strings) Translated using Weblate (Dutch) Currently translated at 85.2% (774 of 908 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (908 of 908 strings) Translated using Weblate (Slovak) Currently translated at 63.4% (106 of 167 strings) Translated using Weblate (Hungarian) Currently translated at 100.0% (908 of 908 strings) Translated using Weblate (Spanish) Currently translated at 100.0% (908 of 908 strings) Translated using Weblate (Slovak) Currently translated at 2.0% (5 of 245 strings) Translated using Weblate (French) Currently translated at 100.0% (908 of 908 strings) Translated using Weblate (Russian) Currently translated at 64.4% (158 of 245 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.0% (837 of 862 strings) Translated using Weblate (German) Currently translated at 97.9% (844 of 862 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.3% (401 of 412 strings) Translated using Weblate (Portuguese) Currently translated at 95.3% (393 of 412 strings) Translated using Weblate (Slovak) Currently translated at 45.6% (413 of 905 strings) Translated using Weblate (Slovak) Currently translated at 50.8% (85 of 167 strings) Translated using Weblate (Russian) Currently translated at 99.1% (113 of 114 strings) Translated using Weblate (Russian) Currently translated at 64.0% (157 of 245 strings) Translated using Weblate (Russian) Currently translated at 64.0% (157 of 245 strings) Translated using Weblate (Russian) Currently translated at 62.0% (152 of 245 strings) Translated using Weblate (Russian) Currently translated at 62.0% (152 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.8% (149 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.8% (149 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.4% (148 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.4% (148 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.0% (147 of 245 strings) Translated using Weblate (Russian) Currently translated at 60.0% (147 of 245 strings) Translated using Weblate (Russian) Currently translated at 57.9% (142 of 245 strings) Translated using Weblate (Russian) Currently translated at 57.9% (142 of 245 strings) Translated using Weblate (Russian) Currently translated at 56.7% (139 of 245 strings) Translated using Weblate (Russian) Currently translated at 56.7% (139 of 245 strings) Translated using Weblate (Russian) Currently translated at 56.3% (138 of 245 strings) Translated using Weblate (Russian) Currently translated at 56.3% (138 of 245 strings) Translated using Weblate (Russian) Currently translated at 53.8% (132 of 245 strings) Translated using Weblate (Russian) Currently translated at 53.8% (132 of 245 strings) Translated using Weblate (Russian) Currently translated at 53.4% (131 of 245 strings) Translated using Weblate (Russian) Currently translated at 53.4% (131 of 245 strings) Translated using Weblate (Russian) Currently translated at 48.9% (120 of 245 strings) Translated using Weblate (Russian) Currently translated at 48.9% (120 of 245 strings) Translated using Weblate (Russian) Currently translated at 48.5% (119 of 245 strings) Translated using Weblate (Russian) Currently translated at 48.5% (119 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 46.9% (115 of 245 strings) Translated using Weblate (Russian) Currently translated at 45.3% (111 of 245 strings) Translated using Weblate (Russian) Currently translated at 45.3% (111 of 245 strings) Translated using Weblate (Russian) Currently translated at 45.3% (111 of 245 strings) Translated using Weblate (Russian) Currently translated at 45.3% (111 of 245 strings) Translated using Weblate (Russian) Currently translated at 44.4% (109 of 245 strings) Translated using Weblate (German) Currently translated at 99.9% (3324 of 3325 strings) Translated using Weblate (Russian) Currently translated at 44.4% (109 of 245 strings) Translated using Weblate (Russian) Currently translated at 44.4% (109 of 245 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (94 of 94 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 93.8% (107 of 114 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (22 of 22 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.7% (429 of 430 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.6% (902 of 905 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (167 of 167 strings) Translated using Weblate (Portuguese) Currently translated at 100.0% (167 of 167 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 93.8% (107 of 114 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 93.6% (3114 of 3325 strings) Translated using Weblate (Portuguese) Currently translated at 53.9% (1793 of 3325 strings) Translated using Weblate (Dutch) Currently translated at 78.1% (2600 of 3325 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.5% (242 of 243 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 95.1% (820 of 862 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 96.6% (398 of 412 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 99.6% (902 of 905 strings) Translated using Weblate (Italian) Currently translated at 99.1% (113 of 114 strings) Translated using Weblate (Italian) Currently translated at 87.3% (2903 of 3325 strings) Translated using Weblate (Italian) Currently translated at 17.1% (42 of 245 strings) Translated using Weblate (Italian) Currently translated at 99.0% (408 of 412 strings) Translated using Weblate (Italian) Currently translated at 92.7% (102 of 110 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 99.0% (3292 of 3325 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.7% (3285 of 3325 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.7% (3285 of 3325 strings) Translated using Weblate (Slovak) Currently translated at 100.0% (134 of 134 strings) Translated using Weblate (Slovak) Currently translated at 100.0% (412 of 412 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (905 of 905 strings) Translated using Weblate (Chinese (Simplified)) Currently translated at 98.1% (3262 of 3325 strings) Co-authored-by: Andrea <goffopaguro@gmail.com> Co-authored-by: Artem StolyROV <stolyarov11303@gmail.com> Co-authored-by: Céu <marcel.ufscar@gmail.com> Co-authored-by: David Kaya <david@kaya.sk> Co-authored-by: Filip Betko <filipbetko@gmail.com> Co-authored-by: FingerTiao <787170918@qq.com> Co-authored-by: Irina Shcherbinina <cat3dcat007@gmail.com> Co-authored-by: Jaime Martí <jaumemarti77@icloud.com> Co-authored-by: Mencius <beautyalinap@gmail.com> Co-authored-by: Natalie Luhrs <eilatan@gmail.com> Co-authored-by: Nikita Maximov <ruvemaximus@gmail.com> Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com> Co-authored-by: Summer_GUI <heyang94@163.com> Co-authored-by: Tetiana <merekka13@gmail.com> Co-authored-by: Tom <tompsognathus@gmail.com> Co-authored-by: Toro Mor <thomas.bizer@gmx.de> Co-authored-by: V Aar <v.vanderaar@gmail.com> Co-authored-by: Viktor Révész <rviktor@ivankapal.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: razil <boss.razmarin@gmail.com> Co-authored-by: Волкозмей <klippiky@gmail.com> Co-authored-by: Данила Мальцев <maltsev-danila@inbox.ru> Co-authored-by: Татьяна Куклева <klippiky@gmail.com> Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt/ Translate-URL: https://translate.habitica.com/projects/habitica/achievements/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/achievements/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/de/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/es/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/fr/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/hu/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/backgrounds/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/challenge/it/ Translate-URL: https://translate.habitica.com/projects/habitica/communityguidelines/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/content/it/ Translate-URL: https://translate.habitica.com/projects/habitica/content/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/content/pt/ Translate-URL: https://translate.habitica.com/projects/habitica/content/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/content/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/it/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/ru/ Translate-URL: https://translate.habitica.com/projects/habitica/faq/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/de/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/it/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/gear/zh_Hans/ Translate-URL: https://translate.habitica.com/projects/habitica/generic/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/groups/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/es/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/fr/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/hu/ Translate-URL: https://translate.habitica.com/projects/habitica/limited/nl/ Translate-URL: https://translate.habitica.com/projects/habitica/loginincentives/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/npc/sk/ Translate-URL: https://translate.habitica.com/projects/habitica/npc/uk/ Translate-URL: https://translate.habitica.com/projects/habitica/pets/it/ Translate-URL: https://translate.habitica.com/projects/habitica/pets/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/pets/ru/ Translate-URL: https://translate.habitica.com/projects/habitica/quests/pt_BR/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/de/ Translate-URL: https://translate.habitica.com/projects/habitica/questscontent/pt_BR/ Translation: Habitica/Achievements Translation: Habitica/Backgrounds Translation: Habitica/Challenge Translation: Habitica/Communityguidelines Translation: Habitica/Content Translation: Habitica/Faq Translation: Habitica/Gear Translation: Habitica/Generic Translation: Habitica/Groups Translation: Habitica/Limited Translation: Habitica/Loginincentives Translation: Habitica/Npc Translation: Habitica/Pets Translation: Habitica/Quests Translation: Habitica/Questscontent * 5.36.4 * chore(deps): bump serialize-javascript in /website/client (#15395) Bumps [serialize-javascript](https://github.com/yahoo/serialize-javascript) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/yahoo/serialize-javascript/releases) - [Commits](https://github.com/yahoo/serialize-javascript/compare/v6.0.1...v6.0.2) --- updated-dependencies: - dependency-name: serialize-javascript dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump axios from 1.7.4 to 1.8.2 (#15401) Bumps [axios](https://github.com/axios/axios) from 1.7.4 to 1.8.2. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.7.4...v1.8.2) --- updated-dependencies: - dependency-name: axios dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump prismjs from 1.29.0 to 1.30.0 (#15403) Bumps [prismjs](https://github.com/PrismJS/prism) from 1.29.0 to 1.30.0. - [Release notes](https://github.com/PrismJS/prism/releases) - [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md) - [Commits](https://github.com/PrismJS/prism/compare/v1.29.0...v1.30.0) --- updated-dependencies: - dependency-name: prismjs dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @babel/runtime-corejs2 in /website/client (#15406) Bumps [@babel/runtime-corejs2](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs2) from 7.23.6 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime-corejs2) --- updated-dependencies: - dependency-name: "@babel/runtime-corejs2" dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @babel/helpers in /website/client (#15407) Bumps [@babel/helpers](https://github.com/babel/babel/tree/HEAD/packages/babel-helpers) from 7.23.6 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-helpers) --- updated-dependencies: - dependency-name: "@babel/helpers" dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @babel/runtime from 7.23.9 to 7.26.10 (#15410) Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.23.9 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump http-proxy-middleware in /website/client (#15427) Bumps [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) from 2.0.6 to 2.0.9. - [Release notes](https://github.com/chimurai/http-proxy-middleware/releases) - [Changelog](https://github.com/chimurai/http-proxy-middleware/blob/v2.0.9/CHANGELOG.md) - [Commits](https://github.com/chimurai/http-proxy-middleware/compare/v2.0.6...v2.0.9) --- updated-dependencies: - dependency-name: http-proxy-middleware dependency-version: 2.0.9 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Optimize database access for some use cases (#15444) * optimize query when listing challenge tasks * Optimize query for checking if user is party leader * correct worker call * remove unused priority * fix tests * don’t use body with delete * add detailed information about sub payment for google and apple * Support paypal details for subscription in admin panel * stripe payment details * fix imports * fix tests * fix deleting account * begin building group admin panel * fix convertig sub to group plan * improve sub status display * fix lint * fix long line * fix sub state display * lint fix * fix * delete amplitude data by default * improve searching for email in admin panel * correctly call method * move delete button in admin panel * fix(lint): whitespace * fix(style): indent * fix(typo): humand --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Natalie <78037386+CuriousMagpie@users.noreply.github.com> Co-authored-by: Kalista Payne <sabrecat@gmail.com> Co-authored-by: Weblate <noreply@weblate.org> Co-authored-by: Andrea <goffopaguro@gmail.com> Co-authored-by: Artem StolyROV <stolyarov11303@gmail.com> Co-authored-by: Céu <marcel.ufscar@gmail.com> Co-authored-by: David Kaya <david@kaya.sk> Co-authored-by: Filip Betko <filipbetko@gmail.com> Co-authored-by: FingerTiao <787170918@qq.com> Co-authored-by: Irina Shcherbinina <cat3dcat007@gmail.com> Co-authored-by: Jaime Martí <jaumemarti77@icloud.com> Co-authored-by: Mencius <beautyalinap@gmail.com> Co-authored-by: Natalie Luhrs <eilatan@gmail.com> Co-authored-by: Nikita Maximov <ruvemaximus@gmail.com> Co-authored-by: Sophie LE MASLE <sophiesuff@gmail.com> Co-authored-by: Summer_GUI <heyang94@163.com> Co-authored-by: Tetiana <merekka13@gmail.com> Co-authored-by: Tom <tompsognathus@gmail.com> Co-authored-by: Toro Mor <thomas.bizer@gmx.de> Co-authored-by: V Aar <v.vanderaar@gmail.com> Co-authored-by: Viktor Révész <rviktor@ivankapal.com> Co-authored-by: razil <boss.razmarin@gmail.com> Co-authored-by: Волкозмей <klippiky@gmail.com> Co-authored-by: Данила Мальцев <maltsev-danila@inbox.ru> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kalista Payne <kalista@habitica.com>
813 lines
25 KiB
Vue
813 lines
25 KiB
Vue
<template>
|
|
<form
|
|
@submit.prevent="saveHero({ hero: {
|
|
_id: hero._id,
|
|
purchased: hero.purchased
|
|
}, msg: 'Subscription Perks' })"
|
|
>
|
|
<div class="card mt-2">
|
|
<div
|
|
class="card-header"
|
|
@click="expand = !expand"
|
|
>
|
|
<h3
|
|
class="mb-0 mt-0"
|
|
:class="{ 'open': expand }"
|
|
>
|
|
Subscription, Monthly Perks
|
|
<span
|
|
v-if="isSubscribed() && !isCancelled()"
|
|
class="text-success float-right ml-3"
|
|
>
|
|
Active
|
|
</span>
|
|
<span
|
|
v-else-if="isSubscribed() && isCancelled()"
|
|
class="text-success float-right ml-3"
|
|
>
|
|
Active until {{ dateFormat(hero.purchased.plan.dateTerminated) }}
|
|
</span>
|
|
<span
|
|
v-else-if="hero.purchased.plan.customerId && hero.purchased.plan.dateTerminated"
|
|
class="text-warning float-right ml-3"
|
|
>
|
|
Inactive
|
|
</span>
|
|
|
|
<b
|
|
v-if="hasUnsavedChanges && !expand"
|
|
class="text-warning float-right"
|
|
>
|
|
Unsaved changes
|
|
</b>
|
|
</h3>
|
|
</div>
|
|
<div
|
|
v-if="expand"
|
|
class="card-body"
|
|
>
|
|
<div
|
|
class="form-group row"
|
|
>
|
|
<label class="col-sm-3 col-form-label">
|
|
Payment method:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<input
|
|
v-if="!isRegularPaymentMethod"
|
|
v-model="hero.purchased.plan.paymentMethod"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
<select
|
|
v-else
|
|
v-model="hero.purchased.plan.paymentMethod"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
<option value="Group Plan">
|
|
Group Plan
|
|
</option>
|
|
<option value="Stripe">
|
|
Stripe
|
|
</option>
|
|
<option value="Apple">
|
|
Apple
|
|
</option>
|
|
<option value="Google">
|
|
Google
|
|
</option>
|
|
<option value="Amazon Payments">
|
|
Amazon
|
|
</option>
|
|
<option value="PayPal">
|
|
PayPal
|
|
</option>
|
|
<option value="Gift">
|
|
Gift
|
|
</option>
|
|
<option value="">
|
|
Clear out
|
|
</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div
|
|
class="form-group row"
|
|
>
|
|
<label class="col-sm-3 col-form-label">
|
|
Payment schedule:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<input
|
|
v-if="!isRegularPlanId"
|
|
v-model="hero.purchased.plan.planId"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
<select
|
|
v-else
|
|
v-model="hero.purchased.plan.planId"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
<option value="basic_earned">
|
|
Monthly recurring
|
|
</option>
|
|
<option value="basic_3mo">
|
|
3 Months recurring
|
|
</option>
|
|
<option value="basic_6mo">
|
|
6 Months recurring
|
|
</option>
|
|
<option value="basic_12mo">
|
|
12 Months recurring
|
|
</option>
|
|
<option value="group_monthly">
|
|
Group Plan (legacy)
|
|
</option>
|
|
<option value="group_plan_auto">
|
|
Group Plan (auto)
|
|
</option>
|
|
<option value="">
|
|
Clear out
|
|
</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div
|
|
class="form-group row"
|
|
>
|
|
<label class="col-sm-3 col-form-label">
|
|
Customer ID:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<input
|
|
v-model="hero.purchased.plan.customerId"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="hero.purchased.plan.planId === 'group_plan_auto'"
|
|
class="form-group row"
|
|
>
|
|
<label class="col-sm-3 col-form-label">
|
|
Group Plan Memberships:
|
|
</label>
|
|
<div class="col-sm-9 col-form-label">
|
|
<loading-spinner
|
|
v-if="!groupPlans"
|
|
dark-color="true"
|
|
/>
|
|
<b
|
|
v-else-if="groupPlans.length === 0"
|
|
class="text-danger col-form-label"
|
|
>User is not part of an active group plan!</b>
|
|
<div
|
|
v-for="group in groupPlans"
|
|
v-else
|
|
:key="group._id"
|
|
class="card mb-2"
|
|
>
|
|
<div class="card-body">
|
|
<h6 class="card-title">
|
|
<router-link
|
|
:to="{ name: 'groupAdminGroup', params: { groupId: group._id } }"
|
|
>
|
|
{{ group.name }}
|
|
</router-link>
|
|
<small class="float-right">{{ group._id }}</small>
|
|
</h6>
|
|
<p class="card-text">
|
|
<strong>Leader: </strong>
|
|
<a
|
|
v-if="group.leader !== hero._id"
|
|
@click="switchUser(group.leader)"
|
|
>{{ group.leader }}</a>
|
|
<strong
|
|
v-else
|
|
class="text-success"
|
|
>This user</strong>
|
|
</p>
|
|
<p class="card-text">
|
|
<strong>Members: </strong> {{ group.memberCount }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="hero.purchased.plan.dateCreated"
|
|
class="form-group row"
|
|
>
|
|
<label class="col-sm-3 col-form-label">
|
|
Creation date:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<div class="input-group">
|
|
<input
|
|
v-model="hero.purchased.plan.dateCreated"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
<div class="input-group-append">
|
|
<strong class="input-group-text">
|
|
{{ dateFormat(hero.purchased.plan.dateCreated) }}
|
|
</strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="hero.purchased.plan.dateCurrentTypeCreated"
|
|
class="form-group row"
|
|
>
|
|
<label class="col-sm-3 col-form-label">
|
|
Current sub start date:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<div class="input-group">
|
|
<input
|
|
v-model="hero.purchased.plan.dateCurrentTypeCreated"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
<div class="input-group-append">
|
|
<strong class="input-group-text">
|
|
{{ dateFormat(hero.purchased.plan.dateCurrentTypeCreated) }}
|
|
</strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label class="col-sm-3 col-form-label">
|
|
Termination date:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<div class="input-group">
|
|
<input
|
|
v-model="hero.purchased.plan.dateTerminated"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
<div class="input-group-append">
|
|
<strong class="input-group-text">
|
|
{{ dateFormat(hero.purchased.plan.dateTerminated) }}
|
|
</strong>
|
|
<a
|
|
v-if="!hero.purchased.plan.dateTerminated && hero.purchased.plan.planId"
|
|
v-b-modal.sub_termination_modal
|
|
class="btn btn-danger"
|
|
href="#"
|
|
>
|
|
Terminate
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<small
|
|
v-if="isSubscribed() && !isCancelled()"
|
|
class="text-success"
|
|
>
|
|
The subscription does not have a termination date and is active.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label class="col-sm-3 col-form-label">
|
|
Cumulative months:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<input
|
|
v-model="hero.purchased.plan.cumulativeCount"
|
|
class="form-control"
|
|
type="number"
|
|
min="0"
|
|
step="1"
|
|
>
|
|
<small class="text-secondary">
|
|
Cumulative subscribed months across subscription periods.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label class="col-sm-3 col-form-label">
|
|
Extra months:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<div class="input-group">
|
|
<input
|
|
v-model="hero.purchased.plan.extraMonths"
|
|
class="form-control"
|
|
type="number"
|
|
min="0"
|
|
step="any"
|
|
>
|
|
<div class="input-group-append">
|
|
<a
|
|
v-if="hero.purchased.plan.dateTerminated && hero.purchased.plan.extraMonths > 0"
|
|
class="btn btn-warning"
|
|
@click="applyExtraMonths"
|
|
>
|
|
Apply Credit
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<small class="text-secondary">
|
|
Additional credit that is applied if a subscription is cancelled.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label class="col-sm-3 col-form-label">
|
|
Received hourglass bonus:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<div class="input-group">
|
|
<input
|
|
v-model="hero.purchased.plan.hourglassPromoReceived"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
<div class="input-group-append">
|
|
<strong class="input-group-text">
|
|
{{ dateFormat(hero.purchased.plan.hourglassPromoReceived) }}
|
|
</strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label class="col-sm-3 col-form-label">
|
|
Mystic Hourglasses:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<input
|
|
v-model="hero.purchased.plan.consecutive.trinkets"
|
|
class="form-control"
|
|
type="number"
|
|
min="0"
|
|
step="1"
|
|
>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label class="col-sm-3 col-form-label">
|
|
Gem cap increase:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<input
|
|
v-model="hero.purchased.plan.consecutive.gemCapExtra"
|
|
class="form-control"
|
|
type="number"
|
|
min="0"
|
|
max="26"
|
|
step="2"
|
|
>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label class="col-sm-3 col-form-label">
|
|
Total Gem cap:
|
|
</label>
|
|
<strong class="col-sm-9 col-form-label">
|
|
{{ Number(hero.purchased.plan.consecutive.gemCapExtra) + 24 }}
|
|
</strong>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label class="col-sm-3 col-form-label">
|
|
Gems bought this month:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<input
|
|
v-model="hero.purchased.plan.gemsBought"
|
|
class="form-control"
|
|
type="number"
|
|
min="0"
|
|
:max="hero.purchased.plan.consecutive.gemCapExtra + 24"
|
|
step="1"
|
|
>
|
|
</div>
|
|
</div>
|
|
<div class="form-group row">
|
|
<label class="col-sm-3 col-form-label">
|
|
Mystery Items:
|
|
</label>
|
|
<div class="col-sm-9 col-form-label">
|
|
<span v-if="hero.purchased.plan.mysteryItems.length > 0">
|
|
<span
|
|
v-for="(item, index) in hero.purchased.plan.mysteryItems"
|
|
:key="index"
|
|
>
|
|
<strong v-if="index < hero.purchased.plan.mysteryItems.length - 1">
|
|
{{ item }},
|
|
</strong>
|
|
<strong v-else> {{ item }} </strong>
|
|
</span>
|
|
</span>
|
|
<span v-else>
|
|
<strong>None</strong>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="!isConvertingToGroupPlan && hero.purchased.plan.planId !== 'group_plan_auto'"
|
|
class="form-group row"
|
|
>
|
|
<div class="offset-sm-3 col-sm-9">
|
|
<button
|
|
type="button"
|
|
class="btn btn-secondary btn-sm"
|
|
@click="beginGroupPlanConvert"
|
|
>
|
|
Begin converting to group plan subscription
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="isConvertingToGroupPlan"
|
|
class="form-group row"
|
|
>
|
|
<label class="col-sm-3 col-form-label">
|
|
Group Plan group ID:
|
|
</label>
|
|
<div class="col-sm-9">
|
|
<input
|
|
v-model="groupPlanID"
|
|
class="form-control"
|
|
type="text"
|
|
>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<h2>Payment Details</h2>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="offset-sm-3 col-sm-9 mb-3">
|
|
<button
|
|
type="button"
|
|
class="btn btn-secondary btn-sm"
|
|
@click="getSubscriptionPaymentDetails"
|
|
>
|
|
Get Subscription Payment Details
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="paymentDetails"
|
|
>
|
|
<div
|
|
v-for="(value, key) in paymentDetails"
|
|
:key="key"
|
|
class="form-group row"
|
|
>
|
|
<label class="col-sm-3 col-form-label">
|
|
{{ getHumanReadablePaymentDetails(key).label }}:
|
|
<span
|
|
:id="`${key}_tooltip`"
|
|
v-b-tooltip.hover.right="getHumanReadablePaymentDetails(key).help"
|
|
class="info-icon"
|
|
>?</span>
|
|
</label>
|
|
<strong class="col-sm-9 col-form-label">
|
|
<span v-if="value === true">Yes</span>
|
|
<span v-else-if="value === false">No</span>
|
|
<span
|
|
v-else-if="value instanceof String && isDate(value)"
|
|
v-b-tooltip.hover="value"
|
|
>
|
|
{{ formatDate(value) }}
|
|
</span>
|
|
<span v-else-if="value === null">---</span>
|
|
<span v-else>{{ value }}</span>
|
|
</strong>
|
|
</div>
|
|
<div class="form-group row">
|
|
<div class="offset-sm-3 col-sm-9">
|
|
<a
|
|
v-if="hero.purchased.plan.paymentMethod === 'Google'"
|
|
class="btn btn-primary btn-sm"
|
|
target="_blank"
|
|
:href="playOrdersUrl"
|
|
>
|
|
Play Console
|
|
</a>
|
|
<a
|
|
v-else-if="hero.purchased.plan.paymentMethod === 'Paypal'"
|
|
class="btn btn-primary btn-sm"
|
|
target="_blank"
|
|
:href="'https://www.paypal.com/billing/subscriptions/' + paymentDetails.customerId"
|
|
>
|
|
PayPal Dashboard
|
|
</a>
|
|
<a
|
|
v-else-if="hero.purchased.plan.paymentMethod === 'Stripe'"
|
|
class="btn btn-primary btn-sm"
|
|
target="_blank"
|
|
:href="'https://dashboard.stripe.com/customers/' + paymentDetails.customerId"
|
|
>
|
|
Stripe Dashboard
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="expand"
|
|
class="card-footer d-flex align-items-center justify-content-between"
|
|
>
|
|
<input
|
|
type="submit"
|
|
value="Save"
|
|
class="btn btn-primary mt-1"
|
|
@click="saveClicked"
|
|
>
|
|
<b
|
|
v-if="hasUnsavedChanges"
|
|
class="text-warning float-right"
|
|
>
|
|
Unsaved changes
|
|
</b>
|
|
</div>
|
|
</div>
|
|
<b-modal
|
|
id="sub_termination_modal"
|
|
title="Set Termination Date"
|
|
>
|
|
<p>
|
|
You can set the sub benefit termination date to today or to the last
|
|
day of the current billing cycle. Any extra subscription credit will
|
|
then be processed and automatically added onto the selected date.
|
|
</p>
|
|
<template #modal-footer>
|
|
<div
|
|
class="mt-3 btn btn-secondary"
|
|
@click="$bvModal.hide('sub_termination_modal')"
|
|
>
|
|
Close
|
|
</div>
|
|
<div
|
|
class="mt-3 btn btn-danger"
|
|
@click="terminateSubscription()"
|
|
>
|
|
Set to Today
|
|
</div>
|
|
<div
|
|
class="mt-3 btn btn-danger"
|
|
@click="terminateSubscription(todayWithRemainingCycle)"
|
|
>
|
|
Set to {{ todayWithRemainingCycle.utc().format('MM/DD/YYYY') }}
|
|
</div>
|
|
</template>
|
|
</b-modal>
|
|
</form>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
@import '@/assets/scss/colors.scss';
|
|
|
|
.form-group {
|
|
margin-bottom: 0.4rem;
|
|
}
|
|
|
|
.input-group-append {
|
|
width: auto;
|
|
|
|
.input-group-text {
|
|
border-bottom-right-radius: 2px;
|
|
border-top-right-radius: 2px;
|
|
font-weight: 600;
|
|
font-size: 0.8rem;
|
|
color: $gray-200;
|
|
}
|
|
}
|
|
|
|
.info-icon {
|
|
font-size: 0.8rem;
|
|
color: $purple-400;
|
|
cursor: pointer;
|
|
margin-left: 0.2rem;
|
|
background-color: $gray-500;
|
|
padding: 0.1rem 0.3rem;
|
|
border-radius: 0.2rem;
|
|
}
|
|
|
|
.info-icon:hover {
|
|
background-color: $purple-400;
|
|
color: white;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
import isUUID from 'validator/es/lib/isUUID';
|
|
import moment from 'moment';
|
|
import { getPlanContext } from '@/../../common/script/cron';
|
|
import subscriptionBlocks from '@/../../common/script/content/subscriptionBlocks';
|
|
import saveHero from '../mixins/saveHero';
|
|
import LoadingSpinner from '@/components/ui/loadingSpinner';
|
|
|
|
const PLAY_CONSOLE_ORDERS_BASE_URL = import.meta.env.PLAY_CONSOLE_ORDERS_BASE_URL;
|
|
|
|
const humanReadablePaymentDetails = {
|
|
customerId: {
|
|
label: 'Customer ID',
|
|
help: 'The unique identifier for the customer in the payment system.',
|
|
},
|
|
purchaseDate: {
|
|
label: 'Purchase Date',
|
|
help: 'The date when the subscription was purchased or renewed.',
|
|
},
|
|
originalPurchaseDate: {
|
|
label: 'Original Purchase Date',
|
|
help: 'The date when the subscription was first purchased.',
|
|
},
|
|
productId: {
|
|
label: 'Product ID',
|
|
help: 'The identifier for the product associated with the subscription.',
|
|
},
|
|
transactionId: {
|
|
label: 'Transaction ID',
|
|
help: 'The unique identifier for the last transaction in the payment system.',
|
|
},
|
|
isCanceled: {
|
|
label: 'Is Canceled',
|
|
help: 'Indicates whether the subscription has been canceled by the user or the system.',
|
|
},
|
|
isExpired: {
|
|
label: 'Is Expired',
|
|
help: 'Indicates whether the subscription has expired. A cancelled subscription may still be active until the end of the billing cycle.',
|
|
},
|
|
expirationDate: {
|
|
label: 'Termination Date',
|
|
help: 'The date when the subscription will expire or has expired.',
|
|
},
|
|
nextPaymentDate: {
|
|
label: 'Next Payment Date',
|
|
help: 'The date when the next payment is due. If the subscription is canceled or expired, this may be null.',
|
|
},
|
|
lastPaymentDate: {
|
|
label: 'Last Payment Date',
|
|
help: 'The date when the lastpayment was made for the subscription.',
|
|
},
|
|
failedPayments: {
|
|
label: 'Failed Payments',
|
|
help: 'Number of times the payment failed for this subscription.',
|
|
},
|
|
};
|
|
|
|
export default {
|
|
components: {
|
|
LoadingSpinner,
|
|
},
|
|
mixins: [saveHero],
|
|
props: {
|
|
hero: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
hasUnsavedChanges: {
|
|
type: Boolean,
|
|
required: true,
|
|
},
|
|
groupPlans: {
|
|
type: Array,
|
|
default: null,
|
|
},
|
|
},
|
|
data () {
|
|
return {
|
|
expand: false,
|
|
isConvertingToGroupPlan: false,
|
|
groupPlanID: '',
|
|
subscriptionBlocks,
|
|
paymentDetails: null,
|
|
};
|
|
},
|
|
computed: {
|
|
nextHourglassDate () {
|
|
const currentPlanContext = getPlanContext(this.hero, new Date());
|
|
|
|
if (!currentPlanContext.nextHourglassDate) return 'N/A';
|
|
return currentPlanContext.nextHourglassDate.format('MMMM YYYY');
|
|
},
|
|
isRegularPlanId () {
|
|
return this.subscriptionBlocks[this.hero.purchased.plan.planId] !== undefined;
|
|
},
|
|
isRegularPaymentMethod () {
|
|
return [
|
|
'groupPlan',
|
|
'Group Plan',
|
|
'Stripe',
|
|
'Apple',
|
|
'Google',
|
|
'Amazon Payments',
|
|
'PayPal',
|
|
'Gift',
|
|
].includes(this.hero.purchased.plan.paymentMethod);
|
|
},
|
|
todayWithRemainingCycle () {
|
|
const now = moment();
|
|
const monthCount = subscriptionBlocks[this.hero.purchased.plan.planId].months;
|
|
const terminationDate = moment(this.hero.purchased.plan.dateCurrentTypeCreated || new Date());
|
|
while (terminationDate.isBefore(now)) {
|
|
terminationDate.add(monthCount, 'months');
|
|
}
|
|
return terminationDate;
|
|
},
|
|
playOrdersUrl () {
|
|
return `${PLAY_CONSOLE_ORDERS_BASE_URL}${this.paymentDetails?.transactionId || ''}`;
|
|
},
|
|
},
|
|
methods: {
|
|
dateFormat (date) {
|
|
if (!date) {
|
|
return '--';
|
|
}
|
|
return moment(date).format('YYYY/MM/DD');
|
|
},
|
|
terminateSubscription (terminationDate) {
|
|
if (terminationDate) {
|
|
this.hero.purchased.plan.dateTerminated = terminationDate.utc().format();
|
|
} else {
|
|
this.hero.purchased.plan.dateTerminated = moment(new Date()).utc().format();
|
|
}
|
|
this.applyExtraMonths();
|
|
this.saveHero({ hero: this.hero, msg: 'Subscription Termination', reloadData: true });
|
|
},
|
|
applyExtraMonths () {
|
|
if (this.hero.purchased.plan.extraMonths > 0 || this.hero.purchased.plan.extraMonths !== '0') {
|
|
const date = moment(this.hero.purchased.plan.dateTerminated || new Date());
|
|
const extraMonths = Math.max(this.hero.purchased.plan.extraMonths, 0);
|
|
const extraDays = Math.ceil(30.5 * extraMonths);
|
|
this.hero.purchased.plan.dateTerminated = date.add(extraDays, 'days').utc().format();
|
|
this.hero.purchased.plan.extraMonths = 0;
|
|
}
|
|
},
|
|
beginGroupPlanConvert () {
|
|
this.isConvertingToGroupPlan = true;
|
|
this.hero.purchased.plan.owner = '';
|
|
},
|
|
getSubscriptionPaymentDetails () {
|
|
this.$store.dispatch('admin:getSubscriptionPaymentDetails', { userIdentifier: this.hero._id })
|
|
.then(details => {
|
|
if (details) {
|
|
this.paymentDetails = details;
|
|
} else {
|
|
alert('No payment details found.');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching subscription payment details:', error);
|
|
alert(`Failed to fetch payment details: ${error.message || 'Unknown error'}`);
|
|
});
|
|
},
|
|
saveClicked (e) {
|
|
e.preventDefault();
|
|
if (this.isConvertingToGroupPlan) {
|
|
if (!isUUID(this.groupPlanID)) {
|
|
alert('Invalid group ID');
|
|
return;
|
|
}
|
|
this.hero.purchased.plan.convertToGroupPlan = this.groupPlanID;
|
|
this.saveHero({ hero: this.hero, msg: 'Group Plan Subscription', reloadData: true });
|
|
} else {
|
|
this.saveHero({ hero: this.hero, msg: 'Subscription Perks', reloadData: true });
|
|
}
|
|
},
|
|
switchUser (id) {
|
|
if (window.confirm('Switch to this user?')) {
|
|
this.$emit('changeUserIdentifier', id);
|
|
}
|
|
},
|
|
getHumanReadablePaymentDetails (key) {
|
|
return humanReadablePaymentDetails[key] || { label: key, help: '' };
|
|
},
|
|
isDate (date) {
|
|
return moment(date).isValid();
|
|
},
|
|
formatDate (date) {
|
|
return date ? moment(date).format('MM/DD/YYYY') : '---';
|
|
},
|
|
isSubscribed () {
|
|
console.log(this.hero.purchased.plan.customerId, this.hero.purchased.plan.dateTerminated);
|
|
return this.hero.purchased.plan
|
|
&& this.hero.purchased.plan.customerId
|
|
&& this.hero.purchased.plan.planId
|
|
&& this.hero.purchased.plan.paymentMethod
|
|
&& (
|
|
!this.hero.purchased.plan.dateTerminated
|
|
|| moment(this.hero.purchased.plan.dateTerminated).isAfter(moment())
|
|
);
|
|
},
|
|
isCancelled () {
|
|
return this.hero.purchased.plan
|
|
&& this.hero.purchased.plan.dateTerminated
|
|
&& this.hero.purchased.plan.dateTerminated !== '';
|
|
},
|
|
},
|
|
};
|
|
</script>
|