feat: Responsive admin UI, SEO pages, and click analytics
## Responsive Admin UI - Layout.tsx: Mobile sidebar drawer with hamburger menu - Dashboard.tsx: 2-col grid on mobile, responsive stats cards - OrchestratorDashboard.tsx: Responsive table with hidden columns - PagesTab.tsx: Responsive filters and table ## SEO Pages - New /admin/seo section with state landing pages - SEO page generation and management - State page content with dispensary/product counts ## Click Analytics - Product click tracking infrastructure - Click analytics dashboard ## Other Changes - Consumer features scaffolding (alerts, deals, favorites) - Health panel component - Workers dashboard improvements - Legacy DutchieAZ pages removed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -269,13 +269,12 @@ router.get('/dispensaries/:id/profile', async (req: Request, res: Response) => {
|
||||
dcp.dispensary_id,
|
||||
dcp.profile_key,
|
||||
dcp.profile_name,
|
||||
dcp.platform,
|
||||
dcp.crawler_type,
|
||||
dcp.version,
|
||||
dcp.status,
|
||||
dcp.config,
|
||||
dcp.enabled,
|
||||
dcp.sandbox_attempt_count,
|
||||
dcp.next_retry_at,
|
||||
dcp.sandbox_attempts,
|
||||
dcp.created_at,
|
||||
dcp.updated_at,
|
||||
d.name as dispensary_name,
|
||||
@@ -318,13 +317,12 @@ router.get('/dispensaries/:id/profile', async (req: Request, res: Response) => {
|
||||
id: profile.id,
|
||||
profileKey: profile.profile_key,
|
||||
profileName: profile.profile_name,
|
||||
platform: profile.platform,
|
||||
crawlerType: profile.crawler_type,
|
||||
version: profile.version,
|
||||
status: profile.status || profile.config?.status || 'unknown',
|
||||
config: profile.config,
|
||||
enabled: profile.enabled,
|
||||
sandboxAttemptCount: profile.sandbox_attempt_count,
|
||||
nextRetryAt: profile.next_retry_at,
|
||||
sandboxAttempts: profile.sandbox_attempts || [],
|
||||
createdAt: profile.created_at,
|
||||
updatedAt: profile.updated_at,
|
||||
},
|
||||
@@ -349,7 +347,7 @@ router.get('/dispensaries/:id/crawler-module', async (req: Request, res: Respons
|
||||
|
||||
// Get the profile key for this dispensary
|
||||
const { rows } = await pool.query(`
|
||||
SELECT profile_key, platform
|
||||
SELECT profile_key, crawler_type
|
||||
FROM dispensary_crawler_profiles
|
||||
WHERE dispensary_id = $1 AND enabled = true
|
||||
ORDER BY updated_at DESC
|
||||
@@ -364,14 +362,14 @@ router.get('/dispensaries/:id/crawler-module', async (req: Request, res: Respons
|
||||
}
|
||||
|
||||
const profileKey = rows[0].profile_key;
|
||||
const platform = rows[0].platform || 'dutchie';
|
||||
const crawlerType = rows[0].crawler_type || 'dutchie';
|
||||
|
||||
// Construct file path
|
||||
const modulePath = path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'crawlers',
|
||||
platform,
|
||||
crawlerType,
|
||||
'stores',
|
||||
`${profileKey}.ts`
|
||||
);
|
||||
@@ -381,7 +379,7 @@ router.get('/dispensaries/:id/crawler-module', async (req: Request, res: Respons
|
||||
return res.status(404).json({
|
||||
error: `Crawler module file not found: ${profileKey}.ts`,
|
||||
hasModule: false,
|
||||
expectedPath: `crawlers/${platform}/stores/${profileKey}.ts`,
|
||||
expectedPath: `crawlers/${crawlerType}/stores/${profileKey}.ts`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -391,9 +389,9 @@ router.get('/dispensaries/:id/crawler-module', async (req: Request, res: Respons
|
||||
res.json({
|
||||
hasModule: true,
|
||||
profileKey,
|
||||
platform,
|
||||
crawlerType,
|
||||
fileName: `${profileKey}.ts`,
|
||||
filePath: `crawlers/${platform}/stores/${profileKey}.ts`,
|
||||
filePath: `crawlers/${crawlerType}/stores/${profileKey}.ts`,
|
||||
content,
|
||||
lines: content.split('\n').length,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user