Skip to content

Subscription Gate Modal Implementation

Date: January 9, 2026 Status: ✅ COMPLETE


Overview

Implemented a comprehensive subscription gate system that displays a glassmorphic modal when users without proper subscriptions attempt to access premium content. Admin users bypass all subscription requirements.


Backend Changes

1. Content Stream Endpoint

File: /backend/app/api/routes/content.py (lines 195-208)

python
# Admin users bypass subscription checks
is_admin = current_user.role in ["super_admin", "admin"]

# Check subscription (skip for admins)
if not is_admin:
    required_tier = content.requires_subscription
    user_tier = current_user.subscription_tier

    tier_levels = {"basic": 1, "premium": 2, "family": 3}
    if not user_tier or tier_levels.get(user_tier, 0) < tier_levels.get(required_tier, 1):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Subscription upgrade required",
        )

Features:

  • Checks if user has admin role (super_admin or admin)
  • Admins bypass subscription checks entirely
  • Regular users must have appropriate subscription tier
  • Returns 403 Forbidden with clear message when subscription is required

2. Live Channel Stream Endpoint

File: /backend/app/api/routes/live.py (lines 130-139)

python
# Admin users bypass subscription checks
is_admin = current_user.role in ["super_admin", "admin"]

# Check subscription for live TV (skip for admins)
if not is_admin:
    if not current_user.subscription_tier or current_user.subscription_tier == "basic":
        raise HTTPException(
            status_code=403,
            detail="Live TV requires Premium or Family subscription",
        )

Features:

  • Same admin bypass logic as VOD content
  • Live TV requires Premium or Family subscription
  • Returns 403 error for unauthorized users

Frontend Implementation

1. SubscriptionGateModal Component

File: /tv-app/src/components/player/SubscriptionGateModal.tsx

Features:

  • Glassmorphic Design: Uses LinearGradient backgrounds matching app aesthetic
  • RTL Support: Full right-to-left text support for Hebrew
  • Header Section: Warning icon with "Subscription Required" title
  • Content Info: Shows which content requires subscription
  • Tier Card: Displays premium tier features with checkmarks
  • Info Box: Explains subscription benefits
  • Action Buttons: Cancel (dismiss) and Upgrade Now buttons
  • Modal Styling:
    • Dark semi-transparent backdrop (rgba(0, 0, 0, 0.7))
    • Glass background with gradient (rgba(26, 26, 46, 0.95) to rgba(20, 20, 35, 0.95))
    • Border: 1px glassBorder color
    • Header accent bar with warning color

Props:

typescript
export interface SubscriptionGateModalProps {
  visible: boolean;
  onClose: () => void;
  onUpgrade: () => void;
  requiredTier?: 'basic' | 'premium' | 'family';
  contentTitle?: string;
  contentType?: 'vod' | 'live' | 'radio' | 'podcast';
}

2. PlayerScreen Integration

File: /tv-app/src/screens/PlayerScreen.tsx

Changes:

  • Added import: SubscriptionGateModal from player components

  • Added state variables:

    • showSubscriptionGate: boolean for modal visibility
    • subscriptionRequired: stores required tier level
  • Updated loadStream() function:

    • Resets subscription gate state at start
    • Catches 403 errors and shows modal instead of generic error
    • Checks for subscription error in both formats:
      • err.status === 403
      • err.response?.status === 403
  • Added handler: handleSubscriptionUpgrade()

    • Closes modal
    • Navigates to Subscribe screen
  • Rendered modal in JSX:

    tsx
    <SubscriptionGateModal
      visible={showSubscriptionGate}
      onClose={() => setShowSubscriptionGate(false)}
      onUpgrade={handleSubscriptionUpgrade}
      requiredTier={subscriptionRequired}
      contentTitle={title}
      contentType={type}
    />

3. Component Exports

File: /tv-app/src/components/player/index.ts

Added exports:

typescript
export { SubscriptionGateModal } from './SubscriptionGateModal';
export type { SubscriptionGateModalProps } from './SubscriptionGateModal';

Internationalization (i18n)

English Translations

File: /shared/i18n/locales/en.json

Added under player section:

json
"subscription": {
  "requiredTitle": "Subscription Required",
  "requiredMessage": "requires a paid subscription",
  "upgradeInfo": "Upgrade your subscription to access premium content",
  "upgrade": "Upgrade Now"
}

Hebrew Translations

File: /shared/i18n/locales/he.json

Added under player section:

json
"subscription": {
  "requiredTitle": "נדרשת הנתקה",
  "requiredMessage": "דורש מנוי בתשלום",
  "upgradeInfo": "שדרג את המנוי שלך כדי לגשת לתוכן פרימיום",
  "upgrade": "שדרג כעת"
}

User Experience Flow

For Regular Users (No Subscription)

  1. User attempts to play premium content
  2. Backend returns 403 Forbidden
  3. PlayerScreen catches error
  4. SubscriptionGateModal appears with:
    • Content title
    • Subscription requirement message
    • Premium tier features list
    • "Upgrade Now" button
  5. User can:
    • Tap "Upgrade Now" → Navigate to subscription page
    • Tap "Cancel" → Dismiss modal and return to previous screen

