| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- import * as React from 'react';
- import { Sidebar } from './components/Sidebar';
- import { PageBuilder } from './components/PageBuilder';
- import AIAssistant from './components/AIAssistant';
- import PageAnalytics from './components/PageAnalytics';
- import InteractionAnalytics from './components/InteractionAnalytics';
- import ShortLinks from './components/ShortLinks';
- import EnterpriseHosting from './components/EnterpriseHosting';
- import SEOServices from './components/SEOServices';
- import VideoCreator from './components/VideoCreator';
- import NewsCreator from './components/NewsCreator';
- import { ContentScheduler } from './components/ContentScheduler';
- import { CRM } from './components/CRM';
- import { GreenPage, AIGCSettings, FormSubmission } from './types';
- import { createNewPage } from './services/mockDataService';
- import PageManagementModal from './components/PageManagementModal';
- import ShareModal from './components/ShareModal';
- import Showcase from './components/Showcase';
- import Auth from './components/Auth';
- import { authService } from './services/authService';
- import { LanguageProvider, useTranslation } from './hooks/useI18n';
- const MainApp = () => {
- const { t } = useTranslation();
- const [currentUser, setCurrentUser] = React.useState<string | null>(() => authService.getCurrentUser());
- const [pages, setPages] = React.useState<GreenPage[]>([]);
- const [activePageId, setActivePageId] = React.useState<string | null>(null);
- const [activeNavKey, setActiveNavKey] = React.useState('Page.Link');
- const [isPageManagerOpen, setIsPageManagerOpen] = React.useState(false);
- const [isShareModalOpen, setIsShareModalOpen] = React.useState(false);
- const [theme, setTheme] = React.useState<'light' | 'dark'>('dark');
-
- // Load user pages on login/app load, and handle multi-tab logout
- React.useEffect(() => {
- const loadUserData = () => {
- const user = authService.getCurrentUser();
- if (user) {
- if (user !== currentUser) {
- setCurrentUser(user);
- }
- const userPages = authService.getUserPages();
- if (userPages) {
- setPages(userPages);
- if (userPages.length > 0) {
- // Ensure activePageId is valid, otherwise default to the first page
- const currentActive = userPages.find(p => p.id === activePageId);
- if (!currentActive) {
- setActivePageId(userPages[0].id);
- }
- } else {
- setActivePageId(null);
- }
- }
- } else {
- setCurrentUser(null);
- setPages([]);
- setActivePageId(null);
- }
- };
- loadUserData();
- // Listen for storage changes to handle login/logout from other tabs
- window.addEventListener('storage', loadUserData);
- return () => {
- window.removeEventListener('storage', loadUserData);
- };
- }, [currentUser, activePageId]);
- // Save pages whenever they change
- React.useEffect(() => {
- if (currentUser && pages.length > 0) {
- authService.saveUserPages(pages);
- }
- }, [pages, currentUser]);
- React.useEffect(() => {
- if (theme === 'dark') {
- document.documentElement.classList.add('dark');
- } else {
- document.documentElement.classList.remove('dark');
- }
- }, [theme]);
- const activePage = React.useMemo(() => pages.find(p => p.id === activePageId), [pages, activePageId]);
-
- const handleAuthSuccess = () => {
- const user = authService.getCurrentUser();
- setCurrentUser(user);
- };
- const handleLogout = () => {
- authService.logout();
- setCurrentUser(null);
- };
- const handleUpdateActivePage = (updates: Partial<GreenPage>) => {
- setPages(currentPages =>
- currentPages.map(page =>
- page.id === activePageId ? { ...page, ...updates } : page
- )
- );
- };
-
- const handleUpdatePage = (id: string, newName: string) => {
- setPages(currentPages =>
- currentPages.map(page =>
- page.id === id ? { ...page, name: newName, slug: newName.toLowerCase().replace(/\s+/g, '-') } : page
- )
- );
- };
- const handleCreatePage = (name: string) => {
- if (!name.trim()) return;
- const newPage = createNewPage(name);
- setPages(prev => [...prev, newPage]);
- setActivePageId(newPage.id);
- setActiveNavKey('Page.Link');
- setIsPageManagerOpen(false);
- };
- const handleImportShowcasePage = (pageData: GreenPage) => {
- // This is a deep copy to prevent state mutation issues
- const newPage: GreenPage = JSON.parse(JSON.stringify(pageData));
- // Make it unique for the user's list
- newPage.id = `page_${Date.now()}_${Math.random()}`;
- newPage.name = `${pageData.name} (Copy)`;
- newPage.slug = `${pageData.slug}-copy-${Math.floor(Math.random() * 1000)}`;
- setPages(prev => [...prev, newPage]);
- setActivePageId(newPage.id);
- setActiveNavKey('Page.Link'); // Switch to the page builder
- alert(t('app.import_success', { name: pageData.name }));
- };
- const handleVideosGenerated = (newVideos: any[]) => {
- if (!activePage) return;
- const updatedAIGCSettings = {
- ...activePage.aigcSettings,
- videos: [...activePage.aigcSettings.videos, ...newVideos]
- };
- handleUpdateActivePage({ aigcSettings: updatedAIGCSettings });
- alert(t('app.videos_generated_success', { count: newVideos.length }));
- setActiveNavKey('AIGC.Scheduler');
- };
- const handleScheduleUpdate = (newSchedule: any[]) => {
- if (!activePage) return;
- const updatedAIGCSettings = { ...activePage.aigcSettings, schedule: newSchedule };
- handleUpdateActivePage({ aigcSettings: updatedAIGCSettings });
- };
- const handleUpdateAIGCSettings = (newSettings: AIGCSettings) => {
- handleUpdateActivePage({ aigcSettings: newSettings });
- };
- const handleFormSubmission = (submission: FormSubmission) => {
- if (!activePage) return;
- const updatedAnalyticsData = {
- ...activePage.analyticsData,
- formSubmissions: [...(activePage.analyticsData.formSubmissions || []), submission]
- };
- handleUpdateActivePage({ analyticsData: updatedAnalyticsData });
- alert(t('app.form_submission_success'));
- };
- const renderContent = () => {
- if (activeNavKey.startsWith('Showcase.')) {
- const tab = (activeNavKey.split('.')[1] || 'Personal').toLowerCase();
- return <Showcase initialTab={tab as any} onImportPage={handleImportShowcasePage} />;
- }
-
- if (!activePage) {
- return (
- <div className="p-8 text-center text-gray-500 dark:text-gray-400 flex flex-col items-center justify-center h-full">
- <h2 className="text-2xl font-bold mb-2 text-gray-800 dark:text-gray-200">{t('app.welcome')}</h2>
- <p className="mb-6">{t('app.no_pages_prompt')}</p>
- <button onClick={() => setIsPageManagerOpen(true)} className="bg-brand-primary text-white font-bold py-2 px-5 rounded-md hover:bg-brand-secondary transition-colors">
- {t('app.create_first_page')}
- </button>
- </div>
- );
- }
- if (activeNavKey.startsWith('Page.')) {
- const tab = (activeNavKey.split('.')[1] || '').toLowerCase();
- return <PageBuilder
- key={activePage.id}
- pageSettings={activePage.pageSettings}
- onUpdate={(newSettings) => handleUpdateActivePage({ pageSettings: newSettings })}
- aigcVideos={activePage.aigcSettings.videos}
- aigcArticles={activePage.aigcSettings.articles}
- initialTab={tab as any || 'link'}
- onOpenShareModal={() => setIsShareModalOpen(true)}
- onFormSubmit={handleFormSubmission}
- />
- }
-
- if (activeNavKey.startsWith('AI Assistant.')) {
- const tab = (activeNavKey.split('.')[1] || 'Persona').toLowerCase();
- return <AIAssistant
- key={activePage.id}
- aiAssistantSettings={activePage.aiAssistantSettings}
- onUpdateSettings={(newSettings) => handleUpdateActivePage({ aiAssistantSettings: newSettings })}
- initialTab={tab as any}
- />
- }
- if (activeNavKey.startsWith('SEO.')) {
- const tab = (activeNavKey.split('.')[1] || 'ShortLinks');
- switch (tab) {
- case 'ShortLinks':
- return <ShortLinks
- key={activePage.id}
- slug={activePage.slug}
- onUpdateSlug={(slug) => handleUpdateActivePage({ slug })}
- />
- case 'Hosting':
- return <EnterpriseHosting key={activePage.id} />
- case 'Services':
- return <SEOServices key={activePage.id} />
- default:
- return <ShortLinks key={activePage.id} slug={activePage.slug} onUpdateSlug={(slug) => handleUpdateActivePage({ slug })}/>
- }
- }
- switch (activeNavKey) {
- case 'Analytics.Page':
- return <PageAnalytics key={activePage.id} analyticsData={activePage.analyticsData} />
- case 'Analytics.Interactions':
- return <InteractionAnalytics
- key={activePage.id}
- analyticsData={activePage.analyticsData}
- onUpdateConversations={(conversations) => handleUpdateActivePage({ analyticsData: { ...activePage.analyticsData, conversations } })}
- />
- case 'Analytics.CRM':
- return <CRM key={activePage.id} analyticsData={activePage.analyticsData} />
- case 'AIGC.Creator':
- return <VideoCreator
- key={activePage.id}
- aigcSettings={activePage.aigcSettings}
- onUpdateAIGCSettings={handleUpdateAIGCSettings}
- onVideosGenerated={handleVideosGenerated}
- />
- case 'AIGC.News':
- return <NewsCreator
- key={activePage.id}
- aigcSettings={activePage.aigcSettings}
- onUpdateAIGCSettings={handleUpdateAIGCSettings}
- />
- case 'AIGC.Scheduler':
- return <ContentScheduler
- key={activePage.id}
- videos={activePage.aigcSettings.videos}
- schedule={activePage.aigcSettings.schedule}
- onScheduleUpdate={handleScheduleUpdate}
- />
- default:
- return <PageBuilder
- key={activePage.id}
- pageSettings={activePage.pageSettings}
- onUpdate={(newSettings) => handleUpdateActivePage({ pageSettings: newSettings })}
- aigcVideos={activePage.aigcSettings.videos}
- aigcArticles={activePage.aigcSettings.articles}
- initialTab="link"
- onOpenShareModal={() => setIsShareModalOpen(true)}
- onFormSubmit={handleFormSubmission}
- />
- }
- };
- if (!currentUser) {
- return <Auth onAuthSuccess={handleAuthSuccess} />;
- }
- return (
- <div className="flex h-screen bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
- <Sidebar
- activePageName={activePage ? activePage.name : t('app.no_page_selected')}
- activePageThemeColor={activePage ? activePage.themeColor : 'from-gray-500 to-gray-700'}
- onOpenPageManager={() => setIsPageManagerOpen(true)}
- activeNavKey={activeNavKey}
- setActiveNavKey={setActiveNavKey}
- theme={theme}
- setTheme={setTheme}
- currentUser={currentUser}
- onLogout={handleLogout}
- />
- <main className="flex-1 overflow-y-auto">
- {renderContent()}
- </main>
- {isPageManagerOpen && (
- <PageManagementModal
- pages={pages}
- activePageId={activePageId || ''}
- onSelectPage={(id) => {
- setActivePageId(id);
- setIsPageManagerOpen(false);
- }}
- onCreatePage={handleCreatePage}
- onUpdatePage={handleUpdatePage}
- onClose={() => setIsPageManagerOpen(false)}
- />
- )}
- {isShareModalOpen && activePage && (
- <ShareModal
- pageSlug={activePage.slug}
- onClose={() => setIsShareModalOpen(false)}
- />
- )}
- </div>
- );
- };
- const App = () => {
- return (
- <LanguageProvider>
- <MainApp />
- </LanguageProvider>
- );
- };
- export default App;
|