Pricing Page and Subscription Guard

This commit is contained in:
ajaysi
2025-10-13 10:25:57 +05:30
parent 20b01717cd
commit c38812b6c5
11 changed files with 1838 additions and 19 deletions

View File

@@ -0,0 +1,131 @@
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import { apiClient } from '../api/client';
export interface SubscriptionLimits {
gemini_calls: number;
openai_calls: number;
anthropic_calls: number;
mistral_calls: number;
tavily_calls: number;
serper_calls: number;
metaphor_calls: number;
firecrawl_calls: number;
stability_calls: number;
monthly_cost: number;
}
export interface SubscriptionStatus {
active: boolean;
plan: string;
tier: string;
can_use_api: boolean;
reason?: string;
limits: SubscriptionLimits;
}
interface SubscriptionContextType {
subscription: SubscriptionStatus | null;
loading: boolean;
error: string | null;
checkSubscription: () => Promise<void>;
refreshSubscription: () => Promise<void>;
}
const SubscriptionContext = createContext<SubscriptionContextType | undefined>(undefined);
export const useSubscription = () => {
const context = useContext(SubscriptionContext);
if (!context) {
throw new Error('useSubscription must be used within a SubscriptionProvider');
}
return context;
};
interface SubscriptionProviderProps {
children: ReactNode;
}
export const SubscriptionProvider: React.FC<SubscriptionProviderProps> = ({ children }) => {
const [subscription, setSubscription] = useState<SubscriptionStatus | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const checkSubscription = async () => {
setLoading(true);
setError(null);
try {
// Get user ID from localStorage or auth context
const userId = localStorage.getItem('user_id') || 'anonymous';
const response = await apiClient.get(`/api/subscription/status/${userId}`);
const subscriptionData = response.data.data;
setSubscription(subscriptionData);
} catch (err) {
console.error('Error checking subscription:', err);
setError(err instanceof Error ? err.message : 'Failed to check subscription');
// Default to free tier on error
setSubscription({
active: true,
plan: 'free',
tier: 'free',
can_use_api: true,
limits: {
gemini_calls: 100,
openai_calls: 100,
anthropic_calls: 100,
mistral_calls: 100,
tavily_calls: 50,
serper_calls: 50,
metaphor_calls: 50,
firecrawl_calls: 50,
stability_calls: 20,
monthly_cost: 5.0
}
});
} finally {
setLoading(false);
}
};
const refreshSubscription = async () => {
await checkSubscription();
};
useEffect(() => {
// Check subscription on mount
checkSubscription();
// Set up periodic refresh (every 5 minutes)
const interval = setInterval(checkSubscription, 5 * 60 * 1000);
// Listen for subscription updates
const handleSubscriptionUpdate = () => {
console.log('Subscription updated, refreshing...');
checkSubscription();
};
window.addEventListener('subscription-updated', handleSubscriptionUpdate);
return () => {
clearInterval(interval);
window.removeEventListener('subscription-updated', handleSubscriptionUpdate);
};
}, []);
const value: SubscriptionContextType = {
subscription,
loading,
error,
checkSubscription,
refreshSubscription,
};
return (
<SubscriptionContext.Provider value={value}>
{children}
</SubscriptionContext.Provider>
);
};