For Admin Users

  1. Admin attempts to play any content
  2. Backend checks current_user.role and finds "admin" or "super_admin"
  3. Subscription check is skipped
  4. Stream URL is returned directly
  5. Content plays normally without subscription gate

Subscription Tiers

Tier Levels

  • Basic: Level 1 - Limited access
  • Premium: Level 2 - Full access to most content
  • Family: Level 3 - Premium features + multi-device + family profiles

Live TV Requirements

  • Requires: Premium or Family
  • Blocked for: Basic or no subscription

VOD Content Requirements

  • Customizable per content item via requires_subscription field
  • Compared using tier levels

Error Handling

Subscription Error Detection

Catches 403 Forbidden responses from:

  • Content stream endpoint: /content/{id}/stream
  • Live channel stream endpoint: /live/{channel_id}/stream

Error Response Checks

typescript
if (err && typeof err === 'object' && 'status' in err && err.status === 403) {
  setShowSubscriptionGate(true);
} else if (err && typeof err === 'object' && 'response' in err && err.response?.status === 403) {
  setShowSubscriptionGate(true);
}

Technical Details

Styling System

  • Colors Used:

    • Warning: colors.warning (yellow/orange)
    • Success: colors.success (green)
    • Primary: colors.primary (cyan/blue)
    • Glass: colors.glass, colors.glassBorder
    • Text Secondary: colors.textSecondary
  • Spacing:

    • Padding: lg (24px), md (16px), sm (8px), xs (4px)
    • Border Radius: lg, md, sm
  • Typography:

    • Header: fontSize.lg, fontWeight 600
    • Content: fontSize.sm
    • Tier Name: fontSize.md, fontWeight 600

RTL Handling

  • Text alignment: textAlign: 'right' for Hebrew
  • Flex direction: flex-direction: 'row-reverse' for button layout
  • Border positioning: Left to Right for English, Right to Left for Hebrew
  • All text uses isRTL state from useDirection() hook

API Integration

Stream URL Endpoints

GET /content/{content_id}/stream

  • Requires authentication
  • Admin bypass: ✅
  • Returns:
    • url: Stream URL
    • type: Stream type (hls, dash)
    • is_drm_protected: DRM status
    • drm_key_id: (if DRM protected)

GET /live/{channel_id}/stream

  • Requires authentication
  • Admin bypass: ✅
  • Returns:
    • url: Stream URL
    • type: Stream type
    • is_drm_protected: DRM status

Testing Checklist

Backend

  • [ ] Admin user can stream premium content without error
  • [ ] Regular user with no subscription gets 403 error
  • [ ] Regular user with basic subscription gets 403 for live TV
  • [ ] Regular user with premium subscription can stream live TV
  • [ ] Content-specific subscription requirements are enforced
  • [ ] Subscription tier levels are correctly compared

Frontend

  • [ ] Modal appears when 403 error is caught
  • [ ] Modal displays correct content title
  • [ ] "Upgrade Now" button navigates to Subscribe screen
  • [ ] "Cancel" button closes modal
  • [ ] Modal displays in correct language (English/Hebrew)
  • [ ] RTL layout works correctly in Hebrew
  • [ ] Glassmorphic styling matches app aesthetic
  • [ ] Features list displays with checkmarks

User Experience

  • [ ] Error message is clear and actionable
  • [ ] Subscription requirements are clearly explained
  • [ ] User can easily dismiss modal
  • [ ] User can easily navigate to upgrade
  • [ ] Modal doesn't interfere with other player controls

Files Modified/Created

Created Files

  • /tv-app/src/components/player/SubscriptionGateModal.tsx (270+ lines)

Modified Files

  • /backend/app/api/routes/content.py - Added admin bypass to subscription check
  • /backend/app/api/routes/live.py - Added admin bypass to subscription check
  • /tv-app/src/screens/PlayerScreen.tsx - Integrated modal and error handling
  • /tv-app/src/components/player/index.ts - Added modal exports
  • /shared/i18n/locales/en.json - Added English translations
  • /shared/i18n/locales/he.json - Added Hebrew translations

Key Features

Admin Bypass: Admins can access any content without subscription ✅ Glassmorphic Design: Modal matches existing app aesthetic ✅ RTL Support: Full Hebrew language support with proper text direction ✅ Clear UX: Users understand what's required and how to upgrade ✅ Error Handling: Distinguishes subscription errors from other errors ✅ Internationalization: English and Hebrew translations included ✅ Tier Information: Shows users what each subscription tier includes ✅ Navigation: Easy access to subscription upgrade page


Next Steps (Optional Enhancements)

  • [ ] Add more subscription tier details to modal
  • [ ] Show current user's subscription status in modal
  • [ ] Display pricing information
  • [ ] Add comparison table of tiers
  • [ ] Track failed access attempts for analytics
  • [ ] Send notification to admin of upgrade attempts
  • [ ] Add promotional offers for upgrading
  • [ ] Implement trial period logic

Summary

The subscription gate feature is now fully implemented with:

  • Backend: Admin bypass + subscription validation
  • Frontend: Glassmorphic modal with full error handling
  • UX: Clear messaging and easy navigation to upgrade
  • i18n: Full English and Hebrew support with RTL
  • Design: Consistent with existing app aesthetic

The system allows admins full access while protecting premium content for regular users.

Released under the MIT License.