summaryrefslogtreecommitdiff
path: root/Biz/PodcastItLater/Admin.py
diff options
context:
space:
mode:
authorBen Sima <ben@bsima.me>2025-11-09 20:32:34 -0500
committerBen Sima <ben@bsima.me>2025-11-09 20:32:34 -0500
commit14af38a21dc8e790b9ddc29e241784fd769dc3fc (patch)
treee33ef9866f6448088cac4acd2ef9b48c32ca3990 /Biz/PodcastItLater/Admin.py
parent83d90f815447abc5447f6b0b4a978b2e8ce82894 (diff)
PodcastItLater: Add Stripe billing and mobile responsiveness
- Implemented complete Stripe integration (Billing.py) - Checkout sessions for subscription upgrades - Billing portal for subscription management - Webhook handling for subscription events - Usage tracking with tier-based limits (free: 10, personal: 50, pro: unlimited) - Added billing page UI (BillingPage component) - Current plan display with usage stats - Pricing cards for all tiers with upgrade buttons - Manage subscription button for paid users - Success/error messaging - Database migrations for billing - Added plan_tier, stripe_customer_id, stripe_subscription_id - Added subscription_status, period dates, cancel_at_period_end - Created stripe_events table for webhook idempotency - Added get_usage() method for usage tracking - Made UI mobile-friendly and responsive - Added viewport meta tags to all pages - Replaced pages.HtmlPage with raw html.html for meta tag control - Responsive button layouts with flexbox wrapping - Responsive pricing cards (1 col mobile, 2 col tablet, 3 col desktop) - Touch-friendly forms and buttons (44px minimum) - Responsive padding and containers - Admin tables with horizontal scroll - Added Stripe testing guide (STRIPE_TESTING.md) - Fixed CSS bug in pricing cards (cardh-100 text rendering) - Updated tasks: completed t-144e7lF, t-1pIV0ZF, t-1s8ADC0 Amp-Thread-ID: https://ampcode.com/threads/T-42fd5fb3-3dc5-4cbc-a9a3-78db9e13187e Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'Biz/PodcastItLater/Admin.py')
-rw-r--r--Biz/PodcastItLater/Admin.py45
1 files changed, 30 insertions, 15 deletions
diff --git a/Biz/PodcastItLater/Admin.py b/Biz/PodcastItLater/Admin.py
index 5772256..7dd0c50 100644
--- a/Biz/PodcastItLater/Admin.py
+++ b/Biz/PodcastItLater/Admin.py
@@ -13,7 +13,6 @@ Admin pages and functionality for managing users and queue items.
# : dep pytest-mock
import Biz.PodcastItLater.Core as Core
import ludic.catalog.layouts as layouts
-import ludic.catalog.pages as pages
import ludic.html as html
# i need to import these unused because bild cannot get local transitive python
@@ -305,16 +304,24 @@ class AdminUsers(Component[AnyChildren, AdminUsersAttrs]):
"""Admin view for managing users."""
@override
- def render(self) -> pages.HtmlPage:
+ def render(self) -> html.html:
users = self.attrs["users"]
- return pages.HtmlPage(
- pages.Head(
- title="PodcastItLater - User Management",
- htmx_version="1.9.10",
- load_styles=False,
+ return html.html(
+ html.head(
+ html.meta(charset="utf-8"),
+ html.meta(
+ name="viewport",
+ content="width=device-width, initial-scale=1",
+ ),
+ html.title("PodcastItLater - User Management"),
+ html.script(
+ src="https://unpkg.com/htmx.org@1.9.10",
+ integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC",
+ crossorigin="anonymous",
+ ),
),
- pages.Body(
+ html.body(
create_bootstrap_styles(),
html.div(
html.h1(
@@ -371,18 +378,26 @@ class AdminView(Component[AnyChildren, AdminViewAttrs]):
"""Admin view showing all queue items and episodes in tables."""
@override
- def render(self) -> pages.HtmlPage:
+ def render(self) -> html.html:
queue_items = self.attrs["queue_items"]
episodes = self.attrs["episodes"]
status_counts = self.attrs.get("status_counts", {})
- return pages.HtmlPage(
- pages.Head(
- title="PodcastItLater - Admin Queue Status",
- htmx_version="1.9.10",
- load_styles=False,
+ return html.html(
+ html.head(
+ html.meta(charset="utf-8"),
+ html.meta(
+ name="viewport",
+ content="width=device-width, initial-scale=1",
+ ),
+ html.title("PodcastItLater - Admin Queue Status"),
+ html.script(
+ src="https://unpkg.com/htmx.org@1.9.10",
+ integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC",
+ crossorigin="anonymous",
+ ),
),
- pages.Body(
+ html.body(
create_bootstrap_styles(),
html.div(
AdminView._render_content(