Fix TypeScript errors in experiments feature

- Add experimentMap/onOpenExperiment props to WeeklyRow component
- Export VendorDailyRow type from supabase.ts
- Fix type errors in experiments.ts (unknown[] to string[])
- Add type annotation for allAsins in App.tsx

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Christian Vidal Wolf
2026-02-20 19:39:56 +01:00
co-authored by Qwen-Coder
parent f93d92da0b
commit a21c0d532c
5 changed files with 24 additions and 17 deletions
+1 -1
View File
@@ -251,7 +251,7 @@ const App: React.FC = () => {
const handleExperimentsFetch = useCallback(async () => { const handleExperimentsFetch = useCallback(async () => {
try { try {
const allAsins = Array.from(new Set(rawData.map(r => r.asin.toUpperCase()))); const allAsins: string[] = Array.from(new Set(rawData.map(r => String(r.asin).toUpperCase())));
const expMap = await getActiveExperimentsForASINs(allAsins); const expMap = await getActiveExperimentsForASINs(allAsins);
setExperimentMap(expMap); setExperimentMap(expMap);
console.log('[App] Loaded experiments for', expMap.size, 'ASINs'); console.log('[App] Loaded experiments for', expMap.size, 'ASINs');
+9 -10
View File
@@ -7,25 +7,24 @@ interface ExperimentBadgeProps {
onClick?: (experimentId: string) => void; onClick?: (experimentId: string) => void;
} }
const getStatusBadge = (status: ExperimentStatus) => {
switch (status) {
case 'active': return '🟢';
case 'planned': return '🟡';
case 'completed': return '⚪';
case 'paused': return '⏸️';
}
};
export const ExperimentBadge: React.FC<ExperimentBadgeProps> = ({ experiments, onClick }) => { export const ExperimentBadge: React.FC<ExperimentBadgeProps> = ({ experiments, onClick }) => {
if (!experiments || experiments.length === 0) return null; if (!experiments || experiments.length === 0) return null;
const activeExp = experiments.find(e => e.status === 'active'); const activeExp = experiments.find(e => e.status === 'active');
const plannedExp = experiments.find(e => e.status === 'planned'); const plannedExp = experiments.find(e => e.status === 'planned');
const hasPast = experiments.some(e => e.status === 'completed' || e.status === 'paused');
// Priority: active > planned > past // Priority: active > planned > past
const displayExp = activeExp || plannedExp || experiments[0]; const displayExp = activeExp || plannedExp || experiments[0];
const getStatusBadge = (status: ExperimentStatus) => {
switch (status) {
case 'active': return '🟢';
case 'planned': return '🟡';
case 'completed': return '⚪';
case 'paused': return '⏸️';
}
};
const daysText = displayExp.days_remaining !== undefined const daysText = displayExp.days_remaining !== undefined
? displayExp.days_remaining > 0 ? displayExp.days_remaining > 0
? `${displayExp.days_remaining}d left` ? `${displayExp.days_remaining}d left`
+8 -2
View File
@@ -159,7 +159,9 @@ const WeeklyRow: React.FC<{
velocityMap?: Map<string, number>; velocityMap?: Map<string, number>;
buyBoxLostMap?: Map<string, { countries: string[]; reasons: Record<string, string> }>; buyBoxLostMap?: Map<string, { countries: string[]; reasons: Record<string, string> }>;
primaryMetric: 'units' | 'revenue'; primaryMetric: 'units' | 'revenue';
}> = React.memo(({ row, weeks, onDrillDown, stockMap, top50Ranking, top50Mode, sortConfig, renderGrowth, customerFilters, vendorStockMap, velocityMap, buyBoxLostMap, primaryMetric }) => { experimentMap?: Map<string, ActiveExperiment[]>;
onOpenExperiment?: (experimentId: string) => void;
}> = React.memo(({ row, weeks, onDrillDown, stockMap, top50Ranking, top50Mode, sortConfig, renderGrowth, customerFilters, vendorStockMap, velocityMap, buyBoxLostMap, primaryMetric, experimentMap, onOpenExperiment }) => {
const ranks: { rank: number; label: string; theme: 'amber' | 'blue' | 'indigo' }[] = []; const ranks: { rank: number; label: string; theme: 'amber' | 'blue' | 'indigo' }[] = [];
const asin = row.asin.trim().toUpperCase(); const asin = row.asin.trim().toUpperCase();
@@ -346,7 +348,9 @@ const WeeklyGrid: React.FC<WeeklyGridProps & { top50Mode: 'eu' | 'uk' }> = ({
customerFilters, customerFilters,
top50Mode, top50Mode,
velocityMap, velocityMap,
buyBoxLostMap buyBoxLostMap,
experimentMap,
onOpenExperiment
}) => { }) => {
// Pivot data - memoized // Pivot data - memoized
const { rows, weeks: allWeeks } = useMemo(() => pivotWeeklySalesData(data), [data]); const { rows, weeks: allWeeks } = useMemo(() => pivotWeeklySalesData(data), [data]);
@@ -1030,6 +1034,8 @@ const WeeklyGrid: React.FC<WeeklyGridProps & { top50Mode: 'eu' | 'uk' }> = ({
velocityMap={velocityMap} velocityMap={velocityMap}
buyBoxLostMap={buyBoxLostMap} buyBoxLostMap={buyBoxLostMap}
primaryMetric={primaryMetric} primaryMetric={primaryMetric}
experimentMap={experimentMap}
onOpenExperiment={onOpenExperiment}
/> />
))} ))}
{displayCount < sortedRows.length && ( {displayCount < sortedRows.length && (
+1 -1
View File
@@ -166,7 +166,7 @@ export const getActiveExperimentsForASINs = async (
for (const asin of asins) { for (const asin of asins) {
const experiments = (data || []) const experiments = (data || [])
.filter((exp: any) => exp.asins?.includes(asin)) .filter((exp: any) => Array.isArray(exp.asins) && exp.asins.includes(asin))
.map((exp: any) => { .map((exp: any) => {
const endDate = exp.end_date ? new Date(exp.end_date) : null; const endDate = exp.end_date ? new Date(exp.end_date) : null;
const daysRemaining = endDate const daysRemaining = endDate
+2
View File
@@ -2,6 +2,8 @@
import { createClient, SupabaseClient } from '@supabase/supabase-js'; import { createClient, SupabaseClient } from '@supabase/supabase-js';
import { VendorDailyRow } from '../types'; import { VendorDailyRow } from '../types';
export type { VendorDailyRow };
const supabaseUrl = process.env.SUPABASE_URL || ''; const supabaseUrl = process.env.SUPABASE_URL || '';
const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || ''; const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || '';