[BUILD-452] Fix copies and subscribe success notifications (#2194)

[BUILD-452] Fix copies and subscribe success notifications (#2194)

fix copies and subscribe success notifications

diff --git a/ankihub/common/mixins.py b/ankihub/common/mixins.py
index 36f2abd..d7f1820 100644
--- a/ankihub/common/mixins.py
+++ b/ankihub/common/mixins.py
@@ -311,6 +311,16 @@ class NotifyToastMixin:
             level="success",
             duration=2500,
         ),
+        "success-plan-core": Toast(
+            message="You’re now a Core member and can trial Premium features for 14 days! 🎁",
+            level="success",
+            duration=2500,
+        ),
+        "success-plan-ankihub_ai": Toast(
+            message="You’re now a Premium member! Enjoy the best features AnkiHub has to offer 🌟",
+            level="success",
+            duration=2500,
+        ),
     }
 
     def get_message(self, notify):
diff --git a/ankihub/common/tests/test_mixins.py b/ankihub/common/tests/test_mixins.py
index d0c7bed..fe92ff1 100644
--- a/ankihub/common/tests/test_mixins.py
+++ b/ankihub/common/tests/test_mixins.py
@@ -63,3 +63,31 @@ class TestNotifyToastMixin:
         assert toast.message == "You're now subscribed to this deck!"
         assert toast.level == "success"
         assert toast.duration == 2500
