Files
cannaiq/cannaiq/src/App.tsx
Kelly d102d27731 feat(admin): Dispensary schedule page and UI cleanup
- Add DispensarySchedule page showing crawl history and upcoming schedule
- Add /dispensaries/:state/:city/:slug/schedule route
- Add API endpoint for store crawl history
- Update View Schedule link to use dispensary-specific route
- Remove colored badges from DispensaryDetail product table (plain text)
- Make Details button ghost style in product table
- Add "Sort by States" option to IntelligenceBrands
- Remove status filter dropdown from Dispensaries page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 23:50:47 -07:00

139 lines
9.3 KiB
TypeScript
Executable File

// CannaIQ v1.8.0 - Emerald Theme
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { Home } from './pages/Home';
import { Login } from './pages/Login';
import { Dashboard } from './pages/Dashboard';
import { Products } from './pages/Products';
import { ProductDetail } from './pages/ProductDetail';
import { Stores } from './pages/Stores';
import { Dispensaries } from './pages/Dispensaries';
import { DispensaryDetail } from './pages/DispensaryDetail';
import { DispensarySchedule } from './pages/DispensarySchedule';
import { StoreDetail } from './pages/StoreDetail';
import { StoreBrands } from './pages/StoreBrands';
import { StoreSpecials } from './pages/StoreSpecials';
import { Categories } from './pages/Categories';
import { Campaigns } from './pages/Campaigns';
import { Analytics } from './pages/Analytics';
import { ClickAnalytics } from './pages/ClickAnalytics';
import { Specials } from './pages/Specials';
import { PriceCompare } from './pages/PriceCompare';
import { Settings } from './pages/Settings';
import { Proxies } from './pages/Proxies';
import { Logs } from './pages/Logs';
import { ScraperMonitor } from './pages/ScraperMonitor';
import { ScraperSchedule } from './pages/ScraperSchedule';
import { ScraperTools } from './pages/ScraperTools';
import { ChangeApproval } from './pages/ChangeApproval';
import { ApiPermissions } from './pages/ApiPermissions';
import { AISettings } from './pages/AISettings';
import { CrawlSchedulePage } from './pages/CrawlSchedulePage';
import { StoresListPage } from './pages/StoresListPage';
import { StoreDetailPage } from './pages/StoreDetailPage';
import { WholesaleAnalytics } from './pages/WholesaleAnalytics';
import { Users } from './pages/Users';
import { OrchestratorDashboard } from './pages/OrchestratorDashboard';
import { OrchestratorProducts } from './pages/OrchestratorProducts';
import { OrchestratorBrands } from './pages/OrchestratorBrands';
import { OrchestratorStores } from './pages/OrchestratorStores';
import { ChainsDashboard } from './pages/ChainsDashboard';
import { IntelligenceBrands } from './pages/IntelligenceBrands';
import { IntelligencePricing } from './pages/IntelligencePricing';
import { IntelligenceStores } from './pages/IntelligenceStores';
import { SyncInfoPanel } from './pages/SyncInfoPanel';
import NationalDashboard from './pages/NationalDashboard';
import StateHeatmap from './pages/StateHeatmap';
import CrossStateCompare from './pages/CrossStateCompare';
import StateDetail from './pages/StateDetail';
import { Discovery } from './pages/Discovery';
import { WorkersDashboard } from './pages/WorkersDashboard';
import { JobQueue } from './pages/JobQueue';
import TasksDashboard from './pages/TasksDashboard';
import { ScraperOverviewDashboard } from './pages/ScraperOverviewDashboard';
import { SeoOrchestrator } from './pages/admin/seo/SeoOrchestrator';
import { StatePage } from './pages/public/StatePage';
import { SeoPage } from './pages/public/SeoPage';
import { PrivateRoute } from './components/PrivateRoute';
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/dashboard" element={<PrivateRoute><Dashboard /></PrivateRoute>} />
<Route path="/products" element={<PrivateRoute><Products /></PrivateRoute>} />
<Route path="/products/:id" element={<PrivateRoute><ProductDetail /></PrivateRoute>} />
<Route path="/stores" element={<PrivateRoute><Stores /></PrivateRoute>} />
<Route path="/dispensaries" element={<PrivateRoute><Dispensaries /></PrivateRoute>} />
<Route path="/dispensaries/:state/:city/:slug" element={<PrivateRoute><DispensaryDetail /></PrivateRoute>} />
<Route path="/dispensaries/:state/:city/:slug/schedule" element={<PrivateRoute><DispensarySchedule /></PrivateRoute>} />
<Route path="/stores/:state/:storeName/:slug/brands" element={<PrivateRoute><StoreBrands /></PrivateRoute>} />
<Route path="/stores/:state/:storeName/:slug/specials" element={<PrivateRoute><StoreSpecials /></PrivateRoute>} />
<Route path="/stores/:state/:storeName/:slug" element={<PrivateRoute><StoreDetail /></PrivateRoute>} />
<Route path="/categories" element={<PrivateRoute><Categories /></PrivateRoute>} />
<Route path="/campaigns" element={<PrivateRoute><Campaigns /></PrivateRoute>} />
<Route path="/analytics" element={<PrivateRoute><Analytics /></PrivateRoute>} />
<Route path="/analytics/clicks" element={<PrivateRoute><ClickAnalytics /></PrivateRoute>} />
<Route path="/analytics/specials" element={<PrivateRoute><Specials /></PrivateRoute>} />
<Route path="/analytics/compare" element={<PrivateRoute><PriceCompare /></PrivateRoute>} />
<Route path="/settings" element={<PrivateRoute><Settings /></PrivateRoute>} />
<Route path="/changes" element={<PrivateRoute><ChangeApproval /></PrivateRoute>} />
<Route path="/proxies" element={<PrivateRoute><Proxies /></PrivateRoute>} />
<Route path="/logs" element={<PrivateRoute><Logs /></PrivateRoute>} />
<Route path="/scraper-tools" element={<PrivateRoute><ScraperTools /></PrivateRoute>} />
<Route path="/scraper-monitor" element={<PrivateRoute><ScraperMonitor /></PrivateRoute>} />
<Route path="/scraper-schedule" element={<PrivateRoute><ScraperSchedule /></PrivateRoute>} />
{/* Provider-agnostic routes */}
<Route path="/schedule" element={<PrivateRoute><CrawlSchedulePage /></PrivateRoute>} />
<Route path="/stores/list" element={<PrivateRoute><StoresListPage /></PrivateRoute>} />
<Route path="/stores/list/:id" element={<PrivateRoute><StoreDetailPage /></PrivateRoute>} />
<Route path="/monitor" element={<PrivateRoute><WorkersDashboard /></PrivateRoute>} />
{/* Legacy AZ routes - redirect to new paths */}
<Route path="/az-schedule" element={<Navigate to="/schedule" replace />} />
<Route path="/az" element={<Navigate to="/stores/list" replace />} />
<Route path="/az/stores/:id" element={<PrivateRoute><StoreDetailPage /></PrivateRoute>} />
<Route path="/api-permissions" element={<PrivateRoute><ApiPermissions /></PrivateRoute>} />
<Route path="/ai-settings" element={<PrivateRoute><AISettings /></PrivateRoute>} />
<Route path="/wholesale-analytics" element={<PrivateRoute><WholesaleAnalytics /></PrivateRoute>} />
<Route path="/users" element={<PrivateRoute><Users /></PrivateRoute>} />
{/* National / Multi-State routes */}
<Route path="/national" element={<PrivateRoute><NationalDashboard /></PrivateRoute>} />
<Route path="/national/heatmap" element={<PrivateRoute><StateHeatmap /></PrivateRoute>} />
<Route path="/national/compare" element={<PrivateRoute><CrossStateCompare /></PrivateRoute>} />
<Route path="/national/state/:stateCode" element={<PrivateRoute><StateDetail /></PrivateRoute>} />
{/* Admin routes */}
<Route path="/admin" element={<Navigate to="/admin/orchestrator" replace />} />
<Route path="/admin/orchestrator" element={<PrivateRoute><OrchestratorDashboard /></PrivateRoute>} />
<Route path="/admin/orchestrator/products" element={<PrivateRoute><OrchestratorProducts /></PrivateRoute>} />
<Route path="/admin/orchestrator/brands" element={<PrivateRoute><OrchestratorBrands /></PrivateRoute>} />
<Route path="/admin/orchestrator/stores" element={<PrivateRoute><OrchestratorStores /></PrivateRoute>} />
<Route path="/admin/orchestrator/chains" element={<PrivateRoute><ChainsDashboard /></PrivateRoute>} />
{/* Intelligence routes */}
<Route path="/admin/intelligence" element={<Navigate to="/admin/intelligence/brands" replace />} />
<Route path="/admin/intelligence/brands" element={<PrivateRoute><IntelligenceBrands /></PrivateRoute>} />
<Route path="/admin/intelligence/pricing" element={<PrivateRoute><IntelligencePricing /></PrivateRoute>} />
<Route path="/admin/intelligence/stores" element={<PrivateRoute><IntelligenceStores /></PrivateRoute>} />
<Route path="/admin/intelligence/sync" element={<PrivateRoute><SyncInfoPanel /></PrivateRoute>} />
{/* SEO Orchestrator */}
<Route path="/admin/seo" element={<PrivateRoute><SeoOrchestrator /></PrivateRoute>} />
{/* Public SEO pages (no auth) - all use SeoPage renderer for generated content */}
<Route path="/states/:slug" element={<SeoPage />} />
<Route path="/alternatives/:slug" element={<SeoPage />} />
<Route path="/brands/:slug" element={<SeoPage />} />
{/* Discovery routes */}
<Route path="/discovery" element={<PrivateRoute><Discovery /></PrivateRoute>} />
{/* Workers Dashboard */}
<Route path="/workers" element={<PrivateRoute><WorkersDashboard /></PrivateRoute>} />
{/* Job Queue Management */}
<Route path="/job-queue" element={<PrivateRoute><JobQueue /></PrivateRoute>} />
{/* Task Queue Dashboard */}
<Route path="/tasks" element={<PrivateRoute><TasksDashboard /></PrivateRoute>} />
{/* Scraper Overview Dashboard (new primary) */}
<Route path="/scraper/overview" element={<PrivateRoute><ScraperOverviewDashboard /></PrivateRoute>} />
<Route path="*" element={<Navigate to="/dashboard" replace />} />
</Routes>
</BrowserRouter>
);
}