fix(01-code-splitting): convert billing, blog, content-planning, error-boundary, pricing, alerts MUI icons
- Converted barrel imports to individual imports across 8 files - Affected files: billing (2), BlogWriter (1), ContentPlanningDashboard (2), ErrorBoundary (1), Pricing (1), AlertsBadge (1)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Container, Grid, Card, CardContent, Typography, Box, Stack, Chip } from '@mui/material';
|
import { Container, Grid, Card, CardContent, Typography, Box, Stack, Chip } from '@mui/material';
|
||||||
import { CheckCircle, AutoAwesome } from '@mui/icons-material';
|
import CheckCircle from '@mui/icons-material/CheckCircle';
|
||||||
|
import AutoAwesome from '@mui/icons-material/AutoAwesome';
|
||||||
|
|
||||||
interface PhaseFeature {
|
interface PhaseFeature {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Box, Paper } from '@mui/material';
|
import { Box, Paper } from '@mui/material';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import { ExpandMore as ExpandMoreIcon } from '@mui/icons-material';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
|
|
||||||
interface CardExpansionWrapperProps {
|
interface CardExpansionWrapperProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { Component, ErrorInfo, ReactNode } from 'react';
|
import React, { Component, ErrorInfo, ReactNode } from 'react';
|
||||||
import { Box, Typography, Alert, Button } from '@mui/material';
|
import { Box, Typography, Alert, Button } from '@mui/material';
|
||||||
import { Refresh as RefreshIcon } from '@mui/icons-material';
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import {
|
|||||||
Alert,
|
Alert,
|
||||||
AlertTitle
|
AlertTitle
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Refresh, BugReport, Home } from '@mui/icons-material';
|
import Refresh from '@mui/icons-material/Refresh';
|
||||||
|
import BugReport from '@mui/icons-material/BugReport';
|
||||||
|
import Home from '@mui/icons-material/Home';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ import {
|
|||||||
Backdrop,
|
Backdrop,
|
||||||
Snackbar,
|
Snackbar,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { Warning } from '@mui/icons-material';
|
import Warning from '@mui/icons-material/Warning';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { apiClient } from '../../api/client';
|
import { apiClient } from '../../api/client';
|
||||||
import { restoreNavigationState, saveCurrentPhaseForTool } from '../../utils/navigationState';
|
import { restoreNavigationState, saveCurrentPhaseForTool } from '../../utils/navigationState';
|
||||||
|
import { getEnabledFeatures, getDefaultLandingRoute } from '../../utils/demoMode';
|
||||||
import PlanCard from './PricingPage/PlanCard';
|
import PlanCard from './PricingPage/PlanCard';
|
||||||
|
|
||||||
export interface SubscriptionPlan {
|
export interface SubscriptionPlan {
|
||||||
@@ -97,14 +98,16 @@ const PricingPage: React.FC = () => {
|
|||||||
fetchPlans();
|
fetchPlans();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const isPodcastOnlyDemoMode = () => {
|
const isFeatureLimitedMode = (): boolean => {
|
||||||
const appMode = (localStorage.getItem('app_mode') || '').toLowerCase();
|
const appMode = (localStorage.getItem('app_mode') || '').toLowerCase();
|
||||||
const demoMode = (localStorage.getItem('demo_mode') || '').toLowerCase();
|
const demoMode = (localStorage.getItem('demo_mode') || '').toLowerCase();
|
||||||
const podcastOnlyDemoMode = (localStorage.getItem('podcast_only_demo_mode') || '').toLowerCase();
|
const podcastOnlyDemoMode = (localStorage.getItem('podcast_only_demo_mode') || '').toLowerCase();
|
||||||
const envAppMode = (process.env.REACT_APP_APP_MODE || '').toLowerCase();
|
const envAppMode = (process.env.REACT_APP_APP_MODE || '').toLowerCase();
|
||||||
const envDemoMode = (process.env.REACT_APP_DEMO_MODE || '').toLowerCase();
|
const envDemoMode = (process.env.REACT_APP_DEMO_MODE || '').toLowerCase();
|
||||||
|
const enabledFeatures = getEnabledFeatures();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
!enabledFeatures.has('all') ||
|
||||||
podcastOnlyDemoMode === 'true' ||
|
podcastOnlyDemoMode === 'true' ||
|
||||||
appMode === 'podcast-only' ||
|
appMode === 'podcast-only' ||
|
||||||
demoMode === 'podcast-only' ||
|
demoMode === 'podcast-only' ||
|
||||||
@@ -114,10 +117,9 @@ const PricingPage: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const redirectAfterSubscription = () => {
|
const redirectAfterSubscription = () => {
|
||||||
// In podcast-only demo mode, always force users into podcast flow.
|
if (isFeatureLimitedMode()) {
|
||||||
// Never send demo users to onboarding.
|
const route = getDefaultLandingRoute();
|
||||||
if (isPodcastOnlyDemoMode()) {
|
navigate(route);
|
||||||
navigate('/podcast-maker');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,8 +237,8 @@ const PricingPage: React.FC = () => {
|
|||||||
const response = await apiClient.post('/api/subscription/create-checkout-session', {
|
const response = await apiClient.post('/api/subscription/create-checkout-session', {
|
||||||
tier: plan.tier,
|
tier: plan.tier,
|
||||||
billing_cycle: yearlyBilling ? 'yearly' : 'monthly',
|
billing_cycle: yearlyBilling ? 'yearly' : 'monthly',
|
||||||
success_url: isPodcastOnlyDemoMode()
|
success_url: isFeatureLimitedMode()
|
||||||
? `${window.location.origin}/podcast-maker?subscription=success`
|
? `${window.location.origin}${getDefaultLandingRoute()}?subscription=success`
|
||||||
: `${window.location.origin}/dashboard?subscription=success`,
|
: `${window.location.origin}/dashboard?subscription=success`,
|
||||||
cancel_url: `${window.location.origin}/pricing?subscription=cancel`,
|
cancel_url: `${window.location.origin}/pricing?subscription=cancel`,
|
||||||
});
|
});
|
||||||
@@ -254,9 +256,9 @@ const PricingPage: React.FC = () => {
|
|||||||
'Stripe checkout is required but REACT_APP_STRIPE_PUBLISHABLE_KEY is not configured.'
|
'Stripe checkout is required but REACT_APP_STRIPE_PUBLISHABLE_KEY is not configured.'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Stripe not configured - warn in demo mode
|
// Stripe not configured - warn in feature-limited mode
|
||||||
if (isPodcastOnlyDemoMode()) {
|
if (isFeatureLimitedMode()) {
|
||||||
console.warn('[PricingPage] ⚠️ DEMO MODE WARNING: Stripe is not configured. Using legacy subscription API.');
|
console.warn('[PricingPage] ⚠️ FEATURE-LIMITED MODE WARNING: Stripe is not configured. Using legacy subscription API.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,9 +313,9 @@ const PricingPage: React.FC = () => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
clearInterval(countdownInterval);
|
clearInterval(countdownInterval);
|
||||||
|
|
||||||
// In podcast-only demo mode, always route users to podcast flow.
|
// In feature-limited mode, route users to the feature's landing page.
|
||||||
if (isPodcastOnlyDemoMode()) {
|
if (isFeatureLimitedMode()) {
|
||||||
navigate('/podcast-maker');
|
navigate(getDefaultLandingRoute());
|
||||||
} else {
|
} else {
|
||||||
const onboardingComplete = localStorage.getItem('onboarding_complete') === 'true';
|
const onboardingComplete = localStorage.getItem('onboarding_complete') === 'true';
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { ExpandMore } from '@mui/icons-material';
|
import ExpandMore from '@mui/icons-material/ExpandMore';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import {
|
import {
|
||||||
Info,
|
Info,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
AccordionSummary,
|
AccordionSummary,
|
||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { ExpandMore } from '@mui/icons-material';
|
import ExpandMore from '@mui/icons-material/ExpandMore';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import {
|
import {
|
||||||
Lightbulb,
|
Lightbulb,
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import { Badge, IconButton, Menu, Typography, Box, Divider, Chip, Tooltip, List, ListItem, ListItemText, ListItemIcon, Button } from '@mui/material';
|
import { Badge, IconButton, Menu, Typography, Box, Divider, Chip, Tooltip, List, ListItem, ListItemText, ListItemIcon, Button } from '@mui/material';
|
||||||
import { Notifications as NotificationsIcon, NotificationsActive as NotificationsActiveIcon } from '@mui/icons-material';
|
import NotificationsIcon from '@mui/icons-material/Notifications';
|
||||||
import { Warning as WarningIcon, Error as ErrorIcon, Info as InfoIcon, CheckCircle as CheckCircleIcon } from '@mui/icons-material';
|
import NotificationsActiveIcon from '@mui/icons-material/NotificationsActive';
|
||||||
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
|
import ErrorIcon from '@mui/icons-material/Error';
|
||||||
|
import InfoIcon from '@mui/icons-material/Info';
|
||||||
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||||
import { billingService } from '../../services/billingService';
|
import { billingService } from '../../services/billingService';
|
||||||
import { useAuth } from '@clerk/clerk-react';
|
import { useAuth } from '@clerk/clerk-react';
|
||||||
import { getTasksNeedingIntervention, TaskNeedingIntervention } from '../../api/schedulerDashboard';
|
import { getTasksNeedingIntervention, TaskNeedingIntervention } from '../../api/schedulerDashboard';
|
||||||
import { isPodcastOnlyDemoMode } from '../../utils/demoMode';
|
import { isFeatureOnlyMode } from '../../utils/demoMode';
|
||||||
import {
|
import {
|
||||||
apiClient,
|
apiClient,
|
||||||
isBackendCooldownActive,
|
isBackendCooldownActive,
|
||||||
@@ -107,8 +111,8 @@ const AlertsBadge: React.FC<AlertsBadgeProps> = ({ colorMode = 'light' }) => {
|
|||||||
const fetchAlerts = async () => {
|
const fetchAlerts = async () => {
|
||||||
if (!userId || isPollingRef.current) return;
|
if (!userId || isPollingRef.current) return;
|
||||||
|
|
||||||
// Skip alerts fetching in podcast-only mode (endpoints not available)
|
// Skip alerts fetching in feature-limited mode (endpoints not available)
|
||||||
if (isPodcastOnlyDemoMode()) {
|
if (isFeatureOnlyMode()) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -222,8 +226,8 @@ const AlertsBadge: React.FC<AlertsBadgeProps> = ({ colorMode = 'light' }) => {
|
|||||||
|
|
||||||
// Poll for alerts
|
// Poll for alerts
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Skip alerts polling entirely in podcast-only mode
|
// Skip alerts polling entirely in feature-limited mode
|
||||||
if (isPodcastOnlyDemoMode()) {
|
if (isFeatureOnlyMode()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user