My Subscriptions
| Plan / Course | Type | Start | Expiry | Status | |
|---|---|---|---|---|---|
| Premium Yearly | Period | 2026-01-15 | 2027-01-15 | Active | |
| Intro to Welding | Lifetime | 2025-11-02 | Lifetime | Active | โ |
| Basic Monthly | Period | 2025-12-01 | 2026-04-30 | Expired |
SUC-BIL-01 โ Checkout via BCEL
After the sub-flow completes it returns to
/renew-subscription/
Uses sub-flows:
Screen Flow (uc-bil-03-renew-subscription.flow.puml):
๐ Spec notes โ UC-BIL.03 / SCR-BIL.01 (fields, actions, requirements)
- Screen: SCR-BIL.01 โ Subscription Detail (My Subscriptions)
- Use case: UC-BIL.03 โ Renew Subscription
The "My Subscriptions" page for learners โ displays all subscriptions of the user, sorted active first, expired last (within grace period). Each card shows product name + type + period + status + expiry; period subscriptions have a "Renew" button (expands inline renew config on that card), lifetime subscriptions have no button (no renewal needed). This page is the entry point for UC-BIL.03 Renew Subscription โ click "Renew" to expand qty picker + (optional) switch product then confirm โ invoke SUC-BIL-01.
filter_status"Status" โ enum [all, active, expired] ยท default: all ยท always visiblerow_product_name"Plan / Course" โ text ยท lookup ยท always ยท read-onlyrow_product_type"Type" โ enum [lifetime, period] ยท lookup ยท always ยท read-onlyrow_started_at"Start" โ date ยท lookup ยท always ยท read-onlyrow_expiry_date"Expiry" โ date ยท lookup ยท visible when row_product_type != lifetime ยท read-onlyrow_status"Status" โ enum [active, expired, revoked] ยท lookup ยท always ยท read-onlyrenew_qty"Renewal Period" โ enum (qty_tier from active DiscountRule for this product) ยท required & visible when renew config expanded ยท fallback: ""renew_total_preview"Total (preview)" โ computed: Product.price ร renew_qty โ (Product.price ร renew_qty ร DiscountRule.discount_pct) ยท visible when renew config expanded ยท read-only
apply_filter"Filter" โ always enabledrenew"Renew" โ enabled when status == active OR (status == expired && within grace period) AND type != lifetime ยท triggers UC-BIL.03-M-1confirm_renew"Checkout" โ enabled when renew config expanded AND renew_qty != "" ยท invokes SUC-BIL-01 โ /checkout-via-bcel/?returnUrl=/renew-subscription/ ยท triggers UC-BIL.03-M-2cancel_renew"Cancel" โ enabled when renew config expanded ยท collapses inline config ยท triggers UC-BIL.03-A-2A-1browse_catalog"Browse Courses" โ enabled when subscriptions.count == 0 (empty state only)
- Supports concurrent users per NFR-01 (100โ200 peak) [refs: NFR-01]
- Usable on connection โค1 Mbps โ list paginate (default 20 cards/page), lazy-load expired subscriptions on a separate page [refs: NFR-02]
- TLS 1.2+ during transit; users see only their own subscriptions (server-side filter by session) [refs: NFR-03, NFR-10]
- Supports desktop/laptop/tablet/smartphone โ card list (responsive, no horizontal scroll) [refs: NFR-08]
- WCAG accessibility โ card must have proper heading + aria-label (product name + status), expand/collapse renew region uses aria-expanded, qty dropdown has <fieldset>+<legend>, clear focus order [refs: NFR-09]
- Empty state when user has no subscriptions โ show message + button to catalog (not an error) [refs: NFR-04]
- Lifetime subscription displays "Lifetime" instead of expiry date and does not show a Renew button (UC-BIL.03 covers period subscriptions only) [refs: โ]
- Renew config expands inline โ other cards remain accessible; user can only expand one row at a time (opening a new one auto-closes the previous) to reduce UI confusion [refs: NFR-04]
- Total (preview) in Renew config computed from Product.price ร renew_qty minus discount per the DiscountRule matching the selected qty_tier; displayed before learner clicks Checkout [refs: โ]
Renew panel โ total display
Override: Do not show the calculation formula in the renewal total preview.
Show only the final total amount (e.g. Total: 10,800 LAK), not the breakdown formula (e.g. 2,000 ร 6 โ 10% = 10,800 LAK).
Applies to: initial static display value in each inline renew row ยท dynamic updateRenewTotal() JS function output โ always render Total: X LAK regardless of whether a discount applies.
Prototype/screen-notes/renew-subscription/index.md โ applied as override layer at generation time