feat: Accept Payments - Stripe Integration with User Tiers (#55) #56
@@ -7,6 +7,7 @@ import { useSettings } from '../hooks/useSettings';
|
|||||||
import { useProfile, useUpdateProfile } from '../hooks/useProfile';
|
import { useProfile, useUpdateProfile } from '../hooks/useProfile';
|
||||||
import { useExportUserData } from '../hooks/useExportUserData';
|
import { useExportUserData } from '../hooks/useExportUserData';
|
||||||
import { useVehicles } from '../../vehicles/hooks/useVehicles';
|
import { useVehicles } from '../../vehicles/hooks/useVehicles';
|
||||||
|
import { useSubscription } from '../../subscription/hooks/useSubscription';
|
||||||
import { useAdminAccess } from '../../../core/auth/useAdminAccess';
|
import { useAdminAccess } from '../../../core/auth/useAdminAccess';
|
||||||
import { useNavigationStore } from '../../../core/store';
|
import { useNavigationStore } from '../../../core/store';
|
||||||
import { DeleteAccountModal } from './DeleteAccountModal';
|
import { DeleteAccountModal } from './DeleteAccountModal';
|
||||||
@@ -86,6 +87,8 @@ export const MobileSettingsScreen: React.FC = () => {
|
|||||||
const updateProfileMutation = useUpdateProfile();
|
const updateProfileMutation = useUpdateProfile();
|
||||||
const exportMutation = useExportUserData();
|
const exportMutation = useExportUserData();
|
||||||
const { data: vehicles, isLoading: vehiclesLoading } = useVehicles();
|
const { data: vehicles, isLoading: vehiclesLoading } = useVehicles();
|
||||||
|
const { data: subscriptionData, isLoading: subscriptionLoading } = useSubscription();
|
||||||
|
const subscription = subscriptionData?.data;
|
||||||
const { isAdmin, loading: adminLoading } = useAdminAccess();
|
const { isAdmin, loading: adminLoading } = useAdminAccess();
|
||||||
const [showDataExport, setShowDataExport] = useState(false);
|
const [showDataExport, setShowDataExport] = useState(false);
|
||||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||||
@@ -382,6 +385,60 @@ export const MobileSettingsScreen: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</GlassCard>
|
</GlassCard>
|
||||||
|
|
||||||
|
{/* Subscription Section */}
|
||||||
|
<GlassCard padding="md">
|
||||||
|
<div>
|
||||||
|
<div className="flex justify-between items-center mb-4">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<svg className="w-5 h-5 text-primary-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
|
||||||
|
</svg>
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 dark:text-avus">
|
||||||
|
Subscription
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => navigateToScreen('Subscription')}
|
||||||
|
className="px-3 py-1.5 bg-primary-500 text-white rounded-lg text-sm font-medium hover:bg-primary-600 transition-colors dark:bg-primary-600 dark:hover:bg-primary-700"
|
||||||
|
style={{ minHeight: '44px', minWidth: '44px' }}
|
||||||
|
>
|
||||||
|
Manage
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{subscriptionLoading ? (
|
||||||
|
<div className="flex justify-center py-4">
|
||||||
|
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary-500"></div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="font-medium text-slate-800 dark:text-avus">Current Plan:</span>
|
||||||
|
<span className="px-2 py-0.5 bg-primary-500 text-white text-xs font-semibold rounded-full">
|
||||||
|
{(subscription?.tier || 'free').toUpperCase()}
|
||||||
|
</span>
|
||||||
|
{subscription?.status && subscription.status !== 'active' && (
|
||||||
|
<span className={`px-2 py-0.5 text-xs font-semibold rounded-full ${
|
||||||
|
subscription.status === 'past_due'
|
||||||
|
? 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300'
|
||||||
|
: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'
|
||||||
|
}`}>
|
||||||
|
{subscription.status.replace('_', ' ')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-slate-500 dark:text-titanio">
|
||||||
|
{!subscription || subscription.tier === 'free'
|
||||||
|
? 'Upgrade to Pro or Enterprise for more features and vehicle slots.'
|
||||||
|
: subscription.tier === 'pro'
|
||||||
|
? 'Pro plan with up to 5 vehicles and full features.'
|
||||||
|
: 'Enterprise plan with unlimited vehicles and all features.'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</GlassCard>
|
||||||
|
|
||||||
{/* Notifications Section */}
|
{/* Notifications Section */}
|
||||||
<GlassCard padding="md">
|
<GlassCard padding="md">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Reference in New Issue
Block a user