diff --git a/backlog/features.json b/backlog/features.json index 16a429a..9ce6acd 100644 --- a/backlog/features.json +++ b/backlog/features.json @@ -7780,6 +7780,54 @@ }, "phase": "storefront", "completed_at": "2026-08-24T14:13:16Z" + }, + { + "id": "ADMIN-UI-FIXES2", + "type": "fix", + "title": "Admin UI fixes batch 2: trend chart, logs, KPI cards, AI timeout, X/Pinterest, product expiry/weight", + "description": "Need change", + "priority": "high", + "risk": "low", + "status": "pending", + "created_at": "2026-08-24", + "gates": { + "reviewer": false, + "security": false, + "qa": false + }, + "phase": "admin" + }, + { + "id": "FRONTEND-UI-FIXES2", + "type": "fix", + "title": "Frontend/Storefront fixes 2: live search BASE URL, product expiry/weight, TPV receipt clock", + "description": "Need change", + "priority": "high", + "risk": "low", + "status": "pending", + "created_at": "2026-08-24", + "gates": { + "reviewer": false, + "security": false, + "qa": false + }, + "phase": "frontend+storefront" + }, + { + "id": "INVENTORY-OPT", + "type": "fix", + "title": "Inventory optimization: pagination, queries, filters for 10k+ products", + "description": "Need change", + "priority": "med", + "risk": "low", + "status": "pending", + "created_at": "2026-08-24", + "gates": { + "reviewer": false, + "security": false, + "qa": false + }, + "phase": "backend" } ] } diff --git a/project/apps/admin/src/app/(dashboard)/page.tsx b/project/apps/admin/src/app/(dashboard)/page.tsx index dfa0b6f..2505771 100644 --- a/project/apps/admin/src/app/(dashboard)/page.tsx +++ b/project/apps/admin/src/app/(dashboard)/page.tsx @@ -1,6 +1,7 @@ 'use client'; import { useState, useEffect } from 'react'; import { api } from '@/lib/api-client'; +import Link from 'next/link'; interface Stats { ordersToday: number; @@ -47,15 +48,17 @@ function KPICard({ sub, icon, trend, + href, }: { label: string; value: string; sub?: string; icon: string; trend?: 'up' | 'down' | 'neutral'; + href?: string; }) { - return ( -
{label}
@@ -66,6 +69,7 @@ function KPICard({| + |
{/* Extra fields for HTTP request logs */}
{entry.method && entry.url && (
diff --git a/project/apps/admin/src/components/reporting/TrendChart.tsx b/project/apps/admin/src/components/reporting/TrendChart.tsx
index fd591ac..df91799 100644
--- a/project/apps/admin/src/components/reporting/TrendChart.tsx
+++ b/project/apps/admin/src/components/reporting/TrendChart.tsx
@@ -13,7 +13,7 @@ interface TrendChartProps {
height?: number;
}
-export function TrendChart({ data, maxValue, height = 200 }: TrendChartProps) {
+export function TrendChart({ data, maxValue, height = 120 }: TrendChartProps) {
if (data.length === 0) return null;
const width = 100; // percentage-based SVG
diff --git a/project/migrations/062_settings_twitter_pinterest.js b/project/migrations/062_settings_twitter_pinterest.js
new file mode 100644
index 0000000..ace87c9
--- /dev/null
+++ b/project/migrations/062_settings_twitter_pinterest.js
@@ -0,0 +1,13 @@
+/**
+ * Add twitter_url and pinterest_url columns to store_settings table.
+ * Usage: node --env-file=.env -e "require('./migrations/062_settings_twitter_pinterest.js')"
+ */
+import { query } from '../src/infrastructure/db/migrate.js';
+
+async function migrate() {
+ await query(`ALTER TABLE store_settings ADD COLUMN IF NOT EXISTS twitter_url TEXT`);
+ await query(`ALTER TABLE store_settings ADD COLUMN IF NOT EXISTS pinterest_url TEXT`);
+ console.log('✓ Added twitter_url and pinterest_url to store_settings');
+}
+
+migrate().catch(e => { console.error(e); process.exit(1); });
diff --git a/project/src/modules/store-settings/api/settings.routes.ts b/project/src/modules/store-settings/api/settings.routes.ts
index 847c8ce..9e39abe 100644
--- a/project/src/modules/store-settings/api/settings.routes.ts
+++ b/project/src/modules/store-settings/api/settings.routes.ts
@@ -21,6 +21,8 @@ const updateSettingsSchema = z.object({
footerText: z.string().max(400).optional(),
facebookUrl: z.string().url().optional().or(z.literal('')),
instagramUrl: z.string().url().optional().or(z.literal('')),
+ twitterUrl: z.string().url().optional().or(z.literal('')),
+ pinterestUrl: z.string().url().optional().or(z.literal('')),
aiProvider: z.string().max(80).optional(),
aiBaseUrl: z.string().url().optional().or(z.literal('')),
aiModel: z.string().max(120).optional(),
@@ -69,6 +71,8 @@ const SETTING_KEYS: Record |