Subscription Page Overhaul (#11823)

* WIP(settings): subscriber page improvements

* WIP(subscriptions): more design build-out

* fix(css): disabled button styles

* fix(css): better Amazon targeting

* WIP(g1g1): notif

* WIP(g1g1): notif cont'd

* WIP(gifting): partial modal implementation

* feat(gifting): select giftee modal

* fix(gifting): notification order, modal dismiss

* fix(modals): correct some repops

* fix(gifting): style updates

* fix(modals): also clean out "prev"

* refactor(modals): hide in dismiss event

* fix(modals): new dismiss logic

* fix(modals): new dismiss no go??

* WIP(subscription): unsubscribed state

* WIP(subscription): partial subscribed

* WIP(subscription): finish subscribed

* feat(subscription): revised sub page RC

* fix(subs): style tweaks

* fix(subs): moar style tweaks
This commit is contained in:
Sabe Jones
2020-02-13 13:12:45 -06:00
committed by GitHub
parent bac84f6ce0
commit 9a6f8021e3
31 changed files with 1332 additions and 764 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -61,7 +61,7 @@ h3 {
font-size: 16px;
line-height: 1.5;
color: $gray-50;
margin-bottom: 9px;
margin-bottom: 4px;
}
h4 {

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="98" height="40" viewBox="0 0 98 40">
<path fill="#000" fill-rule="nonzero" d="M17.744 5.137c-1.137 1.346-2.957 2.408-4.777 2.256-.228-1.82.663-3.753 1.706-4.948C15.81 1.062 17.801.075 19.413 0c.189 1.896-.55 3.754-1.669 5.137zm1.65 2.617c-2.636-.152-4.892 1.497-6.143 1.497-1.27 0-3.185-1.422-5.27-1.384-2.71.038-5.232 1.574-6.616 4.02C-1.48 16.776.625 24.018 3.375 28c1.345 1.972 2.957 4.133 5.08 4.057 2.01-.076 2.806-1.308 5.232-1.308 2.446 0 3.147 1.308 5.27 1.27 2.2-.038 3.583-1.972 4.93-3.943 1.535-2.237 2.16-4.417 2.198-4.531-.038-.038-4.246-1.65-4.284-6.502-.038-4.057 3.317-5.99 3.47-6.105-1.897-2.805-4.854-3.109-5.878-3.184zm15.222-5.498V31.81h4.588V21.706h6.35c5.801 0 9.877-3.98 9.877-9.744 0-5.763-4-9.706-9.725-9.706h-11.09zm4.588 3.867h5.289c3.98 0 6.256 2.123 6.256 5.858 0 3.735-2.275 5.877-6.275 5.877h-5.27V6.123zM63.81 32.038c2.882 0 5.555-1.46 6.768-3.773h.095v3.545h4.246V17.1c0-4.266-3.412-7.015-8.663-7.015-4.872 0-8.474 2.787-8.607 6.616h4.133c.341-1.82 2.028-3.014 4.341-3.014 2.806 0 4.38 1.308 4.38 3.716v1.63l-5.726.341c-5.327.323-8.208 2.503-8.208 6.294 0 3.83 2.976 6.37 7.241 6.37zm1.233-3.507c-2.446 0-4-1.176-4-2.976 0-1.858 1.497-2.939 4.36-3.11l5.1-.322v1.668c0 2.768-2.351 4.74-5.46 4.74zm15.545 11.317c4.474 0 6.578-1.706 8.417-6.881l8.057-22.597h-4.664l-5.403 17.46H86.9l-5.402-17.46H76.7l7.773 21.516-.417 1.308c-.702 2.218-1.839 3.071-3.867 3.071-.36 0-1.062-.038-1.346-.075v3.545c.265.075 1.402.113 1.744.113z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" fill-rule="evenodd">
<path fill="#9A62FF" d="M20.571 3.429V0h-3.428v3.429H6.857V0H3.43v3.429A3.428 3.428 0 0 0 0 6.857v13.714A3.428 3.428 0 0 0 3.429 24H20.57A3.428 3.428 0 0 0 24 20.571V6.857a3.428 3.428 0 0 0-3.429-3.428z"/>
<path fill="#D5C8FF" d="M3.429 20.571H20.57V10.286H3.43z"/>
<path fill="#9A62FF" d="M3.429 13.286H20.57v-3H3.43z"/>
<path fill="#BDA8FF" d="M3.429 13.286H20.57v-3H3.43z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 550 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<g fill="none" fill-rule="evenodd" stroke="#8EEDF6" stroke-width="2">
<path d="M1 11L11 1M11 11L1 1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 215 B

View File

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="34" viewBox="0 0 32 34">
<g fill="none" fill-rule="evenodd">
<path stroke="#22AEB7" stroke-width="4" d="M12.558 7.452C11.49 5.033 9.422 2.896 6.934 2.79 4.446 2.684 3.019 4.68 3.75 6.444c.73 1.766 2.47 2.09 8.113 3.601 1.603.43 1.764-.174.695-2.593z"/>
<path stroke="#38C9C6" stroke-width="4" d="M18.916 7.452c1.07-2.419 3.137-4.556 5.625-4.662 2.488-.106 3.915 1.89 3.184 3.654-.73 1.766-2.47 2.09-8.114 3.601-1.602.43-1.764-.174-.695-2.593z"/>
<path fill="#46DDDA" d="M15.564 6c-4.87 0-1.953 5.572 0 5.572 1.954 0 4.87-5.572 0-5.572z"/>
<path fill="#6133B4" d="M3 17h26v17H3zM0 11h32v6H0z"/>
<path fill="#FFF" fill-opacity=".5" d="M16 17h13v17H16z" style="mix-blend-mode:soft-light"/>
<path fill="#8EEDF6" d="M16 17h3v17h-3z"/>
<path fill="#3BCAD7" d="M13 17h3v17h-3zM10 11h6v6h-6z"/>
<path fill="#8EEDF6" d="M16 11h6v6h-6z"/>
<path fill="#000" fill-opacity=".2" d="M3 17h13v3H3zM10 11h6v3h-6zM0 14h10v3H0zM22 14h10v3H22zM16 11h6v3h-6zM3 31h13v3H3zM16 17h13v3H16zM16 31h13v3H16z" style="mix-blend-mode:multiply"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="40" viewBox="0 0 100 40">
<g fill="none" fill-rule="evenodd">
<path fill="#5F6368" fill-rule="nonzero" d="M47.131 19.561v11.6h-3.68V2.514h9.76a8.825 8.825 0 0 1 6.32 2.48 7.973 7.973 0 0 1 2.64 6.046 7.936 7.936 0 0 1-2.64 6.08c-1.706 1.627-3.813 2.44-6.32 2.439h-6.08v.002zm0-13.52v10h6.172a4.864 4.864 0 0 0 3.641-1.481 4.882 4.882 0 0 0 0-7.001 4.8 4.8 0 0 0-3.641-1.52H47.13v.002zM70.651 10.921c2.72 0 4.867.727 6.442 2.18 1.574 1.454 2.36 3.448 2.358 5.98v12.08h-3.52v-2.72h-.16c-1.523 2.24-3.55 3.36-6.08 3.36-2.159 0-3.965-.64-5.419-1.92a6.13 6.13 0 0 1-2.18-4.8c0-2.028.766-3.641 2.299-4.839 1.533-1.197 3.58-1.798 6.14-1.8 2.184 0 3.984.4 5.398 1.2V18.8a4.19 4.19 0 0 0-1.52-3.257 5.211 5.211 0 0 0-3.552-1.342c-2.055 0-3.682.867-4.88 2.601l-3.241-2.04c1.783-2.56 4.421-3.84 7.915-3.84zm-4.76 14.24a2.94 2.94 0 0 0 1.22 2.4 4.49 4.49 0 0 0 2.86.96 5.867 5.867 0 0 0 4.139-1.719c1.219-1.147 1.828-2.493 1.828-4.039-1.147-.914-2.747-1.371-4.8-1.371-1.495 0-2.741.36-3.74 1.081-1.007.732-1.508 1.62-1.508 2.688z"/>
<path fill="#5F6368" d="M99.657 11.561L87.37 39.801H83.57l4.56-9.881-8.08-18.359h4l5.84 14.08h.08l5.68-14.08z"/>
<path fill="#4285F4" d="M32.26 17.06a19.61 19.61 0 0 0-.283-3.346h-15.52v6.339h8.89a7.618 7.618 0 0 1-3.288 5v4.115h5.306c3.106-2.864 4.896-7.1 4.896-12.107z"/>
<path fill="#34A853" d="M16.457 33.143c4.441 0 8.18-1.458 10.908-3.973l-5.306-4.114c-1.476 1.001-3.378 1.573-5.602 1.573-4.292 0-7.936-2.894-9.239-6.794H1.753v4.24a16.457 16.457 0 0 0 14.704 9.068z"/>
<path fill="#FBBC04" d="M7.218 19.835a9.86 9.86 0 0 1 0-6.299v-4.24H1.753a16.457 16.457 0 0 0 0 14.78l5.465-4.24z"/>
<path fill="#EA4335" d="M16.457 6.743A8.935 8.935 0 0 1 22.77 9.21l4.697-4.697A15.813 15.813 0 0 0 16.457.23 16.457 16.457 0 0 0 1.753 9.296l5.465 4.24c1.303-3.9 4.947-6.793 9.24-6.793z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="24" viewBox="0 0 34 24">
<g fill="#4E4A57" fill-rule="nonzero">
<path d="M0 20.776c0 1.646 1.182 2.98 2.641 2.98H31.11c1.459 0 2.641-1.333 2.641-2.98V8.818H0v11.958zM31.109.244H2.64C1.182.244 0 1.577 0 3.224v.892h33.75v-.892c0-1.647-1.182-2.98-2.641-2.98z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 346 B

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="144" height="31" viewBox="0 0 144 31">
<g fill="none" fill-rule="evenodd">
<path fill="#4F2A93" d="M120.876 24.007a2.27 2.27 0 0 0-3.183.41 4.595 4.595 0 0 1-3.663 1.804 4.62 4.62 0 0 1-4.613-4.335c-.005-.35-.009-2.864-.009-3.19a4.627 4.627 0 0 1 4.622-4.622c1.28 0 2.47.51 3.353 1.44a2.269 2.269 0 0 0 3.29-3.125 9.2 9.2 0 0 0-6.643-2.853c-5.05 0-9.16 4.109-9.16 9.16 0 .03.002 3.175.014 3.406a9.158 9.158 0 0 0 9.146 8.657 9.1 9.1 0 0 0 7.257-3.57 2.27 2.27 0 0 0-.411-3.182M134.373 26.221a4.62 4.62 0 0 1-4.613-4.333c-.005-.353-.008-2.877-.008-3.193a4.627 4.627 0 0 1 4.621-4.622 4.627 4.627 0 0 1 4.622 4.622c0 .328-.003 2.84-.009 3.189a4.618 4.618 0 0 1-4.613 4.337m6.891-17.078a2.264 2.264 0 0 0-2.19 1.706 9.095 9.095 0 0 0-4.7-1.313c-5.051 0-9.16 4.109-9.16 9.16 0 .031.001 3.173.013 3.406a9.158 9.158 0 0 0 9.146 8.657 9.118 9.118 0 0 0 4.81-1.37 2.268 2.268 0 0 0 4.35-.899V11.412a2.27 2.27 0 0 0-2.269-2.269M30.546 26.221a4.62 4.62 0 0 1-4.613-4.335c-.006-.35-.01-2.863-.01-3.19a4.627 4.627 0 0 1 4.623-4.623 4.627 4.627 0 0 1 4.622 4.622c0 .328-.004 2.84-.01 3.189a4.618 4.618 0 0 1-4.612 4.337m6.89-17.078a2.264 2.264 0 0 0-2.19 1.706 9.095 9.095 0 0 0-4.7-1.313c-5.052 0-9.16 4.109-9.16 9.16 0 .031 0 3.174.013 3.406a9.158 9.158 0 0 0 9.147 8.657 9.118 9.118 0 0 0 4.809-1.37 2.268 2.268 0 0 0 4.35-.899V11.412a2.27 2.27 0 0 0-2.269-2.269M70.84 9.143a2.27 2.27 0 0 0-2.27 2.27V28.49a2.27 2.27 0 0 0 4.539 0V11.412a2.27 2.27 0 0 0-2.27-2.269M97.563 9.143a2.27 2.27 0 0 0-2.27 2.27V28.49a2.27 2.27 0 0 0 4.538 0V11.412a2.27 2.27 0 0 0-2.268-2.269M59.066 21.888a4.62 4.62 0 0 1-4.613 4.333 4.62 4.62 0 0 1-4.613-4.338c-.006-.35-.009-2.86-.009-3.187a4.627 4.627 0 0 1 4.622-4.622 4.627 4.627 0 0 1 4.622 4.622c0 .315-.004 2.84-.009 3.192M54.453 9.536a9.089 9.089 0 0 0-4.622 1.265V2.33a2.27 2.27 0 0 0-4.537 0V28.49a2.269 2.269 0 0 0 4.35.9 9.117 9.117 0 0 0 4.81 1.37 9.16 9.16 0 0 0 9.146-8.666c.011-.224.013-3.367.013-3.398 0-5.052-4.11-9.16-9.16-9.16M8.92 9.536a9.143 9.143 0 0 0-4.382 1.11V2.33A2.27 2.27 0 0 0 0 2.33v26.16a2.269 2.269 0 1 0 4.538 0V16.763c.173-.147.333-.314.46-.516a4.601 4.601 0 0 1 3.921-2.173 4.627 4.627 0 0 1 4.622 4.622c0 .415-.004 9.233-.01 9.738a2.27 2.27 0 0 0 4.535.172c.01-.225.012-9.814.012-9.91 0-5.052-4.108-9.16-9.159-9.16M88.95 9.143h-2.648V2.33a2.27 2.27 0 0 0-4.538 0v6.813h-2.647a2.27 2.27 0 0 0 0 4.538h2.647V28.49a2.27 2.27 0 0 0 4.538 0V13.681h2.647a2.27 2.27 0 0 0 0-4.538"/>
<path fill="#FF6066" d="M73.025 2.33a2.27 2.27 0 1 1-4.538 0 2.27 2.27 0 0 1 4.538 0"/>
<path fill="#4FB5E8" d="M99.748 2.33a2.27 2.27 0 1 1-4.539 0 2.27 2.27 0 0 1 4.539 0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="149" height="40" viewBox="0 0 149 40">
<g fill="none" fill-rule="evenodd">
<path fill="#283B82" fill-rule="nonzero" d="M17.806.284H6.265c-.79 0-1.462.574-1.585 1.354L.012 31.234a.96.96 0 0 0 .952 1.11h5.51c.79 0 1.461-.574 1.585-1.355l1.259-7.982A1.602 1.602 0 0 1 10.9 21.65h3.653c7.603 0 11.99-3.679 13.137-10.97.516-3.189.022-5.695-1.472-7.45C24.58 1.304 21.67.284 17.806.284zm1.332 10.81c-.631 4.141-3.796 4.141-6.855 4.141H10.54l1.222-7.734a.962.962 0 0 1 .95-.812h.798c2.085 0 4.05 0 5.067 1.188.606.709.791 1.762.56 3.217zM52.306 10.96H46.78a.963.963 0 0 0-.95.812l-.245 1.546-.387-.56c-1.196-1.737-3.865-2.317-6.528-2.317-6.107 0-11.323 4.625-12.34 11.114-.528 3.237.223 6.332 2.06 8.49 1.684 1.985 4.094 2.812 6.961 2.812 4.921 0 7.65-3.164 7.65-3.164l-.246 1.536a.961.961 0 0 0 .948 1.113h4.978c.792 0 1.46-.573 1.585-1.355l2.987-18.916a.958.958 0 0 0-.947-1.11zm-7.704 10.757c-.533 3.158-3.039 5.278-6.235 5.278-1.605 0-2.888-.515-3.711-1.49-.817-.97-1.128-2.348-.868-3.884.498-3.13 3.047-5.32 6.194-5.32 1.57 0 2.845.522 3.686 1.506.842.994 1.176 2.381.934 3.91z"/>
<path fill="#283B82" d="M81.742 10.96h-5.554a1.61 1.61 0 0 0-1.328.704L67.2 22.948l-3.247-10.843a1.608 1.608 0 0 0-1.54-1.145h-5.457a.962.962 0 0 0-.913 1.273l6.118 17.953-5.752 8.119a.962.962 0 0 0 .785 1.519h5.547a1.6 1.6 0 0 0 1.318-.689l18.473-26.664a.961.961 0 0 0-.79-1.51"/>
<path fill="#469BDB" fill-rule="nonzero" d="M100.13.284H88.587c-.788 0-1.46.574-1.583 1.354l-4.668 29.596a.96.96 0 0 0 .949 1.11h5.923c.55 0 1.021-.401 1.107-.948l1.325-8.39a1.602 1.602 0 0 1 1.583-1.355h3.652c7.604 0 11.99-3.679 13.138-10.97.518-3.189.02-5.695-1.473-7.45-1.639-1.927-4.547-2.947-8.41-2.947zm1.332 10.81c-.63 4.141-3.794 4.141-6.855 4.141h-1.74l1.223-7.734a.958.958 0 0 1 .949-.812h.798c2.083 0 4.05 0 5.066 1.188.606.709.79 1.762.559 3.217zM134.629 10.96h-5.524a.957.957 0 0 0-.948.812l-.245 1.546-.388-.56c-1.197-1.737-3.863-2.317-6.526-2.317-6.108 0-11.322 4.625-12.338 11.114-.527 3.237.22 6.332 2.057 8.49 1.688 1.985 4.094 2.812 6.961 2.812 4.921 0 7.65-3.164 7.65-3.164l-.246 1.536a.962.962 0 0 0 .952 1.113h4.977c.788 0 1.46-.573 1.583-1.355l2.988-18.916a.964.964 0 0 0-.953-1.11zm-7.704 10.757c-.53 3.158-3.04 5.278-6.236 5.278-1.602 0-2.888-.515-3.711-1.49-.817-.97-1.124-2.348-.867-3.884.5-3.13 3.046-5.32 6.193-5.32 1.57 0 2.845.522 3.686 1.506.845.994 1.18 2.381.935 3.91z"/>
<path fill="#469BDB" d="M141.145 1.096l-4.738 30.138a.96.96 0 0 0 .949 1.11h4.762c.792 0 1.464-.574 1.585-1.355l4.671-29.594a.961.961 0 0 0-.948-1.112h-5.333a.964.964 0 0 0-.948.813"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,26 @@
<svg xmlns="http://www.w3.org/2000/svg" width="39" height="44" viewBox="0 0 39 44">
<g fill="none" fill-rule="evenodd">
<path fill="#24CC8F" d="M2.782 35.927l1.867-8.397 12.887-5.47 7.338 4.49-5.967 16.655z"/>
<path fill="#FFF" d="M9.147 33.008L6.351 28.98l5.523-2.344zM18.352 29.1l-.955-4.808-5.523 2.344z" opacity=".25"/>
<path fill="#FFF" d="M9.147 33.008l2.727-6.372 6.478 2.465zM5.097 34.727L6.35 28.98l2.796 4.028z" opacity=".5"/>
<path fill="#1B996B" d="M22.402 27.382l-5.005-3.09.955 4.809zM5.097 34.727l4.05-1.719 8.627 7.528z" opacity=".35"/>
<path fill="#FFF" d="M22.402 27.382l-4.05 1.719-.578 11.435z" opacity=".5"/>
<path fill="#FFF" d="M9.147 33.008l9.205-3.907-.578 11.435z" opacity=".25"/>
<g>
<path fill="#24CC8F" d="M23.248 7.266l4.784-3.162 8.714 3.345 1.44 5.55-10.575 5.225z"/>
<path fill="#FFF" d="M27.653 8.814l.524-3.227 3.734 1.434zM33.876 11.203l1.77-2.749-3.735-1.433z" opacity=".25"/>
<path fill="#FFF" d="M27.653 8.814L31.91 7.02l1.965 4.182zM24.914 7.763l3.263-2.176-.524 3.227z" opacity=".5"/>
<path fill="#1B996B" d="M36.615 12.254l-.97-3.8-1.769 2.749zM24.914 7.763l2.739 1.05.65 7.606z" opacity=".35"/>
<path fill="#FFF" d="M36.615 12.254l-2.739-1.051-5.572 5.216z" opacity=".5"/>
<path fill="#FFF" d="M27.653 8.814l6.223 2.389-5.572 5.216z" opacity=".25"/>
</g>
<g>
<path fill="#24CC8F" d="M.815 5.996l1.58-4L9.185.301l3.273 2.791-4.25 7.758z"/>
<path fill="#FFF" d="M4.187 5.052L3.121 2.845l2.911-.726zM9.039 3.843l-.096-2.45-2.91.726z" opacity=".25"/>
<path fill="#FFF" d="M4.187 5.052L6.032 2.12 9.04 3.843zM2.053 5.585l1.068-2.74 1.066 2.207z" opacity=".5"/>
<path fill="#1B996B" d="M11.173 3.31l-2.23-1.917.096 2.45zM2.053 5.585l2.134-.533L7.86 9.445z" opacity=".35"/>
<path fill="#FFF" d="M11.173 3.31l-2.134.533-1.18 5.602z" opacity=".5"/>
<path fill="#FFF" d="M4.187 5.052l4.852-1.21-1.18 5.603z" opacity=".25"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,26 @@
<svg xmlns="http://www.w3.org/2000/svg" width="35" height="47" viewBox="0 0 35 47">
<g fill="none" fill-rule="evenodd">
<path fill="#A9DCF6" fill-opacity=".8" d="M25.955 43.329l-.999 2.352a.939.939 0 0 1-.644.555c-3.194.747-9.918-2.107-11.6-4.923a.941.941 0 0 1-.047-.85l.998-2.351c.911-2.146 2.886-3.738 5.074-4.257a.957.957 0 0 0 .607-1.429c-1.147-1.934-1.374-4.46-.463-6.606l.998-2.352a.937.937 0 0 1 .643-.555c3.195-.746 9.919 2.108 11.6 4.924a.935.935 0 0 1 .049.848l-.999 2.353c-.91 2.145-2.886 3.737-5.074 4.256a.957.957 0 0 0-.606 1.429c1.146 1.934 1.373 4.46.463 6.606"/>
<path fill="#FFF" fill-opacity=".9" d="M26.145 25.795c-1.997-.848-3.705-1.145-4.72-1.087l-.788 1.857c-.656 1.547-.524 3.42.347 4.889.466.786.532 1.753.178 2.588a2.881 2.881 0 0 1-1.983 1.669c-1.664.395-3.103 1.6-3.76 3.146l-.788 1.858c.663.77 2.063 1.792 4.06 2.64 1.996.847 3.705 1.144 4.719 1.086l.789-1.858c.656-1.545.523-3.418-.348-4.887a2.883 2.883 0 0 1-.178-2.588 2.886 2.886 0 0 1 1.984-1.67c1.663-.394 3.103-1.6 3.759-3.146l.788-1.857c-.662-.77-2.063-1.793-4.06-2.64"/>
<path fill="#9A62FF" d="M25.383 27.029c1.497.636 3.026 1.448 2.883 1.825-.112.305-.366.882-1.844.982-1.436.098-2.123 1.1-2.765.828-.746-.317-.521-.966-1.166-1.98-.664-1.043-.444-1.979-.287-2.32.219-.473 1.681.03 3.179.665"/>
<path fill="#4F2A93" d="M22.491 28.685c-.664-1.044-.444-1.98-.287-2.32.173-.376 1.126-.139 2.26.292-.382.027-.93.194-1.114.902-.19.738.576 1.97.14 2.507a.755.755 0 0 1-.29.223c-.231-.363-.257-.894-.709-1.604"/>
<path fill="#9A62FF" d="M21.74 36.173c.455.193.22 1.074.662 1.871.543.978.984 2.084.72 3.294-.218.998-.425 1.046-.664 1.021-.238-.024-1.979-.438-3.425-1.454-1.447-1.016-2.062-2.025-1.633-2.608.409-.556 1.079-.893 2.157-1.154 1.032-.25 1.727-1.164 2.182-.97"/>
<path fill="#4F2A93" d="M22.458 42.36c-.24-.025-1.98-.439-3.425-1.455-1.15-.807-1.774-1.61-1.766-2.2a.138.138 0 0 1 .019-.027c.233-.302 1.651.06 3.193 1.031 1.47.925 2.526 1.988 2.271 2.573-.093.085-.19.088-.292.077"/>
<g>
<path fill="#A9DCF6" fill-opacity=".8" d="M12.754 15.163l.61 1.59a.626.626 0 0 1-.052.565c-1.185 1.837-5.732 3.582-7.843 3.01a.627.627 0 0 1-.415-.385l-.61-1.59c-.558-1.45-.348-3.129.461-4.39a.638.638 0 0 0-.37-.967c-1.446-.397-2.725-1.503-3.282-2.954l-.61-1.59a.625.625 0 0 1 .05-.564c1.187-1.837 5.734-3.582 7.844-3.01a.623.623 0 0 1 .416.384l.61 1.59c.557 1.45.347 3.129-.462 4.39a.638.638 0 0 0 .371.967c1.446.397 2.725 1.503 3.282 2.954"/>
<path fill="#FFF" fill-opacity=".9" d="M4.725 6.666c-1.35.518-2.307 1.167-2.767 1.665l.482 1.255c.402 1.046 1.333 1.883 2.43 2.184a1.922 1.922 0 0 1 1.284 1.159 1.92 1.92 0 0 1-.178 1.719c-.615.96-.747 2.204-.346 3.249l.483 1.256c.674.062 1.82-.096 3.17-.614 1.349-.518 2.306-1.167 2.765-1.664l-.482-1.257c-.401-1.044-1.332-1.881-2.43-2.182a1.922 1.922 0 0 1-1.284-1.16 1.924 1.924 0 0 1 .178-1.72c.615-.958.747-2.203.346-3.248l-.482-1.256c-.674-.062-1.82.096-3.17.614"/>
<path fill="#9A62FF" d="M4.93 7.61c1.013-.388 2.122-.706 2.229-.46.087.199.233.593-.43 1.325-.643.713-.508 1.512-.942 1.678-.505.194-.698-.222-1.476-.41-.802-.192-1.13-.743-1.212-.979-.115-.328.82-.765 1.832-1.153"/>
<path fill="#4F2A93" d="M4.31 9.744c-.801-.193-1.129-.743-1.211-.98-.091-.26.476-.587 1.219-.906-.17.19-.357.524-.116.948.25.443 1.188.678 1.228 1.138a.503.503 0 0 1-.036.241c-.28-.067-.537-.31-1.083-.44"/>
<path fill="#9A62FF" d="M7.418 13.683c.308-.118.603.413 1.185.59.713.218 1.436.544 1.87 1.247.358.58.28.698.154.797-.125.099-1.15.706-2.315.889-1.165.183-1.926-.016-1.991-.495-.061-.455.104-.927.5-1.552.38-.598.289-1.358.597-1.476"/>
<path fill="#4F2A93" d="M10.628 16.317c-.126.1-1.152.707-2.316.89-.926.144-1.597.048-1.866-.238a.092.092 0 0 1-.004-.022c-.027-.253.82-.736 2.01-.984 1.132-.237 2.132-.217 2.28.182-.006.084-.05.13-.104.172"/>
</g>
<g>
<path fill="#A9DCF6" fill-opacity=".8" d="M32.605 10.804l-.31 1.24a.47.47 0 0 1-.275.324c-1.518.619-5.062-.265-6.113-1.524a.47.47 0 0 1-.09-.416l.31-1.24c.281-1.13 1.132-2.07 2.172-2.498a.479.479 0 0 0 .188-.753c-.718-.866-1.027-2.096-.745-3.226l.309-1.24a.469.469 0 0 1 .274-.324c1.519-.619 5.063.265 6.113 1.524.097.114.127.27.09.415l-.308 1.24c-.282 1.13-1.133 2.071-2.173 2.498a.479.479 0 0 0-.188.754c.718.865 1.027 2.095.746 3.226"/>
<path fill="#FFF" fill-opacity=".9" d="M31.327 2.13c-1.052-.262-1.92-.276-2.416-.168l-.244.98c-.203.814.009 1.729.554 2.386.292.352.4.824.29 1.264a1.44 1.44 0 0 1-.849.98 2.762 2.762 0 0 0-1.61 1.847l-.244.98c.387.328 1.16.723 2.211.986 1.052.262 1.92.275 2.416.167l.244-.98a2.761 2.761 0 0 0-.554-2.385 1.442 1.442 0 0 1-.29-1.265c.11-.44.427-.806.849-.98a2.76 2.76 0 0 0 1.61-1.847l.244-.979c-.387-.328-1.159-.724-2.211-.986"/>
<path fill="#9A62FF" d="M31.047 2.799c.79.197 1.608.478 1.567.676-.032.159-.112.464-.834.629-.701.16-.962.71-1.3.625-.394-.098-.334-.436-.731-.886-.41-.464-.375-.943-.324-1.124.071-.25.833-.117 1.622.08"/>
<path fill="#4F2A93" d="M29.749 3.843c-.41-.464-.375-.943-.324-1.124.056-.198.546-.156 1.139-.032-.186.044-.444.169-.48.533-.036.38.44.927.266 1.227a.378.378 0 0 1-.126.133c-.143-.161-.197-.422-.475-.737"/>
<path fill="#9A62FF" d="M29.963 7.6c.24.06.193.513.474.872.344.44.648.952.613 1.57-.03.51-.128.55-.248.556-.12.007-1.012-.061-1.805-.45-.794-.388-1.177-.838-1.01-1.16.158-.306.462-.525.974-.739.49-.204.762-.71 1.002-.65"/>
<path fill="#4F2A93" d="M30.802 10.599c-.12.006-1.012-.062-1.806-.45-.63-.31-1.002-.657-1.043-.949a.069.069 0 0 1 .007-.015c.091-.167.82-.1 1.657.26.798.341 1.403.784 1.323 1.092-.04.05-.087.059-.138.062"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -4,6 +4,7 @@
<profileModal />
<report-flag-modal />
<send-gems-modal />
<select-user-modal />
<b-navbar
class="topbar navbar-inverse static-top"
toggleable="lg"
@@ -360,7 +361,7 @@
class="top-menu-icon svg-icon gem"
:aria-label="$t('gems')"
href="#buy-gems"
@click.prevent="showBuyGemsModal('gems')"
@click.prevent="showBuyGemsModal()"
v-html="icons.gem"
></a>
<span>{{ userGems }}</span>
@@ -719,6 +720,7 @@ import notificationMenu from './notificationsDropdown';
import profileModal from '../userMenu/profileModal';
import reportFlagModal from '../chat/reportFlagModal';
import sendGemsModal from '@/components/payments/sendGemsModal';
import selectUserModal from '@/components/payments/selectUserModal';
import sync from '@/mixins/sync';
import userDropdown from './userDropdown';
@@ -730,6 +732,7 @@ export default {
profileModal,
reportFlagModal,
sendGemsModal,
selectUserModal,
userDropdown,
},
mixins: [sync],
@@ -787,9 +790,7 @@ export default {
openPartyModal () {
this.$root.$emit('bv::show::modal', 'create-party-modal');
},
showBuyGemsModal (startingPage) {
this.$store.state.gemModalOptions.startingPage = startingPage;
showBuyGemsModal () {
Analytics.track({
hitType: 'event',
eventCategory: 'button',

View File

@@ -0,0 +1,95 @@
<template>
<div
class="notification d-flex flex-column justify-content-center text-center"
>
<strong class="mx-auto mb-2"> {{ $t('g1g1Announcement') }} </strong>
<p class="mx-4"> {{ $t('g1g1Details') }} </p>
<div
class="btn-secondary mx-auto d-flex"
@click="showSelectUser()"
>
<div class="m-auto"> {{ $t('sendGift') }} </div>
</div>
<div
class="notification-remove"
@click.stop="remove()"
>
<div class="svg-icon" v-html="icons.close"></div>
</div>
</div>
</template>
<style lang='scss' scoped>
@import '~@/assets/scss/colors.scss';
p, strong {
color: $white;
}
p {
font-size: 14px;
}
.notification {
background-image: url('~@/assets/images/g1g1-notif.png');
background-size: 378px 204px;
width: 378px;
height: 204px;
padding: 3rem;
position: relative;
overflow: hidden;
white-space: normal;
cursor: pointer;
}
.notification-remove {
position: absolute;
width: 18px;
height: 18px;
padding: 4px;
right: 24px;
top: 24px;
.svg-icon {
width: 10px;
height: 10px;
}
}
.btn-secondary {
width: 5.75rem;
min-height: 1.5rem;
border-radius: 2px;
border-color: $white;
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
font-size: 12px;
font-weight: bold;
}
</style>
<script>
import closeIcon from '@/assets/svg/close-teal.svg';
import { mapActions } from '@/libs/store';
export default {
props: ['notification'],
data () {
return {
icons: Object.freeze({
close: closeIcon,
}),
};
},
methods: {
...mapActions({
readNotification: 'notifications:readNotification',
}),
remove () {
this.readNotification({ notificationId: this.notification.id });
},
showSelectUser () {
this.$root.$emit('bv::show::modal', 'select-user-modal');
},
},
};
</script>

View File

@@ -147,6 +147,7 @@ import ACHIEVEMENT_JUST_ADD_WATER from './notifications/justAddWater';
import ACHIEVEMENT_LOST_MASTERCLASSER from './notifications/lostMasterclasser';
import ACHIEVEMENT_MIND_OVER_MATTER from './notifications/mindOverMatter';
import ONBOARDING_COMPLETE from './notifications/onboardingComplete';
import GIFT_ONE_GET_ONE from './notifications/g1g1';
import OnboardingGuide from './onboardingGuide';
export default {
@@ -176,6 +177,7 @@ export default {
VERIFY_USERNAME,
OnboardingGuide,
ONBOARDING_COMPLETE,
GIFT_ONE_GET_ONE,
},
data () {
return {
@@ -195,7 +197,7 @@ export default {
// listed in the order they should appear in the notifications panel.
// NOTE: Those not listed here won't be shown in the notification panel!
handledNotifications: [
'NEW_STUFF', 'GROUP_TASK_NEEDS_WORK',
'NEW_STUFF', 'GIFT_ONE_GET_ONE', 'GROUP_TASK_NEEDS_WORK',
'GUILD_INVITATION', 'PARTY_INVITATION', 'CHALLENGE_INVITATION',
'QUEST_INVITATION', 'GROUP_TASK_ASSIGNED', 'GROUP_TASK_APPROVAL', 'GROUP_TASK_APPROVED',
'GROUP_TASK_CLAIMED', 'NEW_MYSTERY_ITEMS', 'CARD_RECEIVED',

View File

@@ -75,7 +75,7 @@
>{{ $t('logout') }}</a>
<li
v-if="!user.purchased.plan.customerId"
@click="showBuyGemsModal('subscribe')"
@click="showBuyGemsModal()"
>
<div class="dropdown-item text-center">
<h3 class="purple">
@@ -176,9 +176,7 @@ export default {
showProfile (startingPage) {
this.$router.push({ name: startingPage });
},
showBuyGemsModal (startingPage) {
this.$store.state.gemModalOptions.startingPage = startingPage;
showBuyGemsModal () {
Analytics.track({
hitType: 'event',
eventCategory: 'button',

View File

@@ -23,23 +23,6 @@
</div>
</div>
</div>
<div class="d-flex nav justify-content-center">
<div
class="nav-item text-center"
:class="{active: selectedPage === 'subscribe'}"
@click="selectedPage = 'subscribe'"
>
{{ $t('subscribe') }}
</div>
<div
class="nav-item text-center"
:class="{active: selectedPage === 'gems'}"
@click="selectedPage = 'gems'"
>
{{ $t('buyGems') }}
</div>
</div>
<div v-show="selectedPage === 'gems'">
<div v-if="hasSubscription">
<div class="row text-center">
<h2 class="mx-auto text-leadin">
@@ -187,301 +170,6 @@
{{ $t('buyGemsSupportsDevs') }}
</div>
</div>
</div>
<div v-show="selectedPage === 'subscribe'">
<div v-if="hasSubscription">
<div class="row text-center">
<h2 class="mx-auto text-leadin">
{{ $t('subscriptionAlreadySubscribedLeadIn') }}
</h2>
</div>
<div class="row text-center">
<div class="col-10 offset-1">
<p v-html="$t('subscriptionAlreadySubscribed1')"></p>
</div>
</div>
</div>
<div v-if="!hasSubscription">
<div class="row text-center">
<h2 class="mx-auto text-leadin">
{{ $t('subscriptionBenefitLeadin') }}
</h2>
</div>
<div class="row">
<div class="col">
<div class="row">
<div class="col-md-2 offset-1">
<div class="d-flex bubble justify-content-center align-items-center">
<div
class="svg-icon check mx-auto"
v-html="icons.check"
></div>
</div>
</div>
<div class="col-md-8 align-self-center">
<p>{{ $t('subscriptionBenefit1') }}</p>
</div>
</div>
<div class="row">
<div class="col-md-2 offset-1">
<div class="d-flex bubble justify-content-center align-items-center">
<div
class="svg-icon check mx-auto"
v-html="icons.check"
></div>
</div>
</div>
<div class="col-md-8 align-self-center">
<p>{{ $t('subscriptionBenefit2') }}</p>
</div>
</div>
<div class="row">
<div class="col-md-2 offset-1">
<div class="d-flex bubble justify-content-center align-items-center">
<div
class="svg-icon check mx-auto"
v-html="icons.check"
></div>
</div>
</div>
<div class="col-md-8 align-self-center">
<p>{{ $t('subscriptionBenefit3') }}</p>
</div>
</div>
</div>
<div class="col">
<div class="row">
<div class="col-md-2 offset-1">
<div class="d-flex bubble justify-content-center align-items-center">
<div
class="svg-icon check mx-auto"
v-html="icons.check"
></div>
</div>
</div>
<div class="col-md-8 align-self-center">
<p>{{ $t('subscriptionBenefit4') }}</p>
</div>
</div>
<div class="row">
<div class="col-md-2 offset-1">
<div class="d-flex bubble justify-content-center align-items-center">
<div
class="svg-icon check mx-auto"
v-html="icons.check"
></div>
</div>
</div>
<div class="col-md-8 align-self-center">
<p>{{ $t('subscriptionBenefit5') }}</p>
</div>
</div>
<div class="row">
<div class="col-md-2 offset-1">
<div class="d-flex bubble justify-content-center align-items-center">
<div
class="svg-icon check mx-auto"
v-html="icons.check"
></div>
</div>
</div>
<div class="col-md-8 align-self-center">
<p>{{ $t('subscriptionBenefit6') }}</p>
</div>
</div>
</div>
</div>
<div class="card-deck">
<div
class="card text-center"
:class="{active: subscriptionPlan === 'basic_earned'}"
>
<div class="card-body">
<div class="subscription-price">
<span class="superscript">$</span>
<span>5</span>
<span class="superscript muted">.00</span>
</div>
<div
v-once
class="small"
>
{{ $t('everyMonth') }}
</div>
<div class="divider"></div>
<p
v-markdown="$t('earnGemsMonthly', {cap:25})"
class="benefits"
></p>
<div class="spacer"></div>
<button
class="btn btn-primary"
@click="subscriptionPlan = 'basic_earned'"
>
{{ subscriptionPlan === "basic_earned" ? $t('selected') : $t('select') }}
</button>
</div>
</div>
<div
class="card text-center"
:class="{active: subscriptionPlan === 'basic_3mo'}"
>
<div class="card-body">
<div class="subscription-price">
<span class="superscript">$</span>
<span>15</span>
<span class="superscript muted">.00</span>
</div>
<div
v-once
class="small"
>
{{ $t('everyXMonths', {interval: 3}) }}
</div>
<div class="divider"></div>
<p
v-markdown="$t('earnGemsMonthly', {cap:30})"
class="benefits"
></p>
<p
v-markdown="$t('receiveMysticHourglass')"
class="benefits"
></p>
<button
class="btn btn-primary"
@click="subscriptionPlan = 'basic_3mo'"
>
{{ subscriptionPlan === "basic_3mo" ? $t('selected') : $t('select') }}
</button>
</div>
</div>
<div
class="card text-center"
:class="{active: subscriptionPlan === 'basic_6mo'}"
>
<div class="card-body">
<div class="subscription-price">
<span class="superscript">$</span>
<span>30</span>
<span class="superscript muted">.00</span>
</div>
<div
v-once
class="small"
>
{{ $t('everyXMonths', {interval: 6}) }}
</div>
<div class="divider"></div>
<p
v-markdown="$t('earnGemsMonthly', {cap:35})"
class="benefits"
></p>
<p
v-markdown="$t('receiveMysticHourglasses', {amount:2})"
class="benefits"
></p>
<button
class="btn btn-primary"
@click="subscriptionPlan = 'basic_6mo'"
>
{{ subscriptionPlan === "basic_6mo" ? $t('selected') : $t('select') }}
</button>
</div>
</div>
<div
class="card text-center"
:class="{active: subscriptionPlan === 'basic_12mo'}"
>
<div class="card-body">
<div class="subscription-price">
<span class="superscript">$</span>
<span>48</span>
<span class="superscript muted">.00</span>
</div>
<div
v-once
class="small"
>
{{ $t('everyYear') }}
</div>
<div class="divider"></div>
<p
v-markdown="$t('earnGemsMonthly', {cap:45})"
class="benefits"
></p>
<p
v-markdown="$t('receiveMysticHourglasses', {amount:4})"
class="benefits"
></p>
<button
class="btn btn-primary"
@click="subscriptionPlan = 'basic_12mo'"
>
{{ subscriptionPlan === "basic_12mo" ? $t('selected') : $t('select') }}
</button>
</div>
</div>
</div>
<div
v-if="subscriptionPlan"
class="row text-center"
>
<h2
v-once
class="mx-auto text-payment"
>
{{ $t('choosePaymentMethod') }}
</h2>
</div>
<div class="row text-center">
<a
v-once
class="mx-auto"
>{{ $t('haveCouponCode') }}</a>
</div>
<div
v-if="subscriptionPlan"
class="payments-column"
>
<button
class="purchase btn btn-primary payment-button payment-item"
@click="showStripe({subscription: subscriptionPlan})"
>
<div
class="svg-icon credit-card-icon"
v-html="icons.creditCardIcon"
></div>
{{ $t('card') }}
</button>
<button
class="btn payment-item paypal-checkout payment-button"
@click="openPaypal(paypalSubscriptionLink, 'subscription')"
>
&nbsp;
<img
src="~@/assets/images/paypal-checkout.png"
:alt="$t('paypal')"
>&nbsp;
</button>
<amazon-button
class="payment-item"
:amazon-data="{type: 'subscription', subscription: subscriptionPlan}"
/>
</div>
<div class="row text-center">
<div
class="svg-icon mx-auto"
style="'height: 24px; width: 24px;'"
v-html="icons.heart"
></div>
</div>
<div class="row text-center text-outtro">
<div class="col-6 offset-3">
{{ $t('subscribeSupportsDevs') }}
</div>
</div>
</div>
</div>
</b-modal>
</div>
</template>
@@ -522,10 +210,6 @@
font-size: 16px;
}
.benefits {
font-size: 14px;
}
.bubble {
width: 32px;
height: 32px;
@@ -579,46 +263,6 @@
height: 56px;
}
.muted {
color: #c3c0c7;
}
.nav {
font-weight: bold;
background-color: $gray-600;
}
.nav-item {
box-sizing: border-box;
display: inline-block;
font-size: 16px;
margin: 0rem;
padding: 1rem;
width: 7.5rem;
}
.nav-item:hover, .nav-item.active {
color: #4f2a93;
border-bottom: 4px solid $purple-300;
cursor: pointer;
}
.spacer {
height: 4em;
}
.subscription-price {
font-family: Roboto Condensed;
font-size: 48px;
font-weight: bold;
color: #1ca372;
}
.superscript {
font-size: 24px;
vertical-align: super;
}
.svg-icon.check {
color: #bda8ff;
width: 1rem;
@@ -696,9 +340,6 @@ export default {
},
computed: {
...mapState({ user: 'user.data' }),
startingPageOption () {
return this.$store.state.gemModalOptions.startingPage;
},
hasSubscription () {
return Boolean(this.user.purchased.plan.customerId);
},
@@ -708,11 +349,6 @@ export default {
>= (this.user.purchased.plan.consecutive.gemCapExtra + this.planGemLimits.convCap);
},
},
watch: {
startingPageOption () {
this.selectedPage = this.$store.state.gemModalOptions.startingPage;
},
},
methods: {
close () {
this.$root.$emit('bv::hide::modal', 'buy-gems');

View File

@@ -0,0 +1,220 @@
<template>
<b-modal
id="select-user-modal"
:hide-header="true"
:hide-footer="true"
@hide="onHide()"
>
<h2 class="ml-2"> {{ $t('sendGift')}} </h2>
<div class="d-flex flex-column align-items-center">
<div
class="modal-close"
@click="close()"
>
<div class="svg-icon" v-html="icons.close"></div>
</div>
<div class="ml-2 mr-auto">
<strong> {{ $t('sendGiftToWhom')}} </strong>
</div>
<div
class="form"
name="selectUser"
novalidate="novalidate"
>
<div class="input-group">
<input
id="selectUser"
v-model="userSearchTerm"
class="form-control"
type="text"
:placeholder="$t('usernameOrUserId')"
:class="{
'input-valid': foundUser._id,
'is-invalid input-invalid': userNotFound,
}"
>
</div>
<div
v-if="userSearchTerm.length > 0 && userNotFound"
class="input-error text-center mt-2"
>
{{ $t('userWithUsernameOrUserIdNotFound') }}
</div>
<div class="d-flex justify-content-center align-items-middle mt-3">
<a
class="my-auto ml-auto mr-3 cancel-link"
@click="close()"
>
{{ $t('cancel') }}
</a>
<button
class="btn btn-primary my-auto mr-auto"
type="submit"
:disabled="searchCannotSubmit"
@click="selectUser()"
>
{{ $t('selectGift') }}
</button>
</div>
</div>
</div>
</b-modal>
</template>
<style lang="scss">
@import '~@/assets/scss/modal.scss';
#select-user-modal {
@include centeredModal();
.modal-dialog {
width: 29.5rem;
margin-top: 25vh;
}
}
</style>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
a:not([href]) {
color: $blue-10;
font-size: 16px;
}
.form-control {
width: 26.5rem;
border: 0px;
color: $gray-50;
}
.g1g1 {
background-image: url('~@/assets/images/g1g1-send.png');
background-size: 472px 152px;
width: 470px;
height: 152px;
margin: -1rem 0rem 0rem -1rem;
border-radius: 0.3rem 0.3rem 0rem 0rem;
padding: 1.5rem;
color: $white;
.heading {
font-size: 16px;
font-weight: bold;
margin-bottom: 1rem;
}
.details {
padding: 0rem 6rem;
}
}
.input-error {
color: $red-50;
font-size: 90%;
width: 100%;
}
.input-group {
border-radius: 2px;
border: solid 1px $gray-400;
margin-top: 0.5rem;
}
.input-group:focus-within {
border-color: $purple-500;
}
.modal-close {
position: absolute;
width: 18px;
height: 18px;
padding: 4px;
right: 16px;
top: 16px;
cursor: pointer;
.svg-icon {
width: 12px;
height: 12px;
}
}
</style>
<script>
import debounce from 'lodash/debounce';
import isUUID from 'validator/lib/isUUID';
import closeIcon from '@/assets/svg/close.svg';
export default {
data () {
return {
userNotFound: false,
userSearchTerm: '',
foundUser: {},
icons: Object.freeze({
close: closeIcon,
}),
};
},
computed: {
searchCannotSubmit () {
if (this.userSearchTerm.length < 1) return true;
return typeof this.foundUser._id === 'undefined';
},
},
watch: {
userSearchTerm: {
handler () {
this.searchUser(this.userSearchTerm);
},
},
},
methods: {
close () {
this.$root.$emit('habitica::dismiss-modal', 'select-user-modal');
this.$root.$emit('bv::hide::modal', 'select-user-modal');
},
searchUser: debounce(async function userSearch (searchTerm) {
this.foundUser = {};
if (searchTerm.length < 1) {
this.userNotFound = false;
return;
}
let result;
if (isUUID(searchTerm)) {
try {
result = await this.$store.dispatch('members:fetchMember', {
memberId: searchTerm,
});
} catch {
result = null;
}
} else {
try {
result = await this.$store.dispatch('members:fetchMemberByUsername', {
username: searchTerm,
});
} catch {
result = null;
}
}
if (!result || !result.data || !result.data.data) {
this.userNotFound = true;
return;
}
this.userNotFound = false;
this.foundUser = result.data.data;
}, 500),
selectUser () {
this.$root.$emit('habitica::send-gems', this.foundUser);
this.close();
},
onHide () {
this.userNotFound = false;
this.userSearchTerm = '';
this.foundUser = {};
},
},
};
</script>

View File

@@ -2,7 +2,6 @@
<b-modal
id="payments-success-modal"
:title="$t('accountSuspendedTitle')"
size="sm"
:hide-footer="isFromBalance"
:modal-class="isFromBalance ? ['modal-hidden-footer'] : []"
>
@@ -102,6 +101,10 @@
<style lang="scss">
@import '~@/assets/scss/colors.scss';
#payments-success-modal .modal-md {
max-width: 20.5rem;
}
#payments-success-modal .modal-content {
background: transparent;
}
@@ -115,7 +118,7 @@
justify-content: center;
padding-top: 24px;
padding-bottom: 0px;
background: $green-10;
background: $green-100;
border-top-right-radius: 8px;
border-top-left-radius: 8px;
border-bottom: none;
@@ -241,6 +244,7 @@ export default {
methods: {
close () {
this.paymentData = {};
this.$root.$emit('habitica::dismiss-modal', 'payments-success-modal');
this.$root.$emit('bv::hide::modal', 'payments-success-modal');
},
},

View File

@@ -1,242 +1,282 @@
<template>
<div class="standard-page pt-0 px-0">
<h1>{{ $t('subscription') }}</h1>
<div class="row">
<div class="col-6">
<h2>{{ $t('benefits') }}</h2>
<ul>
<li>
<span
class="hint"
:popover="$t('buyGemsGoldText', {gemCostTranslation})"
popover-trigger="mouseenter"
popover-placement="right"
>{{ $t('buyGemsGold') }}</span>
<span
v-if="subscription.key !== 'basic_earned'"
class="badge badge-success"
>{{ $t('buyGemsGoldCap', buyGemsGoldCap) }}</span>
</li>
<li>
<span
class="hint"
:popover="$t('retainHistoryText')"
popover-trigger="mouseenter"
popover-placement="right"
>{{ $t('retainHistory') }}</span>
</li>
<li>
<span
class="hint"
:popover="$t('doubleDropsText')"
popover-trigger="mouseenter"
popover-placement="right"
>{{ $t('doubleDrops') }}</span>
</li>
<li>
<span
class="hint"
:popover="$t('mysteryItemText')"
popover-trigger="mouseenter"
popover-placement="right"
>{{ $t('mysteryItem') }}</span>
<div v-if="subscription.key !== 'basic_earned'">
<div class="badge badge-success">
{{ $t('mysticHourglass', mysticHourglass) }}
</div>
<div class="small muted">
{{ $t('mysticHourglassText') }}
<div v-if="!hasSubscription && !hasCanceledSubscription">
<div class="row mt-3">
<div class="block-header mx-auto">
{{ $t('support') }}
</div>
</div>
</li>
<li>
<span
class="hint"
:popover="$t('exclusiveJackalopePetText')"
popover-trigger="mouseenter"
popover-placement="right"
>{{ $t('exclusiveJackalopePet') }}</span>
</li>
<li>
<span
class="hint"
:popover="$t('supportDevsText')"
popover-trigger="mouseenter"
popover-placement="right"
>{{ $t('supportDevs') }}</span>
</li>
</ul>
</div>
<div class="col-6">
<h2>Plan</h2>
<table
v-if="hasSubscription"
class="table alert alert-info"
>
<tr v-if="hasCanceledSubscription">
<td class="alert alert-warning">
<span class="noninteractive-button btn-danger">{{ $t('canceledSubscription') }}</span>
<i class="glyphicon glyphicon-time"></i>
{{ $t('subCanceled') }} &nbsp;
<strong>{{ dateTerminated }}</strong>
</td>
</tr>
<tr v-if="!hasCanceledSubscription">
<td>
<h4>{{ $t('subscribed') }}</h4>
<p v-if="hasPlan && !hasGroupPlan">
{{ $t('purchasedPlanId', purchasedPlanIdInfo) }}
</p>
<p v-if="hasGroupPlan">
{{ $t('youHaveGroupPlan') }}
</p>
</td>
</tr>
<tr v-if="user.purchased.plan.extraMonths">
<td>
<span class="glyphicon glyphicon-credit-card"></span>
&nbsp; {{ $t('purchasedPlanExtraMonths', purchasedPlanExtraMonthsDetails) }}
</td>
</tr>
<tr v-if="hasConsecutiveSubscription">
<td>
<span class="glyphicon glyphicon-forward"></span>
&nbsp; {{ $t('consecutiveSubscription') }}
<ul class="list-unstyled">
<li>{{ $t('consecutiveMonths') }} {{ user.purchased.plan.consecutive.count + user.purchased.plan.consecutive.offset }}</li> <!-- eslint-disable-line max-len -->
<li>{{ $t('gemCapExtra') }} {{ user.purchased.plan.consecutive.gemCapExtra }}</li>
<li>{{ $t('mysticHourglasses') }} {{ user.purchased.plan.consecutive.trinkets }}</li> <!-- eslint-disable-line max-len -->
</ul>
</td>
</tr>
</table>
<div v-if="!hasSubscription || hasCanceledSubscription">
<h4 v-if="hasCanceledSubscription">
{{ $t("resubscribe") }}
</h4>
<div class="form-group reduce-top-margin">
<!-- eslint-disable vue/no-use-v-if-with-v-for -->
<div class="row mb-5">
<div
v-for="block in subscriptionBlocksOrdered"
v-if="block.target !== 'group' && block.canSubscribe === true"
:key="block.key"
class="radio"
>
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
<label>
<input
v-model="subscription.key"
type="radio"
name="subRadio"
:value="block.key"
>
<span v-if="block.original">
<span class="label label-success line-through">${{ block.original }}</span>
{{ $t('subscriptionRateText', {price: block.price, months: block.months}) }}
</span>
<span
v-if="!block.original"
>{{ $t('subscriptionRateText', {price: block.price, months: block.months}) }}</span>
</label>
v-once
class="svg-icon svg-logo mx-auto mt-1"
v-html="icons.logo"
></div>
</div>
<div class="d-flex justify-content-center">
<div>
<div class="row col-12 ml-1">
<h2> {{ $t('subscribersReceiveBenefits') }} </h2>
</div>
<div class="row">
<div class="col-2">
<div
v-once
class="svg-icon svg-gems ml-3 mt-1"
v-html="icons.subscriberGems"
></div>
</div>
<div class="col-10">
<h3> {{ $t('buyGemsGold') }} </h3>
<p> {{ $t('subscriptionBenefit1') }} </p>
</div>
</div>
<div class="form-inline">
<div class="form-group">
<input
v-model="subscription.coupon"
class="form-control"
type="text"
:placeholder="$t('couponPlaceholder')"
<div class="row">
<div class="col-2">
<div
v-once
class="svg-icon svg-hourglasses ml-3 mt-1"
v-html="icons.subscriberHourglasses"
></div>
</div>
<div class="col-10">
<h3> {{ $t('mysticHourglassesTooltip') }} </h3>
<p> {{ $t('subscriptionBenefit6') }} </p>
</div>
</div>
<div class="row">
<div class="col-2">
<div
:class="currentMysterySet"
class="mt-n1"
></div>
</div>
<div class="col-10">
<h3> {{ $t('monthlyMysteryItems') }} </h3>
<p> {{ $t('subscriptionBenefit4') }} </p>
</div>
</div>
<div class="row">
<div class="col-2">
<div class="Pet-Jackalope-RoyalPurple"></div>
</div>
<div class="col-10">
<h3> {{ $t('exclusiveJackalopePet') }} </h3>
<p> {{ $t('subscriptionBenefit5') }} </p>
</div>
</div>
<div class="row">
<div class="col-2">
<div class="image-foods ml-2 mt-2"></div>
</div>
<div class="col-10">
<h3> {{ $t('doubleDropCap') }} </h3>
<p> {{ $t('subscriptionBenefit3') }} </p>
</div>
</div>
</div>
<div class="flex-spacer"></div>
<div>
<div class="subscribe-card d-flex flex-column">
<subscription-options class="mb-4"/>
</div>
</div>
</div>
</div>
<div
v-if="hasSubscription"
class="d-flex flex-column align-items-center"
>
<h1 class="mt-4 mx-auto">{{ $t('subscription') }}</h1>
<div class="subscribe-card mx-auto">
<div
v-if="hasSubscription && !hasCanceledSubscription"
class="d-flex flex-column align-items-center my-4"
>
<div class="round-container bg-green-10 d-flex align-items-center justify-content-center">
<div
v-once
class="svg-icon svg-check"
v-html="icons.checkmarkIcon"
></div>
</div>
<h2 class="green-10 mx-auto">{{ $t('youAreSubscribed') }}</h2>
<div
v-if="hasGroupPlan"
class="mx-5 text-center"
>
{{ $t('youHaveGroupPlan') }}
</div>
<div
v-else
class="w-55 text-center"
v-html="$t('paymentSubBillingWithMethod', {
amount: purchasedPlanIdInfo.price,
months: purchasedPlanIdInfo.months,
paymentMethod: purchasedPlanIdInfo.plan
})"
>
</div>
<div class="form-group">
<button
class="btn btn-primary"
type="button"
@click="applyCoupon(subscription.coupon)"
>
{{ $t("apply") }}
</button>
</div>
</div>
</div>
<div v-if="hasSubscription">
<div
v-if="canEditCardDetails"
class="btn btn-primary"
class="mt-4 text-center"
>
<div class="font-weight-bold gray-10 mb-2">{{ $t('needToUpdateCard') }}</div>
<button
class="btn btn-primary btn-update-card
d-flex justify-content-center align-items-center"
@click="showStripeEdit()"
>
{{ $t('subUpdateCard') }}
<div
v-once
class="svg-icon svg-credit-card mr-2"
v-html="icons.creditCardIcon"
></div>
<div>{{ $t('subUpdateCard') }}</div>
</button>
</div>
<div
v-if="canCancelSubscription && !loading"
class="btn btn-sm btn-danger"
@click="cancelSubscriptionConfirm()"
v-else
class="svg-icon"
:class="paymentMethodLogo.class"
v-html="paymentMethodLogo.icon"
>
</div>
<div
v-if="purchasedPlanExtraMonthsDetails.months > 0"
class="extra-months green-10 py-2 px-3 mt-4"
v-html="$t('purchasedPlanExtraMonths',
{months: purchasedPlanExtraMonthsDetails.months})"
>
</div>
</div>
<div
v-if="hasCanceledSubscription"
class="d-flex flex-column align-items-center mt-4"
>
<div class="round-container bg-gray-300 d-flex align-items-center justify-content-center">
<div
v-once
class="svg-icon svg-close"
v-html="icons.closeIcon"
></div>
</div>
<h2 class="gray-50">{{ $t('subscriptionCanceled') }}</h2>
<div
class="w-75 text-center mb-4"
v-html="$t('subscriptionInactiveDate', {date: subscriptionEndDate})"
>
</div>
<h2>{{ $t('readyToResubscribe') }}</h2>
<subscription-options class="w-100 mb-2"/>
</div>
<div
v-if="hasSubscription"
class="bg-gray-700 p-2 text-center"
>
<div class="header-mini mb-3">{{ $t('subscriptionStats') }}</div>
<div class="d-flex justify-content-around">
<div class="ml-4 mr-3">
<div class="d-flex justify-content-center align-items-center">
<div
v-once
class="svg-icon svg-calendar mr-2"
v-html="icons.calendarIcon"
>
</div>
<div class="number-heavy">
{{ user.purchased.plan.consecutive.count +
user.purchased.plan.consecutive.offset }}
</div>
</div>
<div class="stats-label">{{ $t('subMonths') }}</div>
</div>
<div class="stats-spacer"></div>
<div>
<div class="d-flex justify-content-center align-items-center">
<div
v-once
class="svg-icon svg-gem mr-2"
v-html="icons.gemIcon"
>
</div>
<div class="number-heavy">
{{ user.purchased.plan.consecutive.gemCapExtra }}
</div>
</div>
<div class="stats-label">{{ $t('gemCapExtra') }}</div>
</div>
<div class="stats-spacer"></div>
<div>
<div class="d-flex justify-content-center align-items-center">
<div
v-once
class="svg-icon svg-hourglass mt-1 mr-2"
v-html="icons.hourglassIcon"
>
</div>
<div class="number-heavy">
{{ user.purchased.plan.consecutive.trinkets }}
</div>
</div>
<div class="stats-label">{{ $t('mysticHourglassesTooltip') }}</div>
</div>
</div>
</div>
<div class="d-flex flex-column justify-content-center align-items-center mt-4 mb-3">
<div
v-once
class="svg-icon svg-heart mb-1"
v-html="icons.heartIcon"
>
</div>
<div class="stats-label">{{ $t('giftSubscriptionText4') }}</div>
</div>
</div>
</div>
<div
v-if="hasSubscription && !hasCanceledSubscription"
class="d-flex flex-column align-items-center mt-3"
>
<div class="cancel-card p-4 text-center">
<h2 class="maroon-50">{{ $t('cancelYourSubscription') }}</h2>
<div v-if="hasGroupPlan">{{ $t('cancelSubInfoGroupPlan') }}</div>
<div
v-if="!hasGroupPlan && !canCancelSubscription"
v-html="$t(`cancelSubInfo${user.purchased.plan.paymentMethod}`)"
>
</div>
<div
v-if="canCancelSubscription"
v-html="$t('cancelSubAlternatives')"
>
</div>
<div
class="btn btn-danger mt-4"
:class="{disabled: !canCancelSubscription}"
:disabled="!canCancelSubscription"
@click="cancelSubscriptionConfirm({canCancel: canCancelSubscription})"
>
{{ $t('cancelSub') }}
</div>
<small
v-if="!canCancelSubscription && !hasCanceledSubscription"
v-html="getCancelSubInfo()"
></small>
</div>
</div>
<div class="d-flex flex-column align-items-center mt-4">
<div
v-if="!hasSubscription || hasCanceledSubscription"
class="subscribe-pay"
v-once
class="svg-icon svg-gift-box m-auto"
v-html="icons.giftBox"
>
<h3>{{ $t('subscribeUsing') }}</h3>
<div class="payments-column">
<button
class="purchase btn btn-primary payment-button payment-item"
:disabled="!subscription.key"
@click="showStripe({subscription:subscription.key, coupon:subscription.coupon})"
>
<div
class="svg-icon credit-card-icon"
v-html="icons.creditCardIcon"
></div>
{{ $t('card') }}
</button>
<button
class="btn payment-item paypal-checkout payment-button"
:disabled="!subscription.key"
@click="openPaypal(paypalPurchaseLink, 'subscription')"
>
&nbsp;
<img
src="~@/assets/images/paypal-checkout.png"
:alt="$t('paypal')"
>&nbsp;
</button>
<amazon-button
class="payment-item"
:amazon-data="{
type: 'subscription', subscription: subscription.key, coupon: subscription.coupon}"
/>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<h2 v-once>
<div class="muted mx-auto mt-3 mb-1">
{{ $t('giftSubscription') }}
</h2>
<ol>
<li v-once>
{{ $t('giftSubscriptionText1') }}
</li>
<li v-once>
{{ $t('giftSubscriptionText2') }}
</li>
<li v-once>
{{ $t('giftSubscriptionText3') }}
</li>
</ol>
<h4 v-once>
{{ $t('giftSubscriptionText4') }}
</h4>
</div>
<a
class="mx-auto"
@click="showSelectUser()"
>
{{ $t('giftASubscription') }}
</a>
</div>
</div>
</template>
@@ -244,20 +284,227 @@
<style scoped lang="scss">
@import '~@/assets/scss/colors.scss';
.badge.badge-success {
a {
color: $purple-300;
}
h1, h2 {
color: $purple-200;
}
p {
max-width: 21rem;
}
strong {
font-size: 16px;
}
.bg-green-10 {
background-color: $green-10;
}
.bg-gray-300 {
background-color: $gray-300;
}
.bg-gray-700 {
background-color: $gray-700;
}
.block-header {
color: $purple-200;
letter-spacing: 0.25rem;
font-size: 20px;
}
.btn-update-card {
width: 12.5rem;
height: 2.5rem;
border-radius: 4px;
font-size: 14px;
}
.cancel-card {
width: 28rem;
border: 2px solid $gray-500;
border-radius: 4px;
}
.disabled {
opacity: 0.64;
.btn, .btn:hover, .btn:active {
box-shadow: none;
cursor: default !important;
}
}
.extra-months {
border-radius: 2px;
border: 1px solid $green-50;
}
.flex-spacer {
width: 4rem;
}
.gray-10 {
color: $gray-10;
}
.gray-50 {
color: $gray-50;
}
.green-10 {
color: $green-10;
}
.header-mini {
font-size: 12px;
font-weight: bold;
}
.image-foods {
background: url(~@/assets/images/subscriber-food.png);
background-size: contain;
width: 46px;
height: 49px;
}
.maroon-50 {
color: $maroon-50;
}
.muted {
font-size: 14px;
color: $gray-200;
}
.number-heavy {
font-size: 24px;
}
.Pet-Jackalope-RoyalPurple {
margin-top: -1.75rem;
transform: scale(0.75);
}
.round-container {
width: 64px;
height: 64px;
border-radius: 50%;
margin: 0 auto;
margin-bottom: 16px;
}
.stats-label {
font-size: 12px;
color: $gray-200;
}
.stats-spacer {
width: 1px;
height: 3rem;
background-color: $gray-500;
}
.subscribe-card {
width: 28rem;
border-radius: 4px;
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
background-color: $white;
}
.subscribe-option {
border-bottom: 1px solid $gray-600;
}
.svg-amazon-pay {
width: 208px;
}
.svg-apple-pay {
width: 97.1px;
height: 40px;
}
.svg-calendar, .svg-heart {
width: 24px;
height: 24px;
}
.svg-check {
width: 35.1px;
height: 28px;
color: $white;
}
.subscribe-pay {
margin-top: 1em;
.svg-close {
width: 26px;
height: 26px;
& ::v-deep svg path {
stroke: $white;
stroke-width: 3;
}
}
.svg-credit-card {
width: 21.3px;
height: 16px;
}
.svg-gem {
width: 32px;
height: 28px;
}
.svg-gems {
width: 42px;
height: 52px;
}
.svg-google-pay {
width: 99.7px;
height: 40px;
}
.svg-hourglass {
width: 28px;
height: 28px;
}
.svg-gift-box {
width: 32px;
height: 32px;
}
.svg-hourglasses {
width: 43px;
height: 53px;
}
.svg-logo {
width: 256px;
height: 56px;
}
.svg-paypal {
width: 148px;
height: 40px;
}
.w-55 {
width: 55%;
}
</style>
<script>
import axios from 'axios';
import filter from 'lodash/filter';
import sortBy from 'lodash/sortBy';
import min from 'lodash/min';
import moment from 'moment';
import { mapState } from '@/libs/store';
import subscriptionBlocks from '@/../../common/script/content/subscriptionBlocks';
@@ -265,12 +512,27 @@ import planGemLimits from '@/../../common/script/libs/planGemLimits';
import paymentsMixin from '../../mixins/payments';
import notificationsMixin from '../../mixins/notifications';
import amazonButton from '@/components/payments/amazonButton';
import subscriptionOptions from './subscriptionOptions.vue';
import amazonPayLogo from '@/assets/svg/amazonpay.svg';
import applePayLogo from '@/assets/svg/apple-pay-logo.svg';
import calendarIcon from '@/assets/svg/calendar-purple.svg';
import checkmarkIcon from '@/assets/svg/check.svg';
import closeIcon from '@/assets/svg/close.svg';
import creditCardIcon from '@/assets/svg/credit-card-icon.svg';
import gemIcon from '@/assets/svg/gem.svg';
import giftBox from '@/assets/svg/gift-purple.svg';
import googlePayLogo from '@/assets/svg/google-pay-logo.svg';
import heartIcon from '@/assets/svg/health.svg';
import hourglassIcon from '@/assets/svg/hourglass.svg';
import logo from '@/assets/svg/habitica-logo-purple.svg';
import paypalLogo from '@/assets/svg/paypal-logo.svg';
import subscriberGems from '@/assets/svg/subscriber-gems.svg';
import subscriberHourglasses from '@/assets/svg/subscriber-hourglasses.svg';
export default {
components: {
amazonButton,
subscriptionOptions,
},
mixins: [paymentsMixin, notificationsMixin],
data () {
@@ -281,7 +543,7 @@ export default {
gemLimit: planGemLimits.convRate,
},
subscription: {
key: 'basic_earned',
key: null,
},
// @TODO: Remove the need for this or move it to mixin
amazonPayments: {},
@@ -294,17 +556,26 @@ export default {
GIFT: 'Gift',
},
icons: Object.freeze({
amazonPayLogo,
applePayLogo,
calendarIcon,
checkmarkIcon,
closeIcon,
creditCardIcon,
gemIcon,
giftBox,
googlePayLogo,
heartIcon,
hourglassIcon,
logo,
paypalLogo,
subscriberGems,
subscriberHourglasses,
}),
};
},
computed: {
...mapState({ user: 'user.data', credentials: 'credentials' }),
subscriptionBlocksOrdered () {
const subscriptions = filter(subscriptionBlocks, o => o.discount !== true);
return sortBy(subscriptions, [o => o.months]);
},
purchasedPlanIdInfo () {
if (!this.subscriptionBlocks[this.user.purchased.plan.planId]) {
// @TODO: find which subs are in the common
@@ -391,6 +662,41 @@ export default {
&& !this.hasGroupPlan
);
},
currentMysterySet () {
return `shop_set_mystery_${moment().format('YYYYMM')}`;
},
paymentMethodLogo () {
switch (this.user.purchased.plan.paymentMethod) {
case this.paymentMethods.AMAZON_PAYMENTS:
return {
icon: this.icons.amazonPayLogo,
class: 'svg-amazon-pay mt-3',
};
case this.paymentMethods.APPLE:
return {
icon: this.icons.applePayLogo,
class: 'svg-apple-pay mt-4',
};
case this.paymentMethods.GOOGLE:
return {
icon: this.icons.googlePayLogo,
class: 'svg-google-pay mt-4',
};
case this.paymentMethods.PAYPAL:
return {
icon: this.icons.paypalLogo,
class: 'svg-paypal mt-4',
};
default:
return {
icon: null,
class: null,
};
}
},
subscriptionEndDate () {
return moment(this.user.purchased.plan.dateTerminated).format('MM/DD/YYYY');
},
},
methods: {
async applyCoupon (coupon) {
@@ -406,6 +712,9 @@ export default {
if (payMethod === 'Group Plan') payMethod = 'GroupPlan';
return this.$t(`cancelSubInfo${payMethod}`);
},
showSelectUser () {
this.$root.$emit('bv::show::modal', 'select-user-modal');
},
},
};
</script>

View File

@@ -0,0 +1,178 @@
<template>
<div id="subscription-form">
<b-form-group class="mb-4 w-100 h-100">
<!-- eslint-disable vue/no-use-v-if-with-v-for -->
<b-form-radio
v-for="block in subscriptionBlocksOrdered"
v-if="block.target !== 'group' && block.canSubscribe === true"
:value="block.key"
:key="block.key"
v-model="subscription.key"
class="subscribe-option pt-2 pl-5 pb-3 mb-0"
:class="{selected: subscription.key === block.key}"
@click.native="subscription.key = block.key"
>
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
<div
v-html="$t('subscriptionRateText', {price: block.price, months: block.months})"
class="subscription-text ml-2 mb-1"
>
</div>
<div
v-html="subscriptionBubbles(block.key)"
class="ml-2"
>
</div>
</b-form-radio>
</b-form-group>
<div class="payments-column mx-auto mt-auto">
<button
class="purchase btn btn-primary payment-button payment-item"
:class="{disabled: !subscription.key}"
:disabled="!subscription.key"
@click="showStripe({subscription:subscription.key, coupon:subscription.coupon})"
>
<div
v-once
class="svg-icon credit-card-icon"
v-html="icons.creditCardIcon"
></div>
{{ $t('card') }}
</button>
<button
class="btn payment-item paypal-checkout payment-button"
:class="{disabled: !subscription.key}"
:disabled="!subscription.key"
@click="openPaypal(paypalPurchaseLink, 'subscription')"
>
&nbsp;
<img
src="~@/assets/images/paypal-checkout.png"
:alt="$t('paypal')"
>&nbsp;
</button>
<amazon-button
class="payment-item"
:class="{disabled: !subscription.key}"
:disabled="!subscription.key"
:amazon-data="{
type: 'subscription',
subscription: subscription.key,
coupon: subscription.coupon
}"
/>
</div>
</div>
</template>
<style lang="scss">
@import '~@/assets/scss/colors.scss';
#subscription-form {
.disabled .amazonpay-button-inner-image {
cursor: default !important;
}
.custom-control .custom-control-label::before,
.custom-radio .custom-control-input:checked ~ .custom-control-label::after {
margin-top: 0.75rem;
}
.selected {
background-color: rgba(213, 200, 255, 0.32);
.subscription-bubble {
background-color: $purple-300;
color: $white;
}
.subscription-text {
color: $purple-200;
}
}
.subscription-bubble, .discount-bubble {
border-radius: 100px;
font-size: 12px;
}
.subscription-bubble {
background-color: $gray-600;
color: $gray-200;
}
.discount-bubble {
background-color: $green-10;
color: $white;
}
}
</style>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
.disabled {
opacity: 0.64;
.btn, .btn:hover, .btn:active {
box-shadow: none;
cursor: default !important;
}
}
.subscribe-option {
border-bottom: 1px solid $gray-600;
}
</style>
<script>
import filter from 'lodash/filter';
import sortBy from 'lodash/sortBy';
import amazonButton from '@/components/payments/amazonButton';
import creditCardIcon from '@/assets/svg/credit-card-icon.svg';
import paymentsMixin from '../../mixins/payments';
import subscriptionBlocks from '@/../../common/script/content/subscriptionBlocks';
export default {
components: {
amazonButton,
},
mixins: [
paymentsMixin,
],
data () {
return {
subscription: {
key: null,
},
icons: Object.freeze({
creditCardIcon,
}),
};
},
computed: {
subscriptionBlocks () {
return subscriptionBlocks;
},
subscriptionBlocksOrdered () {
const subscriptions = filter(subscriptionBlocks, o => o.discount !== true);
return sortBy(subscriptions, [o => o.months]);
},
},
methods: {
subscriptionBubbles (subscription) {
switch (subscription) {
case 'basic_3mo':
return '<span class="subscription-bubble px-2 py-1 mr-1">Gem cap raised to 30</span><span class="subscription-bubble px-2 py-1">+1 Mystic Hourglass</span>';
case 'basic_6mo':
return '<span class="subscription-bubble px-2 py-1 mr-1">Gem cap raised to 35</span><span class="subscription-bubble px-2 py-1">+2 Mystic Hourglass</span>';
case 'basic_12mo':
return '<span class="discount-bubble px-2 py-1 mr-1">Save 20%</span><span class="subscription-bubble px-2 py-1 mr-1">Gem cap raised to 45</span><span class="subscription-bubble px-2 py-1">+4 Mystic Hourglass</span>';
default:
return '<span class="subscription-bubble px-2 py-1">Gem cap at 25</span>';
}
},
},
};
</script>

View File

@@ -284,6 +284,7 @@ export default {
this.amazonPayments.group = null;
},
cancelSubscriptionConfirm (config) {
if (config.canCancel === false) return;
this.$root.$emit('habitica:cancel-subscription-confirm', config);
},
async cancelSubscription (config) {

View File

@@ -31,6 +31,12 @@ export async function fetchMember (store, payload) {
return response;
}
export async function fetchMemberByUsername (store, payload) {
const url = `${apiv4Prefix}/members/username/${payload.username}`;
const response = await axios.get(url);
return response;
}
export async function getGroupInvites (store, payload) {
let url = `${apiv4Prefix}/groups/${payload.groupId}/invites`;
if (payload.includeAllPublicFields) {

View File

@@ -114,9 +114,6 @@ export default function () {
profileOptions: {
startingPage: '',
},
gemModalOptions: {
startingPage: '',
},
rageModalOptions: {
npc: '',
},

View File

@@ -176,7 +176,9 @@
"messageWroteIn": "<%= user %> wrote in <%= group %>",
"msgPreviewHeading": "Message Preview",
"leaderOnlyChallenges": "Only group leader can create challenges",
"sendGift": "Send Gift",
"sendGift": "Send a Gift",
"selectGift": "Select Gift",
"sendGiftToWhom": "Who would you like to send a gift to?",
"inviteFriends": "Invite Friends",
"partyMembersInfo": "Your Party currently has <%= memberCount %> members and <%= invitationCount %> pending invitations. The limit of members in a Party is <%= limitMembers %>. Invitations above this limit cannot be sent.",
"inviteByEmail": "Invite by Email",
@@ -245,6 +247,8 @@
"userAlreadyInAParty": "UserID: <%= userId %>, User \"<%= username %>\" already in a party. ",
"userWithIDNotFound": "User with id \"<%= userId %>\" not found.",
"userWithUsernameNotFound": "User with username \"<%= username %>\" not found.",
"usernameOrUserId": "Username or User ID",
"userWithUsernameOrUserIdNotFound": "Username or User ID not found.",
"userHasNoLocalRegistration": "User does not have a local registration (username, email, password).",
"uuidsMustBeAnArray": "User ID invites must be an array.",
"emailsMustBeAnArray": "Email address invites must be an array.",
@@ -346,7 +350,7 @@
"aboutToJoinCancelledGroupPlan": "You are about to join a group with a canceled plan. You will NOT receive a free subscription.",
"cannotChangeLeaderWithActiveGroupPlan": "You can not change the leader while the group has an active plan.",
"leaderCannotLeaveGroupWithActiveGroup": "A leader can not leave a group while the group has an active plan",
"youHaveGroupPlan": "You have a free subscription because you are a member of a group that has a Group Plan. This will end when you are no longer in the group that has a Group Plan. Any months of extra subscription credit you have will be applied at the end of the Group Plan.",
"youHaveGroupPlan": "You have a free subscription because you are a member of a Group Plan. Your subscription will end when you are no longer a member of the Group Plan.",
"cancelGroupSub": "Cancel Group Plan",
"confirmCancelGroupPlan": "Are you sure you want to cancel your Group Plan? All Group members will lose their subscription and benefits.",
"canceledGroupPlan": "Group Plan Canceled",

View File

@@ -120,6 +120,7 @@
"paymentYouSentGems": "You sent <strong><%= name %></strong>:",
"paymentYouSentSubscription": "You sent <strong><%= name %></strong> a <%= months %>-months Habitica subscription.",
"paymentSubBilling": "Your subscription will be billed <strong>$<%= amount %></strong> every <strong><%= months %> months</strong>.",
"paymentSubBillingWithMethod": "Your subscription will be billed <strong>$<%= amount %></strong> every <strong><%= months %> months</strong> via <strong><%= paymentMethod %></strong>.",
"paymentAutoRenew": "This subscription will auto-renew until it is canceled. If you need to cancel this subscription, you can do so from your settings.",
"paymentCanceledDisputes": "Weve sent a cancelation confirmation to your email. If you dont see the email, please contact us to prevent future billing disputes.",
"success": "Success!",

View File

@@ -138,7 +138,7 @@
"unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, Habitica will never be able to notify me via email about important changes to the site or my account.",
"unsubscribeAllPush": "Check to Unsubscribe from all Push Notifications",
"correctlyUnsubscribedEmailType": "Correctly unsubscribed from \"<%= emailType %>\" emails.",
"subscriptionRateText": "Recurring $<%= price %> USD every <%= months %> months",
"subscriptionRateText": "Recurring <strong>$<%= price %> USD</strong> every <strong><%= months %> months</strong>",
"recurringText": "recurring",
"benefits": "Benefits",
"coupon": "Coupon",
@@ -175,14 +175,15 @@
"pushDeviceAlreadyAdded": "The user already has the push device",
"pushDeviceNotFound": "The user has no push device with this id.",
"pushDeviceRemoved": "Push device removed successfully.",
"buyGemsGoldCap": "Cap raised to <%= amount %>",
"buyGemsGoldCapBase": "Gem cap at <%= amount %>",
"buyGemsGoldCap": "Gem cap raised to <%= amount %>",
"mysticHourglass": "<%= amount %> Mystic Hourglass",
"mysticHourglassText": "Mystic Hourglasses allow purchasing a previous month's Mystery Item set.",
"purchasedPlanId": "Recurring $<%= price %> USD each <%= months %> Month(s) (<%= plan %>)",
"purchasedPlanExtraMonths": "You have <%= months %> months of extra subscription credit.",
"purchasedPlanExtraMonths": "You have <strong><%= months %> months</strong> of extra subscription credit.",
"consecutiveSubscription": "Consecutive Subscription",
"consecutiveMonths": "Consecutive Months:",
"gemCapExtra": "Gem Cap Extra:",
"gemCapExtra": "Gem Cap Bonus",
"mysticHourglasses": "Mystic Hourglasses:",
"mysticHourglassesTooltip": "Mystic Hourglasses",
"paypal": "PayPal",

View File

@@ -19,7 +19,8 @@
"supportDevsText": "Your subscription helps keep Habitica thriving and helps fund the development of new features. Thank you for your generosity!",
"exclusiveJackalopePet": "Exclusive pet",
"exclusiveJackalopePetText": "Get the Royal Purple Jackalope pet, available only to subscribers!",
"giftSubscription": "Want to gift a subscription to someone?",
"giftSubscription": "Want to gift the benefits of a subscription to someone else?",
"giftASubscription": "Gift a Subscription",
"giftSubscriptionText1": "Open their profile! You can do this by clicking on their avatar in your party header or by clicking on their name in chat.",
"giftSubscriptionText2": "Click on the gift icon in the top right of their profile.",
"giftSubscriptionText3": "Select \"subscription\" and enter your payment information.",
@@ -42,8 +43,8 @@
"manageSub": "Click to manage subscription",
"cancelSub": "Cancel Subscription",
"cancelSubInfoGoogle": "Please go to the \"Account\" > \"Subscriptions\" section of the Google Play Store app to cancel your subscription or to see your subscription's termination date if you have already cancelled it. This screen is not able to show you whether your subscription has been cancelled.",
"cancelSubInfoApple": "Please follow <a href=\"https://support.apple.com/en-us/HT202039\">Apple's official instructions</a> to cancel your subscription or to see your subscription's termination date if you have already cancelled it. This screen is not able to show you whether your subscription has been cancelled.",
"cancelSubInfoGroupPlan": "Because you have a free subscription from a Group Plan, you cannot cancel it. It will end when you are no longer in the Group. If you are the Group leader and want to cancel the entire Group Plan, you can do that from the group's \"Payment Details\" tab.",
"cancelSubInfoApple": "Please follow <a href=\"https://support.apple.com/en-us/HT202039\" target=\"_blank\">Apple's official instructions</a> to cancel your subscription or to see your subscription's termination date if you have already cancelled it. This screen is not able to show you whether your subscription has been cancelled.",
"cancelSubInfoGroupPlan": "Because you have a free subscription from a Group Plan, you cannot cancel it. It will end when you are no longer a member of the Group Plan. If you are the Group leader and want to cancel the Group Plan, you can do that from the Group Plans “Group Billing” tab.",
"canceledSubscription": "Canceled Subscription",
"cancelingSubscription": "Canceling the subscription",
"adminSub": "Administrator Subscriptions",
@@ -177,7 +178,7 @@
"mysterySetwondercon": "Wondercon",
"subUpdateCard": "Update Card",
"subUpdateCard": "Update Credit Card",
"subUpdateTitle": "Update",
"subUpdateDescription": "Update the card to be charged.",
"notEnoughHourglasses": "You don't have enough Mystic Hourglasses.",
@@ -222,17 +223,29 @@
"gemBenefit3": "Exciting Quest chains that drop pet eggs.",
"gemBenefit4": "Reset your avatar's Stat Points and change its Class.",
"subscriptionBenefitLeadin": "Support Habitica by becoming a subscriber and you'll receive these useful benefits!",
"subscriptionBenefit1": "Alexander the Merchant will sell you Gems, for 20 Gold each!",
"subscriptionBenefit1": "Alexander the Merchant will now sell you Gems from the Market for 20 Gold each!",
"subscriptionBenefit2": "Completed To-Dos and task history are available for longer.",
"subscriptionBenefit3": "Discover more items in Habitica with a doubled daily drop cap.",
"subscriptionBenefit4": "Unique cosmetic items for your avatar each month.",
"subscriptionBenefit5": "Receive the exclusive Royal Purple Jackalope pet!",
"subscriptionBenefit6": "Earn Mystic Hourglasses for use in the Time Travelers' Shop!",
"subscriptionBenefit3": "Discover even more items in Habitica with a 2x daily drop-cap.",
"subscriptionBenefit4": "Unique cosmetic item for you to decorate your avatar each month.",
"subscriptionBenefit5": "Receive the Royal Purple Jackalope pet when you become a new subscriber.",
"subscriptionBenefit6": "Earn Mystic Hourglasses to purchase items in the Time Travelers Shop!",
"haveCouponCode": "Do you have a coupon code?",
"subscriptionAlreadySubscribedLeadIn": "Thanks for subscribing!",
"subscriptionAlreadySubscribed1": "To see your subscription details and cancel, renew, or change your subscription, please go to <a href='/user/settings/subscription'>User icon &gt; Settings &gt; Subscription</a>.",
"purchaseAll": "Purchase Set",
"gemsPurchaseNote": "Subscribers can buy gems for gold in the Market! For easy access, you can also pin the gem to your Rewards column.",
"gemsRemaining": "gems remaining",
"notEnoughGemsToBuy": "You are unable to buy that amount of gems"
"gemsPurchaseNote": "Subscribers can buy Gems for Gold in the Market! For easy access, you can also pin the Gem to your Rewards column.",
"gemsRemaining": "Gems remaining",
"notEnoughGemsToBuy": "You are unable to buy that amount of Gems",
"subscribersReceiveBenefits": "Subscribers receive these useful benefits!",
"monthlyMysteryItems": "Monthly Mystery Items",
"doubleDropCap": "Double the Drops",
"youAreSubscribed": "You are subscribed to Habitica",
"subscriptionCanceled": "Your subscription is canceled",
"subscriptionInactiveDate": "Your subscription benefits will become inactive on <strong><%= date %></strong>",
"subscriptionStats": "Subscription Stats",
"subMonths": "Sub Months",
"needToUpdateCard": "Need to update your card?",
"readyToResubscribe": "Are you ready to resubscribe?",
"cancelYourSubscription": "Cancel your subscription?",
"cancelSubAlternatives": "If you're having technical problems or Habitica doesn't seem to be working out for you, please consider <a href='mailto:admin@habitica.com'>contacting us</a>. We want to help you get the most from Habitica."
}

View File

@@ -22,6 +22,7 @@ const NOTIFICATION_TYPES = [
'GROUP_INVITE_ACCEPTED',
'SCORED_TASK',
'BOSS_DAMAGE', // Not used currently but kept to avoid validation errors
'GIFT_ONE_GET_ONE',
'GUILD_PROMPT',
'GUILD_JOINED_ACHIEVEMENT',
'CHALLENGE_JOINED_ACHIEVEMENT',