mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 14:05:24 +02:00
- 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>
115 lines
3.5 KiB
TypeScript
115 lines
3.5 KiB
TypeScript
import React from 'react';
|
|
import { ActiveExperiment, ExperimentStatus } from '../types';
|
|
import { getExperimentStatusColor, getExperimentTypeColor, getExperimentIcon } from '../services/experiments';
|
|
|
|
interface ExperimentBadgeProps {
|
|
experiments: ActiveExperiment[];
|
|
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 }) => {
|
|
if (!experiments || experiments.length === 0) return null;
|
|
|
|
const activeExp = experiments.find(e => e.status === 'active');
|
|
const plannedExp = experiments.find(e => e.status === 'planned');
|
|
|
|
// Priority: active > planned > past
|
|
const displayExp = activeExp || plannedExp || experiments[0];
|
|
|
|
const daysText = displayExp.days_remaining !== undefined
|
|
? displayExp.days_remaining > 0
|
|
? `${displayExp.days_remaining}d left`
|
|
: 'Ending soon'
|
|
: '';
|
|
|
|
return (
|
|
<div className="inline-flex items-center gap-1">
|
|
{experiments.length > 1 && (
|
|
<span className="text-[9px] text-slate-500 mr-1">+{experiments.length}</span>
|
|
)}
|
|
<button
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
onClick?.(displayExp.experiment_id);
|
|
}}
|
|
className={`
|
|
inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[9px] font-medium
|
|
border ${getExperimentStatusColor(displayExp.status)}
|
|
hover:opacity-80 transition-opacity cursor-pointer
|
|
`}
|
|
title={`${displayExp.experiment_name}
|
|
Type: ${displayExp.type}
|
|
Start: ${displayExp.start_date}
|
|
End: ${displayExp.end_date || 'Ongoing'}
|
|
${daysText}`}
|
|
>
|
|
<span>{getExperimentIcon(displayExp.type)}</span>
|
|
<span className="hidden xl:inline truncate max-w-[80px]">{displayExp.experiment_name}</span>
|
|
{daysText && <span className="opacity-60">{daysText}</span>}
|
|
</button>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface ExperimentStatusBadgeProps {
|
|
status: ExperimentStatus;
|
|
size?: 'sm' | 'md' | 'lg';
|
|
}
|
|
|
|
export const ExperimentStatusBadge: React.FC<ExperimentStatusBadgeProps> = ({ status, size = 'md' }) => {
|
|
const sizeClasses = {
|
|
sm: 'px-1.5 py-0.5 text-[9px]',
|
|
md: 'px-2 py-1 text-xs',
|
|
lg: 'px-3 py-1.5 text-sm',
|
|
};
|
|
|
|
const statusLabels = {
|
|
active: 'Active',
|
|
planned: 'Planned',
|
|
completed: 'Completed',
|
|
paused: 'Paused',
|
|
};
|
|
|
|
return (
|
|
<span className={`inline-flex items-center gap-1 rounded-full font-medium border ${getExperimentStatusColor(status)} ${sizeClasses[size]}`}>
|
|
{getStatusBadge(status)} {statusLabels[status]}
|
|
</span>
|
|
);
|
|
};
|
|
|
|
interface ExperimentTypeBadgeProps {
|
|
type: string;
|
|
size?: 'sm' | 'md' | 'lg';
|
|
}
|
|
|
|
export const ExperimentTypeBadge: React.FC<ExperimentTypeBadgeProps> = ({ type, size = 'md' }) => {
|
|
const sizeClasses = {
|
|
sm: 'px-1.5 py-0.5 text-[9px]',
|
|
md: 'px-2 py-1 text-xs',
|
|
lg: 'px-3 py-1.5 text-sm',
|
|
};
|
|
|
|
const typeLabels = {
|
|
pricing: 'Pricing',
|
|
advertising: 'Advertising',
|
|
content: 'Content',
|
|
promotion: 'Promotion',
|
|
};
|
|
|
|
return (
|
|
<span className={`inline-flex items-center gap-1 rounded-full font-medium border ${getExperimentTypeColor(type as any)} ${sizeClasses[size]}`}>
|
|
<span>{getExperimentIcon(type as any)}</span>
|
|
{typeLabels[type as keyof typeof typeLabels] || type}
|
|
</span>
|
|
);
|
|
};
|