+
+    def test_notify_toast_mixin_success_plan_core(self):
+        request = RequestFactory()
+        request = request.get("/fake-url/?notify=success-plan-core")
+        view = MockNotifyToastView()
+        view.request = request
+        response = view.dispatch(request=view.request)
+        toast = response.context_data["notify"]
+        assert (
+            toast.message
+            == "You’re now a Core member and can trial Premium features for 14 days! 🎁"
+        )
+        assert toast.level == "success"
+        assert toast.duration == 2500
+
+    def test_notify_toast_mixin_success_plan_ankihub_ai(self):
+        request = RequestFactory()
+        request = request.get("/fake-url/?notify=success-plan-ankihub_ai")
+        view = MockNotifyToastView()
+        view.request = request
+        response = view.dispatch(request=view.request)
+        toast = response.context_data["notify"]
+        assert (
+            toast.message
+            == "You’re now a Premium member! Enjoy the best features AnkiHub has to offer 🌟"
+        )
+        assert toast.level == "success"
+        assert toast.duration == 2500
diff --git a/ankihub/decks/views.py b/ankihub/decks/views.py
index 0c0a38f..03005ff 100644
--- a/ankihub/decks/views.py
+++ b/ankihub/decks/views.py
@@ -104,7 +104,9 @@ from .models import (
 log = structlog.get_logger()
 
 
-class BaseExploreDecksView(LoginRequiredMixin, CustomBaseViewMixin, TemplateView):
+class BaseExploreDecksView(
+    LoginRequiredMixin, NotifyToastMixin, CustomBaseViewMixin, TemplateView
+):
     template_name = "decks/pages/base_explore.html"
 
     def is_explore_page(self):
diff --git a/ankihub/memberships/services.py b/ankihub/memberships/services.py
index a73895d..172f39f 100644
--- a/ankihub/memberships/services.py
+++ b/ankihub/memberships/services.py
@@ -431,6 +431,8 @@ class MembershipHandler:
         return subscriptions
 
     def has_subscriptions_by_status(self, customer_id, status=None):
+        if not customer_id:
+            return False
         subscriptions = self.get_subscriptions_by_status(customer_id, status)
         return len(subscriptions.data) > 0
 
diff --git a/ankihub/memberships/tests/test_services.py b/ankihub/memberships/tests/test_services.py
index ab539a9..36ec83d 100644
--- a/ankihub/memberships/tests/test_services.py
+++ b/ankihub/memberships/tests/test_services.py
@@ -346,6 +346,13 @@ def test_has_subscriptions_by_status_return_false_if_does_not_exists(
     assert not mh.has_subscriptions_by_status(customer_id="test_1", status="active")
 
 
+def test_has_subscriptions_by_status_return_false_if_empty_customer_id(
+    mocker: MockerFixture,
+) -> None:
+    mh = MembershipHandler()
+    assert not mh.has_subscriptions_by_status(customer_id="", status="active")
+
+
 def test_has_active_subscription(mocker: MockerFixture) -> None:
     mocked = mocker.patch.object(
         MembershipHandler,
diff --git a/ankihub/memberships/tests/test_views.py b/ankihub/memberships/tests/test_views.py
index d0323a2..1108aa8 100644
--- a/ankihub/memberships/tests/test_views.py
+++ b/ankihub/memberships/tests/test_views.py
@@ -355,7 +355,10 @@ def test_payment_succeeded_set_plan_to_membership(
     )
     membership.refresh_from_db()
     assert response.status_code == 302
-    assert response["Location"] == reverse("explore")
+    assert (
+        response["Location"]
+        == reverse("explore") + f"?notify=success-plan-{membership.plan.slug}"
+    )
     assert membership.plan == Plan.objects.get(slug=plan_slug)
 
 
diff --git a/ankihub/memberships/views.py b/ankihub/memberships/views.py
index 294f91f..4cb02b4 100644
--- a/ankihub/memberships/views.py
+++ b/ankihub/memberships/views.py
@@ -97,7 +97,11 @@ def payment_succeeded(request):
                 request.user.ankihub_membership.membership_end_date
             ),
         )
-    return redirect("explore")
+        return redirect("explore")
+    return redirect(
+        reverse("explore")
+        + f"?notify=success-plan-{request.user.ankihub_membership.plan.slug}"
+    )
 
 
 @login_required
diff --git a/ankihub/templates/components/ModalUpsellContent.html b/ankihub/templates/components/ModalUpsellContent.html
index 9ebef88..4a6df14 100644
--- a/ankihub/templates/components/ModalUpsellContent.html
+++ b/ankihub/templates/components/ModalUpsellContent.html
@@ -28,10 +28,10 @@
             {% if footerContent %}
                 {{ footerContent }}
             {% else %}
-            <button onclick="toggleModal('featureModal')" type="button" class="py-[10px] px-3 bg-indigo-50 dark:bg-indigo-950 rounded-[4px] text-sm text-indigo-600 dark:text-indigo-400">
+            <button onclick="toggleModal('featureModal')" type="button" class="py-[10px] px-3 bg-indigo-50 dark:bg-indigo-950 hover:bg-indigo-100 dark:hover:bg-indigo-900 focus:bg-indigo-200 dark:focus:bg-indigo-800 rounded-[4px] text-sm text-indigo-600 dark:text-indigo-400">
                 Cancel
             </button>
-            <a role="button" class="py-[10px] px-3 bg-indigo-600 dark:bg-indigo-400 rounded-[4px] text-sm text-white dark:text-white" href="{% url 'memberships:plans' %}">
+            <a role="button" class="py-[10px] px-3 bg-indigo-600 dark:bg-indigo-400 hover:bg-indigo-700 dark:hover:bg-indigo-300 focus:bg-indigo-800 dark:focus:bg-indigo-200 rounded-[4px] text-sm text-white dark:text-white" href="{% url 'memberships:plans' %}">
                 Upgrade
             </a>
             {% endif %}
diff --git a/ankihub/templates/decks/pages/base_explore.html b/ankihub/templates/decks/pages/base_explore.html
index 6621bda..968c62b 100644
--- a/ankihub/templates/decks/pages/base_explore.html
+++ b/ankihub/templates/decks/pages/base_explore.html
@@ -336,6 +336,15 @@
         })
       </script>
     {% endif %}
+    {% if notify %}
+      <script>
+        showToast(
+          message=`{{ notify.message|safe }}`,
+          level=`{{ notify.level|safe }}`,
+          duration=`{{ notify.duration|safe }}`,
+        )
+      </script>
+    {% endif %}
 </div>
 
 {% endblock content %}
diff --git a/ankihub/templates/decks/partials/modals/modal_deck_subscription_info.html b/ankihub/templates/decks/partials/modals/modal_deck_subscription_info.html
index 0d6dd78..95fd530 100644
--- a/ankihub/templates/decks/partials/modals/modal_deck_subscription_info.html
+++ b/ankihub/templates/decks/partials/modals/modal_deck_subscription_info.html
@@ -18,7 +18,7 @@
                     <div class="flex justify-between gap-4">
                         <button onclick="toggleModal('modal-subscription-info-{{ deck.id }}')"
                                 type="button"

[... diff too long, it was truncated ...]

GitHub
sha: 56423fbc9a5ea34ed2b1a6e9df2338476e3269f2