@decido/shell 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +13 -0
- package/package.json +65 -0
- package/src/AgentPlayer.tsx +105 -0
- package/src/DecidoPlayer.tsx +117 -0
- package/src/bridge/BridgeAgent.ts +443 -0
- package/src/components/DecidoIcon.tsx +56 -0
- package/src/components/JsonTreeEditor.tsx +117 -0
- package/src/components/PanelSplitter.tsx +71 -0
- package/src/components/PluginErrorBoundary.tsx +69 -0
- package/src/components/SafeLiquidUI.tsx +114 -0
- package/src/components/TransientLayer.tsx +92 -0
- package/src/components/agent/AgentChat.tsx +134 -0
- package/src/components/chat-extensions/IntentCatalogPanel.tsx +81 -0
- package/src/components/chat-extensions/chatSlashCommands.ts +101 -0
- package/src/components/controls/CreatorInputBar.tsx +144 -0
- package/src/components/controls/OSToolbar.tsx +90 -0
- package/src/components/controls/TimelineTape.tsx +43 -0
- package/src/components/debug/ActionTimelineTab.tsx +111 -0
- package/src/components/debug/CSSInspectorTab.tsx +436 -0
- package/src/components/debug/ExportTab.tsx +192 -0
- package/src/components/debug/FlowHealthTab.tsx +86 -0
- package/src/components/debug/LogsTab.tsx +110 -0
- package/src/components/debug/MorphStackTab.tsx +241 -0
- package/src/components/debug/NetworkTab.tsx +173 -0
- package/src/components/debug/PerformanceTab.tsx +171 -0
- package/src/components/debug/ProfilesTab.tsx +238 -0
- package/src/components/debug/ReplayTab.tsx +70 -0
- package/src/components/debug/StoresTab.tsx +255 -0
- package/src/components/debug/TopologyTab.tsx +59 -0
- package/src/components/debug/debugConfig.tsx +66 -0
- package/src/components/playground/DebugPanel.tsx +112 -0
- package/src/components/playground/HeaderCenterControls.tsx +92 -0
- package/src/components/playground/KeyframeListItem.tsx +70 -0
- package/src/components/playground/PlaygroundAppSidebar.tsx +171 -0
- package/src/components/playground/PlaygroundBottomControls.tsx +132 -0
- package/src/components/playground/PlaygroundCanvas.tsx +87 -0
- package/src/components/playground/PlaygroundChat.tsx +236 -0
- package/src/components/playground/PlaygroundErrorBoundary.tsx +63 -0
- package/src/components/playground/PlaygroundFloatingInput.tsx +352 -0
- package/src/components/playground/PlaygroundHeader.tsx +222 -0
- package/src/components/playground/PlaygroundSidebar.tsx +136 -0
- package/src/components/playground/PlaygroundTerminal.tsx +44 -0
- package/src/components/playground/SuggestionCards.tsx +29 -0
- package/src/components/playground/demos/ClinicaAINode.tsx +221 -0
- package/src/components/playground/demos/FinanceAINode.tsx +226 -0
- package/src/components/playground/demos/KiaAcademyNode.tsx +250 -0
- package/src/components/playground/demos/KiaBotNode.tsx +207 -0
- package/src/components/playground/demos/KiaCampaignNode.tsx +191 -0
- package/src/components/playground/demos/KiaComplianceNode.tsx +140 -0
- package/src/components/playground/demos/KiaCustomerJourneyNode.tsx +220 -0
- package/src/components/playground/demos/KiaCyberNode.tsx +203 -0
- package/src/components/playground/demos/KiaDashboardNode.tsx +399 -0
- package/src/components/playground/demos/KiaEmbudoOverviewNode.tsx +168 -0
- package/src/components/playground/demos/KiaExecutiveNode.tsx +169 -0
- package/src/components/playground/demos/KiaGamificationNode.tsx +229 -0
- package/src/components/playground/demos/KiaIntelligenceHubNode.tsx +165 -0
- package/src/components/playground/demos/KiaInventoryNode.tsx +183 -0
- package/src/components/playground/demos/KiaLeadScoringNode.tsx +226 -0
- package/src/components/playground/demos/KiaLiveSimulationNode.tsx +177 -0
- package/src/components/playground/demos/KiaMultiDealerNode.tsx +223 -0
- package/src/components/playground/demos/KiaNPSVoiceNode.tsx +214 -0
- package/src/components/playground/demos/KiaOmnichannelNode.tsx +162 -0
- package/src/components/playground/demos/KiaPBIBudgetNode.tsx +152 -0
- package/src/components/playground/demos/KiaPBIConversionNode.tsx +206 -0
- package/src/components/playground/demos/KiaPBIFunnelNode.tsx +184 -0
- package/src/components/playground/demos/KiaPBIOwnershipNode.tsx +113 -0
- package/src/components/playground/demos/KiaPBIPartnerNode.tsx +143 -0
- package/src/components/playground/demos/KiaPBIPreciosNode.tsx +120 -0
- package/src/components/playground/demos/KiaPBIRuntNode.tsx +205 -0
- package/src/components/playground/demos/KiaPartnerScoreNode.tsx +206 -0
- package/src/components/playground/demos/KiaPredictiveNode.tsx +226 -0
- package/src/components/playground/demos/KiaShowroomNode.tsx +194 -0
- package/src/components/playground/demos/KiaStoreNode.tsx +215 -0
- package/src/components/playground/demos/KiaSustainabilityNode.tsx +173 -0
- package/src/components/playground/demos/KiaUsedVehiclesNode.tsx +163 -0
- package/src/components/playground/demos/KiaWorkshopNode.tsx +221 -0
- package/src/components/playground/demos/SmartCityNode.tsx +205 -0
- package/src/components/playground/demos/kia_campaign_manifest.json +112 -0
- package/src/components/playground/input-parts/AIModelSelector.tsx +156 -0
- package/src/components/playground/input-parts/InputActions.tsx +80 -0
- package/src/components/playground/input-parts/InputToolbar.tsx +245 -0
- package/src/components/playground/input-parts/ResourceLibraryPanel.tsx +287 -0
- package/src/components/playground/sidebarDsdIO.ts +82 -0
- package/src/components/settings/SettingsPanel.tsx +267 -0
- package/src/components/shell/AppHeader.tsx +9 -0
- package/src/components/shell/AppShell.tsx +139 -0
- package/src/components/shell/ArtifactBar.tsx +97 -0
- package/src/components/shell/BootScreen.tsx +19 -0
- package/src/components/shell/CenterComposite.tsx +87 -0
- package/src/components/shell/CodeEditorPanel.tsx +88 -0
- package/src/components/shell/GlobalOverlays.tsx +228 -0
- package/src/components/shell/LayoutConfigurator.tsx +209 -0
- package/src/components/shell/LayoutGrid.tsx +178 -0
- package/src/components/shell/MorphShell.tsx +368 -0
- package/src/components/shell/PluginViewer.tsx +147 -0
- package/src/components/shell/ShellNexusPreview.tsx +458 -0
- package/src/components/shell/SlotRenderer.tsx +115 -0
- package/src/components/shell/TabBar.tsx +94 -0
- package/src/components/shell/TemplateLibrary.tsx +195 -0
- package/src/components/shell/layoutConstants.ts +35 -0
- package/src/components/shell/morphStageMeta.ts +15 -0
- package/src/components/shell/shells/BuiltInShells.tsx +443 -0
- package/src/components/shell/shells/DatawayChatShell.tsx +42 -0
- package/src/components/shell/shells/TokenPreview.tsx +339 -0
- package/src/components/shell/shells/bootShells.ts +31 -0
- package/src/components/shells/CreatorShell.tsx +37 -0
- package/src/components/shells/DecidoShell.tsx +447 -0
- package/src/components/shells/ExperimentalChatShell.tsx +245 -0
- package/src/components/shells/UserCanvas.tsx +44 -0
- package/src/components/studio/BlueprintManagerPanel.tsx +137 -0
- package/src/components/studio/DependencyTreePanel.tsx +192 -0
- package/src/components/studio/NodePalette.tsx +92 -0
- package/src/components/studio/NodePropertiesPanel.tsx +81 -0
- package/src/components/studio/ReactFlowEditor.tsx +242 -0
- package/src/components/studio/TimelineEditor.tsx +122 -0
- package/src/components/studio/TimelineKeyframeCard.tsx +99 -0
- package/src/components/studio/VariablePanel.tsx +181 -0
- package/src/components/studio/blueprint/BlueprintCard.tsx +82 -0
- package/src/components/studio/editor/CanvasContextMenu.tsx +107 -0
- package/src/components/studio/editor/EditorToolbar.tsx +80 -0
- package/src/components/studio/editor/StageContentRenderer.tsx +134 -0
- package/src/components/studio/editor/TrackPropertyEditors.tsx +133 -0
- package/src/components/studio/editor/TreeNodeItem.tsx +91 -0
- package/src/components/studio/editor/edgeStyles.ts +43 -0
- package/src/components/studio/editor/editorKeyHandler.ts +95 -0
- package/src/components/studio/editor/nodeTypeRegistry.ts +137 -0
- package/src/components/studio/editor/paletteCatalog.tsx +84 -0
- package/src/components/studio/nodes/shell/InteractionNodes.tsx +82 -0
- package/src/components/studio/nodes/shell/LayoutControlNodes.tsx +69 -0
- package/src/components/studio/nodes/shell/RegisterActionNode.tsx +20 -0
- package/src/components/studio/nodes/shell/RegisterButtonNode.tsx +22 -0
- package/src/components/studio/nodes/shell/RegisterPanelNode.tsx +19 -0
- package/src/components/studio/nodes/shell/RegisterSidebarNode.tsx +19 -0
- package/src/components/studio/nodes/shell/RegisterStatusBarNode.tsx +22 -0
- package/src/components/studio/nodes/shell/RegisterTabNode.tsx +21 -0
- package/src/components/studio/nodes/shell/RegisterTopBarNode.tsx +22 -0
- package/src/components/studio/nodes/shell/ShellConfigNode.tsx +51 -0
- package/src/components/studio/nodes/shell/ShellNodeBase.tsx +100 -0
- package/src/components/studio/nodes/shell/ThemeNodes.tsx +51 -0
- package/src/components/studio/nodes/shell/index.ts +12 -0
- package/src/components/widgets/BroadcastWidget.tsx +93 -0
- package/src/components/widgets/MarketplaceWidget.tsx +298 -0
- package/src/components/widgets/McpToolsWidget.tsx +231 -0
- package/src/components/widgets/OpsDashboard.tsx +59 -0
- package/src/components/widgets/QuickActionsWidget.tsx +60 -0
- package/src/components/widgets/UsageWidget.tsx +112 -0
- package/src/components/widgets/WidgetRenderer.tsx +892 -0
- package/src/components/widgets/WidgetSlotPanel.tsx +213 -0
- package/src/config/IconRegistry.ts +126 -0
- package/src/contexts/NetworkProvider.tsx +162 -0
- package/src/core/AIDirector.ts +71 -0
- package/src/core/EventBus.ts +37 -0
- package/src/core/PluginContext.tsx +141 -0
- package/src/hooks/listeners/useUIStateListener.ts +59 -0
- package/src/hooks/listeners/useWhatsAppListener.ts +110 -0
- package/src/hooks/morphBridge.ts +82 -0
- package/src/hooks/useAIModelSelector.ts +144 -0
- package/src/hooks/useAgentStream.ts +220 -0
- package/src/hooks/useAutoUpdater.ts +89 -0
- package/src/hooks/useBootSequence.ts +20 -0
- package/src/hooks/useExportDSD.ts +53 -0
- package/src/hooks/useFullscreen.ts +35 -0
- package/src/hooks/useGeminiStream.ts +282 -0
- package/src/hooks/useIntentLens.ts +224 -0
- package/src/hooks/useKeyboardShortcuts.ts +69 -0
- package/src/hooks/useLoggerBridge.ts +32 -0
- package/src/hooks/useMcpClient.ts +112 -0
- package/src/hooks/useNexusaiDeploy.ts +118 -0
- package/src/hooks/usePlaybackEngine.ts +21 -0
- package/src/hooks/usePlaygroundCommander.ts +475 -0
- package/src/hooks/usePluginEngine.ts +165 -0
- package/src/hooks/useScreenRecorder.ts +73 -0
- package/src/hooks/useShellKeyboard.ts +40 -0
- package/src/hooks/useShellShortcuts.ts +118 -0
- package/src/hooks/useSoundEffects.ts +35 -0
- package/src/hooks/useStudioConfig.ts +72 -0
- package/src/hooks/useSystemBoot.ts +84 -0
- package/src/hooks/useSystemTelemetry.ts +62 -0
- package/src/index.ts +97 -0
- package/src/lib/debugLogger.ts +80 -0
- package/src/lib/networkInterceptor.ts +100 -0
- package/src/mocks/decido.tsx +41 -0
- package/src/plugins/pluginAPI.ts +190 -0
- package/src/store/McpStore.ts +69 -0
- package/src/store/UpdaterStore.ts +60 -0
- package/src/store/engine.ts +392 -0
- package/src/store/index.ts +4 -0
- package/src/store/layoutPresets.ts +66 -0
- package/src/store/playgroundTypes.ts +98 -0
- package/src/store/useActionTimelineStore.ts +48 -0
- package/src/store/useDebugPanelStore.ts +98 -0
- package/src/store/useDebugProfileStore.ts +130 -0
- package/src/store/useLayoutStore.ts +205 -0
- package/src/store/useMorphInstanceStore.ts +289 -0
- package/src/store/useMorphologyStore.ts +103 -0
- package/src/store/usePlaygroundStore.ts +236 -0
- package/src/store/useShellRegistry.ts +123 -0
- package/src/store/useSuggestionsStore.ts +57 -0
- package/src/store/useThemeStore.ts +399 -0
- package/src/store/useUIComponentStore.ts +179 -0
- package/src/types/DecidoStoryDefinition.ts +43 -0
- package/src/utils/ai/ai-architect.ts +92 -0
- package/src/utils/ai/ai-code.ts +187 -0
- package/src/utils/ai/ai-core.ts +50 -0
- package/src/utils/ai/ai-media.ts +292 -0
- package/src/utils/layoutGraph.ts +67 -0
- package/tsconfig.json +17 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { BaseNode } from '@decido/macia-core';
|
|
3
|
+
import {
|
|
4
|
+
Target,
|
|
5
|
+
Users,
|
|
6
|
+
Eye,
|
|
7
|
+
Car,
|
|
8
|
+
FileText,
|
|
9
|
+
CheckCircle2,
|
|
10
|
+
TrendingDown,
|
|
11
|
+
Activity,
|
|
12
|
+
Smartphone,
|
|
13
|
+
Globe,
|
|
14
|
+
MapPin,
|
|
15
|
+
HelpCircle,
|
|
16
|
+
} from 'lucide-react';
|
|
17
|
+
|
|
18
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
19
|
+
KIA EMBUDO OVERVIEW NODE
|
|
20
|
+
Funnel visual animado con datos reales de Grecco Motors
|
|
21
|
+
═══════════════════════════════════════════════════════════════ */
|
|
22
|
+
|
|
23
|
+
const FUNNEL_STAGES = [
|
|
24
|
+
{ key: 'oportunidades', label: 'Oportunidades', base: 437, icon: Users, color: '#6366f1' },
|
|
25
|
+
{ key: 'citas', label: 'Citas', base: 284, cumpl: 65, icon: Target, color: '#8b5cf6' },
|
|
26
|
+
{ key: 'showup', label: 'Show Up', base: 264, cumpl: 93, icon: Eye, color: '#3b82f6' },
|
|
27
|
+
{ key: 'testdrive', label: 'Test Drive', base: 79, cumpl: 129, icon: Car, color: '#0ea5e9' },
|
|
28
|
+
{ key: 'cotizacion', label: 'Cotización', base: 52, icon: FileText, color: '#22d3ee' },
|
|
29
|
+
{ key: 'pedidos', label: 'Pedidos', base: 15, icon: CheckCircle2, color: '#22c55e' },
|
|
30
|
+
{ key: 'entregas', label: 'Entregas / Matrículas', base: 30, icon: CheckCircle2, color: '#10b981' },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const CANALES = [
|
|
34
|
+
{ name: 'Redes Sociales', pct: 54.7, icon: Smartphone, color: '#6366f1' },
|
|
35
|
+
{ name: 'Walk-in', pct: 26.3, icon: MapPin, color: '#22c55e' },
|
|
36
|
+
{ name: 'Google Ads', pct: 12.0, icon: Globe, color: '#f59e0b' },
|
|
37
|
+
{ name: 'Otros', pct: 7.0, icon: HelpCircle, color: '#64748b' },
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const jitter = (base: number, range: number) =>
|
|
41
|
+
base + Math.round((Math.random() - 0.5) * range);
|
|
42
|
+
|
|
43
|
+
export const KiaEmbudoOverviewNode = (props: any) => {
|
|
44
|
+
const [tick, setTick] = useState(0);
|
|
45
|
+
const [animateIn, setAnimateIn] = useState(false);
|
|
46
|
+
|
|
47
|
+
/* Auto-refresh */
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
setAnimateIn(true);
|
|
50
|
+
const iv = setInterval(() => setTick(t => t + 1), 10000);
|
|
51
|
+
return () => clearInterval(iv);
|
|
52
|
+
}, []);
|
|
53
|
+
|
|
54
|
+
/* Animated values */
|
|
55
|
+
const stages = FUNNEL_STAGES.map(s => ({
|
|
56
|
+
...s,
|
|
57
|
+
value: jitter(s.base, Math.round(s.base * 0.05)),
|
|
58
|
+
}));
|
|
59
|
+
|
|
60
|
+
const maxVal = stages[0].value;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<BaseNode {...props} title="Embudo Comercial — Grecco Motors" width={520} height={600}>
|
|
64
|
+
<div className="flex flex-col h-full bg-slate-900 text-white p-4 gap-3 overflow-hidden">
|
|
65
|
+
|
|
66
|
+
{/* Header */}
|
|
67
|
+
<div className="flex justify-between items-center">
|
|
68
|
+
<div>
|
|
69
|
+
<h2 className="text-sm font-bold tracking-wide">EMBUDO DE CONVERSIÓN</h2>
|
|
70
|
+
<div className="flex items-center gap-2 mt-0.5">
|
|
71
|
+
<span className="text-[10px] text-slate-400">Febrero 2026 · Grecco Motors</span>
|
|
72
|
+
<span className="flex items-center gap-1 text-[10px] text-green-400 bg-green-500/10 px-1.5 rounded">
|
|
73
|
+
<Activity size={8} className="animate-pulse" /> LIVE
|
|
74
|
+
</span>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
<div className="flex items-center gap-2">
|
|
78
|
+
<TrendingDown size={14} className="text-slate-500" />
|
|
79
|
+
<span className="text-xs text-slate-400">Conversión: <span className="text-white font-bold">{((stages[5].value / stages[0].value) * 100).toFixed(1)}%</span></span>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{/* Funnel Visual */}
|
|
84
|
+
<div className="flex-1 flex flex-col gap-1.5 py-2" key={tick}>
|
|
85
|
+
{stages.map((stage, i) => {
|
|
86
|
+
const widthPct = Math.max(20, (stage.value / maxVal) * 100);
|
|
87
|
+
const conversion = i > 0 ? ((stage.value / stages[i - 1].value) * 100).toFixed(0) : null;
|
|
88
|
+
const Icon = stage.icon;
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<div key={stage.key} className="relative group">
|
|
92
|
+
{/* Conversion Arrow */}
|
|
93
|
+
{conversion && (
|
|
94
|
+
<div className="text-[9px] text-slate-600 text-center mb-0.5">
|
|
95
|
+
↓ {conversion}%
|
|
96
|
+
</div>
|
|
97
|
+
)}
|
|
98
|
+
|
|
99
|
+
{/* Bar */}
|
|
100
|
+
<div className="flex items-center gap-2">
|
|
101
|
+
<div className="w-6 flex-shrink-0 flex justify-center">
|
|
102
|
+
<Icon size={13} style={{ color: stage.color }} />
|
|
103
|
+
</div>
|
|
104
|
+
<div className="flex-1 relative">
|
|
105
|
+
<div
|
|
106
|
+
className="rounded-md flex items-center justify-between px-3 py-2 transition-all duration-1000 ease-out cursor-pointer hover:brightness-125"
|
|
107
|
+
style={{
|
|
108
|
+
width: `${widthPct}%`,
|
|
109
|
+
background: `linear-gradient(90deg, ${stage.color}dd, ${stage.color}88)`,
|
|
110
|
+
boxShadow: `0 0 12px ${stage.color}22`,
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
<span className="text-[11px] font-medium text-white truncate">{stage.label}</span>
|
|
114
|
+
<span className="text-sm font-bold text-white ml-2">{stage.value}</span>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
{stage.cumpl && (
|
|
118
|
+
<span className={`text-[10px] font-mono w-10 text-right flex-shrink-0 ${stage.cumpl >= 100 ? 'text-green-400' : 'text-yellow-400'}`}>
|
|
119
|
+
{stage.cumpl}%
|
|
120
|
+
</span>
|
|
121
|
+
)}
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
})}
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
{/* Canales de Origen */}
|
|
129
|
+
<div className="bg-slate-800 p-3 rounded-xl border border-slate-700">
|
|
130
|
+
<h3 className="text-[10px] uppercase text-slate-400 font-bold mb-2">Canales de Origen</h3>
|
|
131
|
+
<div className="flex gap-1">
|
|
132
|
+
{CANALES.map(c => (
|
|
133
|
+
<div
|
|
134
|
+
key={c.name}
|
|
135
|
+
className="rounded transition-all hover:brightness-125 cursor-pointer flex flex-col items-center justify-center py-2"
|
|
136
|
+
style={{
|
|
137
|
+
flex: c.pct,
|
|
138
|
+
background: `${c.color}22`,
|
|
139
|
+
borderLeft: `2px solid ${c.color}`,
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
142
|
+
<c.icon size={12} style={{ color: c.color }} />
|
|
143
|
+
<span className="text-[9px] font-bold mt-1" style={{ color: c.color }}>{c.pct}%</span>
|
|
144
|
+
<span className="text-[8px] text-slate-500 mt-0.5">{c.name}</span>
|
|
145
|
+
</div>
|
|
146
|
+
))}
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
{/* Footer KPIs */}
|
|
151
|
+
<div className="grid grid-cols-3 gap-2">
|
|
152
|
+
<div className="bg-slate-800 px-3 py-2 rounded-lg border border-slate-700 text-center">
|
|
153
|
+
<div className="text-lg font-bold text-green-400">95.3%</div>
|
|
154
|
+
<div className="text-[9px] text-slate-500">NPS Comercial</div>
|
|
155
|
+
</div>
|
|
156
|
+
<div className="bg-slate-800 px-3 py-2 rounded-lg border border-slate-700 text-center">
|
|
157
|
+
<div className="text-lg font-bold text-blue-400">13.3%</div>
|
|
158
|
+
<div className="text-[9px] text-slate-500">Market Share</div>
|
|
159
|
+
</div>
|
|
160
|
+
<div className="bg-slate-800 px-3 py-2 rounded-lg border border-slate-700 text-center">
|
|
161
|
+
<div className="text-lg font-bold text-yellow-400">S</div>
|
|
162
|
+
<div className="text-[9px] text-slate-500">Partner Prog</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
</BaseNode>
|
|
167
|
+
);
|
|
168
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { BaseNode } from '@decido/macia-core';
|
|
3
|
+
import {
|
|
4
|
+
PieChart, TrendingUp, DollarSign, Users, BarChart3,
|
|
5
|
+
Download, FileText, Calendar, ChevronUp, ChevronDown, Crown
|
|
6
|
+
} from 'lucide-react';
|
|
7
|
+
|
|
8
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
9
|
+
KIA EXECUTIVE NODE — Executive BI & Board Reports · Grecco
|
|
10
|
+
Board deck, sparklines, macro KPIs, scheduled reports
|
|
11
|
+
═══════════════════════════════════════════════════════════════ */
|
|
12
|
+
|
|
13
|
+
interface KPI {
|
|
14
|
+
label: string;
|
|
15
|
+
value: string;
|
|
16
|
+
prev: string;
|
|
17
|
+
trend: number;
|
|
18
|
+
unit: string;
|
|
19
|
+
sparkline: number[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const KPIS: KPI[] = [
|
|
23
|
+
{ label: 'RUNT Matriculas', value: '95', prev: '146', trend: -34.9, unit: 'uds', sparkline: [120, 110, 145, 130, 165, 182, 146, 95, 0, 0, 0, 0] },
|
|
24
|
+
{ label: 'Vehículos', value: '156', prev: '142', trend: 9.9, unit: 'unid', sparkline: [40, 45, 42, 48, 55, 50, 58, 60, 65, 62, 70, 72] },
|
|
25
|
+
{ label: 'NPS', value: '95.3', prev: '91.2', trend: 4.5, unit: 'pts', sparkline: [78, 80, 82, 81, 85, 87, 88, 90, 91, 93, 94, 95] },
|
|
26
|
+
{ label: 'Market Share', value: '13.3%', prev: '12.1%', trend: 9.9, unit: '%', sparkline: [8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13] },
|
|
27
|
+
{ label: 'Partner Score', value: '91', prev: '87', trend: 4.6, unit: 'pts', sparkline: [72, 74, 76, 78, 80, 82, 84, 86, 87, 88, 89, 91] },
|
|
28
|
+
{ label: 'Posventa', value: '128', prev: '115', trend: 11.3, unit: 'OTs', sparkline: [80, 85, 90, 88, 95, 98, 100, 105, 110, 115, 120, 128] },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const REPORTS = [
|
|
32
|
+
{ name: 'KIA Board Deck Q1', frequency: 'Trimestral', lastRun: 'Ene 31', pages: 24, format: 'PDF' },
|
|
33
|
+
{ name: 'Weekly Sales Report', frequency: 'Semanal', lastRun: 'Feb 14', pages: 8, format: 'PDF' },
|
|
34
|
+
{ name: 'Partner Program Update', frequency: 'Mensual', lastRun: 'Feb 1', pages: 12, format: 'PDF' },
|
|
35
|
+
{ name: 'Inventory Status', frequency: 'Diario', lastRun: 'Feb 17', pages: 4, format: 'Excel' },
|
|
36
|
+
{ name: 'CX Dashboard Export', frequency: 'Semanal', lastRun: 'Feb 14', pages: 6, format: 'PDF' },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const TOP_MODELS = [
|
|
40
|
+
{ model: 'Picanto', units: 46, revenue: '$2.8B', share: 48.4 },
|
|
41
|
+
{ model: 'Sportage', units: 12, revenue: '$1.2B', share: 12.6 },
|
|
42
|
+
{ model: 'K3 Cross', units: 10, revenue: '$580M', share: 10.5 },
|
|
43
|
+
{ model: 'Stonic', units: 8, revenue: '$440M', share: 8.4 },
|
|
44
|
+
{ model: 'Sonet', units: 7, revenue: '$350M', share: 7.4 },
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export const KiaExecutiveNode = (props: any) => {
|
|
48
|
+
const [tab, setTab] = useState<'kpis' | 'reports' | 'models'>('kpis');
|
|
49
|
+
|
|
50
|
+
// Sparkline renderer
|
|
51
|
+
const Spark = ({ data, color }: { data: number[]; color: string }) => {
|
|
52
|
+
const max = Math.max(...data);
|
|
53
|
+
const min = Math.min(...data);
|
|
54
|
+
const range = max - min || 1;
|
|
55
|
+
const w = 80;
|
|
56
|
+
const h = 20;
|
|
57
|
+
const points = data.map((v, i) => `${(i / (data.length - 1)) * w},${h - ((v - min) / range) * h}`).join(' ');
|
|
58
|
+
return (
|
|
59
|
+
<svg width={w} height={h} className="inline-block">
|
|
60
|
+
<polyline points={points} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
61
|
+
</svg>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<BaseNode {...props} title="Kia Executive BI" width={500} height={620}>
|
|
67
|
+
<div className="flex flex-col h-full bg-[#050810] text-white overflow-hidden">
|
|
68
|
+
|
|
69
|
+
{/* Header */}
|
|
70
|
+
<div className="flex items-center gap-3 p-3 bg-[#0a1020] border-b border-slate-800">
|
|
71
|
+
<div className="w-10 h-10 rounded-full bg-linear-to-br from-yellow-500/20 to-amber-600/20 flex items-center justify-center border border-yellow-500/20">
|
|
72
|
+
<Crown size={18} className="text-yellow-400" />
|
|
73
|
+
</div>
|
|
74
|
+
<div className="flex-1">
|
|
75
|
+
<div className="text-xs font-bold tracking-wide flex items-center gap-2">
|
|
76
|
+
EXECUTIVE BI
|
|
77
|
+
<span className="text-[8px] px-1.5 py-0.5 bg-yellow-500/20 text-yellow-400 rounded font-normal">BOARD LEVEL</span>
|
|
78
|
+
</div>
|
|
79
|
+
<div className="text-[10px] text-slate-400">Grecco Motors · Febrero 2026 · Reporting Suite</div>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{/* Tabs */}
|
|
84
|
+
<div className="flex gap-1 p-2 bg-[#080e1a] border-b border-slate-800">
|
|
85
|
+
{([
|
|
86
|
+
{ key: 'kpis' as const, label: '📊 KPIs Macro' },
|
|
87
|
+
{ key: 'reports' as const, label: '📄 Reportes' },
|
|
88
|
+
{ key: 'models' as const, label: '🚗 Top Modelos' },
|
|
89
|
+
]).map(t => (
|
|
90
|
+
<button key={t.key} onClick={() => setTab(t.key)}
|
|
91
|
+
className={`flex-1 py-1.5 rounded text-[9px] font-bold transition-all ${tab === t.key ? 'bg-yellow-600/20 text-yellow-400 border border-yellow-500/30' : 'text-slate-500'
|
|
92
|
+
}`}>
|
|
93
|
+
{t.label}
|
|
94
|
+
</button>
|
|
95
|
+
))}
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
{/* Content */}
|
|
99
|
+
<div className="flex-1 overflow-y-auto p-3 space-y-2">
|
|
100
|
+
|
|
101
|
+
{tab === 'kpis' && KPIS.map(k => (
|
|
102
|
+
<div key={k.label} className="bg-slate-900/50 rounded-lg p-3 border border-slate-800 flex items-center gap-3">
|
|
103
|
+
<div className="flex-1">
|
|
104
|
+
<div className="text-[9px] text-slate-500 uppercase font-bold">{k.label}</div>
|
|
105
|
+
<div className="flex items-baseline gap-2">
|
|
106
|
+
<span className="text-xl font-black">{k.value}</span>
|
|
107
|
+
<span className={`text-[10px] flex items-center gap-0.5 font-bold ${k.trend > 0 ? 'text-green-400' : 'text-red-400'}`}>
|
|
108
|
+
{k.trend > 0 ? <ChevronUp size={12} /> : <ChevronDown size={12} />}
|
|
109
|
+
{Math.abs(k.trend)}%
|
|
110
|
+
</span>
|
|
111
|
+
</div>
|
|
112
|
+
<div className="text-[8px] text-slate-500">Prev: {k.prev}</div>
|
|
113
|
+
</div>
|
|
114
|
+
<Spark data={k.sparkline} color={k.trend > 0 ? '#22c55e' : '#ef4444'} />
|
|
115
|
+
</div>
|
|
116
|
+
))}
|
|
117
|
+
|
|
118
|
+
{tab === 'reports' && (
|
|
119
|
+
<>
|
|
120
|
+
<div className="text-[9px] text-slate-500 font-bold uppercase mb-1">Reportes Programados</div>
|
|
121
|
+
{REPORTS.map(r => (
|
|
122
|
+
<div key={r.name} className="bg-slate-900/50 rounded-lg p-2.5 border border-slate-800 flex items-center justify-between">
|
|
123
|
+
<div>
|
|
124
|
+
<div className="text-[11px] font-bold">{r.name}</div>
|
|
125
|
+
<div className="text-[9px] text-slate-500 flex items-center gap-2">
|
|
126
|
+
<span className="flex items-center gap-0.5"><Calendar size={8} />{r.frequency}</span>
|
|
127
|
+
<span>{r.pages}p</span>
|
|
128
|
+
<span className="text-slate-600">Último: {r.lastRun}</span>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
<button className="flex items-center gap-1 px-2 py-1 bg-yellow-500/10 border border-yellow-500/20 rounded text-[9px] font-bold text-yellow-400 hover:bg-yellow-500/20 transition-all">
|
|
132
|
+
<Download size={9} /> {r.format}
|
|
133
|
+
</button>
|
|
134
|
+
</div>
|
|
135
|
+
))}
|
|
136
|
+
</>
|
|
137
|
+
)}
|
|
138
|
+
|
|
139
|
+
{tab === 'models' && (
|
|
140
|
+
<>
|
|
141
|
+
<div className="text-[9px] text-slate-500 font-bold uppercase mb-1">Ranking Ventas por Modelo — Feb 2026</div>
|
|
142
|
+
{TOP_MODELS.map((m, i) => (
|
|
143
|
+
<div key={m.model} className="bg-slate-900/50 rounded-lg p-2.5 border border-slate-800">
|
|
144
|
+
<div className="flex items-center justify-between mb-1">
|
|
145
|
+
<div className="flex items-center gap-2">
|
|
146
|
+
<span className={`text-[10px] font-black w-5 text-center ${i === 0 ? 'text-yellow-400' : i === 1 ? 'text-slate-300' : i === 2 ? 'text-orange-400' : 'text-slate-500'}`}>
|
|
147
|
+
#{i + 1}
|
|
148
|
+
</span>
|
|
149
|
+
<span className="text-[11px] font-bold">{m.model}</span>
|
|
150
|
+
</div>
|
|
151
|
+
<span className="text-sm font-bold text-blue-400">{m.units}</span>
|
|
152
|
+
</div>
|
|
153
|
+
<div className="flex items-center gap-2">
|
|
154
|
+
<div className="flex-1 h-2 bg-slate-800 rounded-full">
|
|
155
|
+
<div className="h-full rounded-full bg-linear-to-r from-yellow-500 to-amber-500 transition-all"
|
|
156
|
+
style={{ width: `${m.share * 3}%` }} />
|
|
157
|
+
</div>
|
|
158
|
+
<span className="text-[9px] text-yellow-400 font-bold">{m.share}%</span>
|
|
159
|
+
<span className="text-[9px] text-slate-500">{m.revenue}</span>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
))}
|
|
163
|
+
</>
|
|
164
|
+
)}
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
</BaseNode>
|
|
168
|
+
);
|
|
169
|
+
};
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
2
|
+
import { BaseNode } from '@decido/macia-core';
|
|
3
|
+
import {
|
|
4
|
+
Trophy, Gift, PartyPopper, User, Phone, Mail,
|
|
5
|
+
ArrowRight, RotateCcw, Users, Activity, BarChart3, Zap
|
|
6
|
+
} from 'lucide-react';
|
|
7
|
+
|
|
8
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
9
|
+
KIA GAMIFICATION NODE — Showroom Experience · Grecco Motors
|
|
10
|
+
Lucky Drive: Ruleta lead-capture + KPIs de conversion
|
|
11
|
+
═══════════════════════════════════════════════════════════════ */
|
|
12
|
+
|
|
13
|
+
const PRIZES = [
|
|
14
|
+
{ label: 'Mantenimiento Gratis', color: '#ef4444', value: '$850K' },
|
|
15
|
+
{ label: 'Bono $500k Accesorios', color: '#f59e0b', value: '$500K' },
|
|
16
|
+
{ label: 'Polarizado Nano-Cerámico', color: '#3b82f6', value: '$1.2M' },
|
|
17
|
+
{ label: 'Kit de Carretera Premium', color: '#22c55e', value: '$320K' },
|
|
18
|
+
{ label: '50% Dcto Alineación', color: '#a855f7', value: '$175K' },
|
|
19
|
+
{ label: 'Lavado Ecológico x3', color: '#06b6d4', value: '$90K' },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
export const KiaGamificationNode = (props: any) => {
|
|
23
|
+
const [step, setStep] = useState<'form' | 'game' | 'result'>('form');
|
|
24
|
+
const [lead, setLead] = useState({ name: '', phone: '', email: '', model: '' });
|
|
25
|
+
const [spinning, setSpinning] = useState(false);
|
|
26
|
+
const [prize, setPrize] = useState<(typeof PRIZES)[0] | null>(null);
|
|
27
|
+
const [totalLeads, setTotalLeads] = useState(347);
|
|
28
|
+
const [todayLeads, setTodayLeads] = useState(23);
|
|
29
|
+
const wheelRef = useRef<HTMLDivElement>(null);
|
|
30
|
+
|
|
31
|
+
/* Simulate growing leads */
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const iv = setInterval(() => {
|
|
34
|
+
if (Math.random() > 0.6) setTotalLeads(t => t + 1);
|
|
35
|
+
}, 12000);
|
|
36
|
+
return () => clearInterval(iv);
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
const handleSpin = () => {
|
|
40
|
+
if (spinning) return;
|
|
41
|
+
setSpinning(true);
|
|
42
|
+
|
|
43
|
+
const randomDeg = 720 + Math.floor(Math.random() * 360);
|
|
44
|
+
const selectedIdx = Math.floor(Math.random() * PRIZES.length);
|
|
45
|
+
|
|
46
|
+
if (wheelRef.current) {
|
|
47
|
+
wheelRef.current.style.transition = 'transform 3s cubic-bezier(0.2, 0.8, 0.2, 1)';
|
|
48
|
+
wheelRef.current.style.transform = `rotate(${randomDeg}deg)`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setTimeout(() => {
|
|
52
|
+
setPrize(PRIZES[selectedIdx]);
|
|
53
|
+
setStep('result');
|
|
54
|
+
setSpinning(false);
|
|
55
|
+
setTodayLeads(t => t + 1);
|
|
56
|
+
setTotalLeads(t => t + 1);
|
|
57
|
+
}, 3000);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const resetGame = () => {
|
|
61
|
+
setStep('form');
|
|
62
|
+
setPrize(null);
|
|
63
|
+
setLead({ name: '', phone: '', email: '', model: '' });
|
|
64
|
+
if (wheelRef.current) {
|
|
65
|
+
wheelRef.current.style.transition = 'none';
|
|
66
|
+
wheelRef.current.style.transform = 'rotate(0deg)';
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const segmentAngle = 360 / PRIZES.length;
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<BaseNode {...props} title="Kia Showroom Experience" width={420} height={640}>
|
|
74
|
+
<div className="flex flex-col h-full bg-linear-to-b from-black to-slate-900 text-white relative overflow-hidden">
|
|
75
|
+
|
|
76
|
+
{/* Animated bg */}
|
|
77
|
+
<div className="absolute top-0 left-0 w-full h-full opacity-10 pointer-events-none">
|
|
78
|
+
<div className="absolute top-[-20%] left-[-20%] w-[140%] h-[140%] bg-[radial-gradient(circle_at_center,_var(--tw-gradient-stops))] from-red-600 via-transparent to-transparent animate-pulse" />
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
{/* Header with Stats */}
|
|
82
|
+
<div className="flex items-center p-3 bg-black/40 z-10 border-b border-slate-800">
|
|
83
|
+
<div className="flex-1">
|
|
84
|
+
<h2 className="text-sm font-bold tracking-[0.15em] uppercase">Lucky Drive</h2>
|
|
85
|
+
<div className="text-[10px] text-slate-400">Grecco Motors · Lead Capture Gamificado</div>
|
|
86
|
+
</div>
|
|
87
|
+
<div className="flex gap-2">
|
|
88
|
+
<div className="bg-slate-800 px-2 py-1 rounded text-center border border-slate-700">
|
|
89
|
+
<div className="text-xs font-bold text-green-400">{todayLeads}</div>
|
|
90
|
+
<div className="text-[8px] text-slate-500">Hoy</div>
|
|
91
|
+
</div>
|
|
92
|
+
<div className="bg-slate-800 px-2 py-1 rounded text-center border border-slate-700">
|
|
93
|
+
<div className="text-xs font-bold text-blue-400">{totalLeads}</div>
|
|
94
|
+
<div className="text-[8px] text-slate-500">Total</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
{/* Content */}
|
|
100
|
+
<div className="flex-1 flex flex-col items-center justify-center p-5 z-10">
|
|
101
|
+
|
|
102
|
+
{step === 'form' && (
|
|
103
|
+
<div className="w-full space-y-3">
|
|
104
|
+
<div className="text-center mb-4">
|
|
105
|
+
<Trophy className="mx-auto text-yellow-400 mb-2" size={44} />
|
|
106
|
+
<h3 className="text-lg font-bold">¡Gana Premios para tu Kia!</h3>
|
|
107
|
+
<p className="text-xs text-slate-400">Regístrate y gira la ruleta.</p>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div className="space-y-2">
|
|
111
|
+
<InputField icon={User} placeholder="Tu Nombre" value={lead.name} onChange={(v: string) => setLead({ ...lead, name: v })} />
|
|
112
|
+
<InputField icon={Phone} placeholder="Celular" value={lead.phone} onChange={(v: string) => setLead({ ...lead, phone: v })} type="tel" />
|
|
113
|
+
<InputField icon={Mail} placeholder="Email" value={lead.email} onChange={(v: string) => setLead({ ...lead, email: v })} type="email" />
|
|
114
|
+
<select
|
|
115
|
+
className="w-full bg-slate-800 border border-slate-700 rounded-lg py-2.5 px-3 text-sm text-white focus:outline-none focus:border-red-500"
|
|
116
|
+
value={lead.model}
|
|
117
|
+
onChange={e => setLead({ ...lead, model: e.target.value })}
|
|
118
|
+
>
|
|
119
|
+
<option value="">¿Qué modelo te interesa?</option>
|
|
120
|
+
<option value="EV6">EV6</option>
|
|
121
|
+
<option value="Sportage">Sportage</option>
|
|
122
|
+
<option value="Seltos">Seltos</option>
|
|
123
|
+
<option value="K3 Cross">K3 Cross</option>
|
|
124
|
+
<option value="Picanto">Picanto</option>
|
|
125
|
+
<option value="Stonic">Stonic</option>
|
|
126
|
+
<option value="Sorento">Sorento</option>
|
|
127
|
+
</select>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<button
|
|
131
|
+
onClick={() => setStep('game')}
|
|
132
|
+
disabled={!lead.name || !lead.phone}
|
|
133
|
+
className="w-full bg-red-600 hover:bg-red-500 text-white font-bold py-3 rounded-lg flex items-center justify-center gap-2 mt-3 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
|
134
|
+
>
|
|
135
|
+
Jugar Ahora <ArrowRight size={16} />
|
|
136
|
+
</button>
|
|
137
|
+
<p className="text-[9px] text-center text-slate-600">*Aceptas términos, condiciones y política de datos.</p>
|
|
138
|
+
</div>
|
|
139
|
+
)}
|
|
140
|
+
|
|
141
|
+
{step === 'game' && (
|
|
142
|
+
<div className="flex flex-col items-center">
|
|
143
|
+
<div className="text-[10px] text-slate-400 mb-3">
|
|
144
|
+
¡Hola <span className="text-white font-bold">{lead.name.split(' ')[0]}</span>! Gira la ruleta 👇
|
|
145
|
+
</div>
|
|
146
|
+
<div className="relative w-56 h-56 mb-6">
|
|
147
|
+
<div className="absolute -top-3 left-1/2 -translate-x-1/2 z-20 text-red-500 text-xl filter drop-shadow-lg">▼</div>
|
|
148
|
+
<div
|
|
149
|
+
ref={wheelRef}
|
|
150
|
+
className="w-full h-full rounded-full border-4 border-slate-700 shadow-2xl relative overflow-hidden"
|
|
151
|
+
style={{
|
|
152
|
+
background: `conic-gradient(${PRIZES.map((p, i) => `${p.color} ${i * segmentAngle}deg ${(i + 1) * segmentAngle}deg`).join(', ')})`
|
|
153
|
+
}}
|
|
154
|
+
>
|
|
155
|
+
{PRIZES.map((p, i) => (
|
|
156
|
+
<div
|
|
157
|
+
key={i}
|
|
158
|
+
className="absolute w-full h-full text-[8px] font-bold text-white flex justify-center pt-3"
|
|
159
|
+
style={{ transform: `rotate(${i * segmentAngle + segmentAngle / 2}deg)` }}
|
|
160
|
+
>
|
|
161
|
+
<span className="bg-black/50 px-1 py-0.5 rounded backdrop-blur-sm max-w-[70px] text-center block" style={{ transform: 'translateY(16px)' }}>
|
|
162
|
+
{p.label.split(' ').slice(0, 2).join(' ')}
|
|
163
|
+
</span>
|
|
164
|
+
</div>
|
|
165
|
+
))}
|
|
166
|
+
</div>
|
|
167
|
+
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-12 h-12 bg-white rounded-full flex items-center justify-center shadow-lg z-10 border-4 border-slate-300">
|
|
168
|
+
<span className="text-red-600 font-bold text-[8px] tracking-widest">KIA</span>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
<button
|
|
172
|
+
onClick={handleSpin}
|
|
173
|
+
disabled={spinning}
|
|
174
|
+
className="px-8 py-3 bg-linear-to-r from-red-600 to-red-500 rounded-full text-white font-bold text-lg shadow-lg hover:shadow-red-500/20 hover:scale-105 active:scale-95 transition-all disabled:opacity-50"
|
|
175
|
+
>
|
|
176
|
+
{spinning ? '🎰 Girando...' : '¡GIRAR!'}
|
|
177
|
+
</button>
|
|
178
|
+
</div>
|
|
179
|
+
)}
|
|
180
|
+
|
|
181
|
+
{step === 'result' && prize && (
|
|
182
|
+
<div className="flex flex-col items-center text-center">
|
|
183
|
+
<div className="w-20 h-20 bg-yellow-400/20 rounded-full flex items-center justify-center mb-4 animate-bounce">
|
|
184
|
+
<Trophy className="text-yellow-400" size={40} />
|
|
185
|
+
</div>
|
|
186
|
+
<h3 className="text-xl font-bold mb-1">¡Felicidades {lead.name.split(' ')[0]}!</h3>
|
|
187
|
+
<p className="text-slate-400 text-sm mb-4">Ganaste:</p>
|
|
188
|
+
|
|
189
|
+
<div className="bg-slate-800 border p-5 rounded-xl w-full max-w-xs mb-4 shadow-[0_0_30px_rgba(220,38,38,0.2)]" style={{ borderColor: `${prize.color}66` }}>
|
|
190
|
+
<Gift className="mx-auto mb-2" size={28} style={{ color: prize.color }} />
|
|
191
|
+
<div className="text-lg font-bold text-white">{prize.label}</div>
|
|
192
|
+
<div className="text-xs mt-1" style={{ color: prize.color }}>Valor: {prize.value}</div>
|
|
193
|
+
<div className="text-[10px] text-slate-500 mt-2">Código: KIA-GRC-{Math.floor(Math.random() * 10000)}</div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div className="bg-green-500/10 border border-green-500/20 rounded-lg p-2 text-[10px] text-green-300 w-full mb-4">
|
|
197
|
+
✅ Lead registrado en CRM · Asesor asignado automáticamente
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<button onClick={resetGame} className="flex items-center gap-2 text-slate-400 hover:text-white transition-colors text-sm">
|
|
201
|
+
<RotateCcw size={14} /> Siguiente Cliente
|
|
202
|
+
</button>
|
|
203
|
+
</div>
|
|
204
|
+
)}
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
{/* Bottom Stats */}
|
|
208
|
+
<div className="flex items-center justify-between text-[10px] text-slate-500 p-2 border-t border-slate-800 z-10">
|
|
209
|
+
<span>Conv. Rate: <span className="text-green-400 font-bold">34.2%</span></span>
|
|
210
|
+
<span>Avg Ticket: <span className="text-blue-400 font-bold">$420K</span></span>
|
|
211
|
+
<span className="flex items-center gap-1"><Activity size={8} className="text-green-400 animate-pulse" /> Live</span>
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
</BaseNode>
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const InputField = ({ icon: Icon, placeholder, value, onChange, type = 'text' }: any) => (
|
|
219
|
+
<div className="relative">
|
|
220
|
+
<Icon className="absolute left-3 top-3 text-slate-500" size={14} />
|
|
221
|
+
<input
|
|
222
|
+
type={type}
|
|
223
|
+
placeholder={placeholder}
|
|
224
|
+
className="w-full bg-slate-800 border border-slate-700 rounded-lg py-2.5 pl-9 text-sm focus:outline-none focus:border-red-500 transition-colors"
|
|
225
|
+
value={value}
|
|
226
|
+
onChange={e => onChange(e.target.value)}
|
|
227
|
+
/>
|
|
228
|
+
</div>
|
|
229
|
+
);
|