@decido/shell 1.0.0 → 4.0.2
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/README.md +31 -0
- package/package.json +27 -18
- package/.turbo/turbo-build.log +0 -13
- package/src/AgentPlayer.tsx +0 -105
- package/src/DecidoPlayer.tsx +0 -117
- package/src/bridge/BridgeAgent.ts +0 -443
- package/src/components/DecidoIcon.tsx +0 -56
- package/src/components/JsonTreeEditor.tsx +0 -117
- package/src/components/PanelSplitter.tsx +0 -71
- package/src/components/PluginErrorBoundary.tsx +0 -69
- package/src/components/SafeLiquidUI.tsx +0 -114
- package/src/components/TransientLayer.tsx +0 -92
- package/src/components/agent/AgentChat.tsx +0 -134
- package/src/components/chat-extensions/IntentCatalogPanel.tsx +0 -81
- package/src/components/chat-extensions/chatSlashCommands.ts +0 -101
- package/src/components/controls/CreatorInputBar.tsx +0 -144
- package/src/components/controls/OSToolbar.tsx +0 -90
- package/src/components/controls/TimelineTape.tsx +0 -43
- package/src/components/debug/ActionTimelineTab.tsx +0 -111
- package/src/components/debug/CSSInspectorTab.tsx +0 -436
- package/src/components/debug/ExportTab.tsx +0 -192
- package/src/components/debug/FlowHealthTab.tsx +0 -86
- package/src/components/debug/LogsTab.tsx +0 -110
- package/src/components/debug/MorphStackTab.tsx +0 -241
- package/src/components/debug/NetworkTab.tsx +0 -173
- package/src/components/debug/PerformanceTab.tsx +0 -171
- package/src/components/debug/ProfilesTab.tsx +0 -238
- package/src/components/debug/ReplayTab.tsx +0 -70
- package/src/components/debug/StoresTab.tsx +0 -255
- package/src/components/debug/TopologyTab.tsx +0 -59
- package/src/components/debug/debugConfig.tsx +0 -66
- package/src/components/playground/DebugPanel.tsx +0 -112
- package/src/components/playground/HeaderCenterControls.tsx +0 -92
- package/src/components/playground/KeyframeListItem.tsx +0 -70
- package/src/components/playground/PlaygroundAppSidebar.tsx +0 -171
- package/src/components/playground/PlaygroundBottomControls.tsx +0 -132
- package/src/components/playground/PlaygroundCanvas.tsx +0 -87
- package/src/components/playground/PlaygroundChat.tsx +0 -236
- package/src/components/playground/PlaygroundErrorBoundary.tsx +0 -63
- package/src/components/playground/PlaygroundFloatingInput.tsx +0 -352
- package/src/components/playground/PlaygroundHeader.tsx +0 -222
- package/src/components/playground/PlaygroundSidebar.tsx +0 -136
- package/src/components/playground/PlaygroundTerminal.tsx +0 -44
- package/src/components/playground/SuggestionCards.tsx +0 -29
- package/src/components/playground/demos/ClinicaAINode.tsx +0 -221
- package/src/components/playground/demos/FinanceAINode.tsx +0 -226
- package/src/components/playground/demos/KiaAcademyNode.tsx +0 -250
- package/src/components/playground/demos/KiaBotNode.tsx +0 -207
- package/src/components/playground/demos/KiaCampaignNode.tsx +0 -191
- package/src/components/playground/demos/KiaComplianceNode.tsx +0 -140
- package/src/components/playground/demos/KiaCustomerJourneyNode.tsx +0 -220
- package/src/components/playground/demos/KiaCyberNode.tsx +0 -203
- package/src/components/playground/demos/KiaDashboardNode.tsx +0 -399
- package/src/components/playground/demos/KiaEmbudoOverviewNode.tsx +0 -168
- package/src/components/playground/demos/KiaExecutiveNode.tsx +0 -169
- package/src/components/playground/demos/KiaGamificationNode.tsx +0 -229
- package/src/components/playground/demos/KiaIntelligenceHubNode.tsx +0 -165
- package/src/components/playground/demos/KiaInventoryNode.tsx +0 -183
- package/src/components/playground/demos/KiaLeadScoringNode.tsx +0 -226
- package/src/components/playground/demos/KiaLiveSimulationNode.tsx +0 -177
- package/src/components/playground/demos/KiaMultiDealerNode.tsx +0 -223
- package/src/components/playground/demos/KiaNPSVoiceNode.tsx +0 -214
- package/src/components/playground/demos/KiaOmnichannelNode.tsx +0 -162
- package/src/components/playground/demos/KiaPBIBudgetNode.tsx +0 -152
- package/src/components/playground/demos/KiaPBIConversionNode.tsx +0 -206
- package/src/components/playground/demos/KiaPBIFunnelNode.tsx +0 -184
- package/src/components/playground/demos/KiaPBIOwnershipNode.tsx +0 -113
- package/src/components/playground/demos/KiaPBIPartnerNode.tsx +0 -143
- package/src/components/playground/demos/KiaPBIPreciosNode.tsx +0 -120
- package/src/components/playground/demos/KiaPBIRuntNode.tsx +0 -205
- package/src/components/playground/demos/KiaPartnerScoreNode.tsx +0 -206
- package/src/components/playground/demos/KiaPredictiveNode.tsx +0 -226
- package/src/components/playground/demos/KiaShowroomNode.tsx +0 -194
- package/src/components/playground/demos/KiaStoreNode.tsx +0 -215
- package/src/components/playground/demos/KiaSustainabilityNode.tsx +0 -173
- package/src/components/playground/demos/KiaUsedVehiclesNode.tsx +0 -163
- package/src/components/playground/demos/KiaWorkshopNode.tsx +0 -221
- package/src/components/playground/demos/SmartCityNode.tsx +0 -205
- package/src/components/playground/demos/kia_campaign_manifest.json +0 -112
- package/src/components/playground/input-parts/AIModelSelector.tsx +0 -156
- package/src/components/playground/input-parts/InputActions.tsx +0 -80
- package/src/components/playground/input-parts/InputToolbar.tsx +0 -245
- package/src/components/playground/input-parts/ResourceLibraryPanel.tsx +0 -287
- package/src/components/playground/sidebarDsdIO.ts +0 -82
- package/src/components/settings/SettingsPanel.tsx +0 -267
- package/src/components/shell/AppHeader.tsx +0 -9
- package/src/components/shell/AppShell.tsx +0 -139
- package/src/components/shell/ArtifactBar.tsx +0 -97
- package/src/components/shell/BootScreen.tsx +0 -19
- package/src/components/shell/CenterComposite.tsx +0 -87
- package/src/components/shell/CodeEditorPanel.tsx +0 -88
- package/src/components/shell/GlobalOverlays.tsx +0 -228
- package/src/components/shell/LayoutConfigurator.tsx +0 -209
- package/src/components/shell/LayoutGrid.tsx +0 -178
- package/src/components/shell/MorphShell.tsx +0 -368
- package/src/components/shell/PluginViewer.tsx +0 -147
- package/src/components/shell/ShellNexusPreview.tsx +0 -458
- package/src/components/shell/SlotRenderer.tsx +0 -115
- package/src/components/shell/TabBar.tsx +0 -94
- package/src/components/shell/TemplateLibrary.tsx +0 -195
- package/src/components/shell/layoutConstants.ts +0 -35
- package/src/components/shell/morphStageMeta.ts +0 -15
- package/src/components/shell/shells/BuiltInShells.tsx +0 -443
- package/src/components/shell/shells/DatawayChatShell.tsx +0 -42
- package/src/components/shell/shells/TokenPreview.tsx +0 -339
- package/src/components/shell/shells/bootShells.ts +0 -31
- package/src/components/shells/CreatorShell.tsx +0 -37
- package/src/components/shells/DecidoShell.tsx +0 -447
- package/src/components/shells/ExperimentalChatShell.tsx +0 -245
- package/src/components/shells/UserCanvas.tsx +0 -44
- package/src/components/studio/BlueprintManagerPanel.tsx +0 -137
- package/src/components/studio/DependencyTreePanel.tsx +0 -192
- package/src/components/studio/NodePalette.tsx +0 -92
- package/src/components/studio/NodePropertiesPanel.tsx +0 -81
- package/src/components/studio/ReactFlowEditor.tsx +0 -242
- package/src/components/studio/TimelineEditor.tsx +0 -122
- package/src/components/studio/TimelineKeyframeCard.tsx +0 -99
- package/src/components/studio/VariablePanel.tsx +0 -181
- package/src/components/studio/blueprint/BlueprintCard.tsx +0 -82
- package/src/components/studio/editor/CanvasContextMenu.tsx +0 -107
- package/src/components/studio/editor/EditorToolbar.tsx +0 -80
- package/src/components/studio/editor/StageContentRenderer.tsx +0 -134
- package/src/components/studio/editor/TrackPropertyEditors.tsx +0 -133
- package/src/components/studio/editor/TreeNodeItem.tsx +0 -91
- package/src/components/studio/editor/edgeStyles.ts +0 -43
- package/src/components/studio/editor/editorKeyHandler.ts +0 -95
- package/src/components/studio/editor/nodeTypeRegistry.ts +0 -137
- package/src/components/studio/editor/paletteCatalog.tsx +0 -84
- package/src/components/studio/nodes/shell/InteractionNodes.tsx +0 -82
- package/src/components/studio/nodes/shell/LayoutControlNodes.tsx +0 -69
- package/src/components/studio/nodes/shell/RegisterActionNode.tsx +0 -20
- package/src/components/studio/nodes/shell/RegisterButtonNode.tsx +0 -22
- package/src/components/studio/nodes/shell/RegisterPanelNode.tsx +0 -19
- package/src/components/studio/nodes/shell/RegisterSidebarNode.tsx +0 -19
- package/src/components/studio/nodes/shell/RegisterStatusBarNode.tsx +0 -22
- package/src/components/studio/nodes/shell/RegisterTabNode.tsx +0 -21
- package/src/components/studio/nodes/shell/RegisterTopBarNode.tsx +0 -22
- package/src/components/studio/nodes/shell/ShellConfigNode.tsx +0 -51
- package/src/components/studio/nodes/shell/ShellNodeBase.tsx +0 -100
- package/src/components/studio/nodes/shell/ThemeNodes.tsx +0 -51
- package/src/components/studio/nodes/shell/index.ts +0 -12
- package/src/components/widgets/BroadcastWidget.tsx +0 -93
- package/src/components/widgets/MarketplaceWidget.tsx +0 -298
- package/src/components/widgets/McpToolsWidget.tsx +0 -231
- package/src/components/widgets/OpsDashboard.tsx +0 -59
- package/src/components/widgets/QuickActionsWidget.tsx +0 -60
- package/src/components/widgets/UsageWidget.tsx +0 -112
- package/src/components/widgets/WidgetRenderer.tsx +0 -892
- package/src/components/widgets/WidgetSlotPanel.tsx +0 -213
- package/src/config/IconRegistry.ts +0 -126
- package/src/contexts/NetworkProvider.tsx +0 -162
- package/src/core/AIDirector.ts +0 -71
- package/src/core/EventBus.ts +0 -37
- package/src/core/PluginContext.tsx +0 -141
- package/src/hooks/listeners/useUIStateListener.ts +0 -59
- package/src/hooks/listeners/useWhatsAppListener.ts +0 -110
- package/src/hooks/morphBridge.ts +0 -82
- package/src/hooks/useAIModelSelector.ts +0 -144
- package/src/hooks/useAgentStream.ts +0 -220
- package/src/hooks/useAutoUpdater.ts +0 -89
- package/src/hooks/useBootSequence.ts +0 -20
- package/src/hooks/useExportDSD.ts +0 -53
- package/src/hooks/useFullscreen.ts +0 -35
- package/src/hooks/useGeminiStream.ts +0 -282
- package/src/hooks/useIntentLens.ts +0 -224
- package/src/hooks/useKeyboardShortcuts.ts +0 -69
- package/src/hooks/useLoggerBridge.ts +0 -32
- package/src/hooks/useMcpClient.ts +0 -112
- package/src/hooks/useNexusaiDeploy.ts +0 -118
- package/src/hooks/usePlaybackEngine.ts +0 -21
- package/src/hooks/usePlaygroundCommander.ts +0 -475
- package/src/hooks/usePluginEngine.ts +0 -165
- package/src/hooks/useScreenRecorder.ts +0 -73
- package/src/hooks/useShellKeyboard.ts +0 -40
- package/src/hooks/useShellShortcuts.ts +0 -118
- package/src/hooks/useSoundEffects.ts +0 -35
- package/src/hooks/useStudioConfig.ts +0 -72
- package/src/hooks/useSystemBoot.ts +0 -84
- package/src/hooks/useSystemTelemetry.ts +0 -62
- package/src/index.ts +0 -97
- package/src/lib/debugLogger.ts +0 -80
- package/src/lib/networkInterceptor.ts +0 -100
- package/src/mocks/decido.tsx +0 -41
- package/src/plugins/pluginAPI.ts +0 -190
- package/src/store/McpStore.ts +0 -69
- package/src/store/UpdaterStore.ts +0 -60
- package/src/store/engine.ts +0 -392
- package/src/store/index.ts +0 -4
- package/src/store/layoutPresets.ts +0 -66
- package/src/store/playgroundTypes.ts +0 -98
- package/src/store/useActionTimelineStore.ts +0 -48
- package/src/store/useDebugPanelStore.ts +0 -98
- package/src/store/useDebugProfileStore.ts +0 -130
- package/src/store/useLayoutStore.ts +0 -205
- package/src/store/useMorphInstanceStore.ts +0 -289
- package/src/store/useMorphologyStore.ts +0 -103
- package/src/store/usePlaygroundStore.ts +0 -236
- package/src/store/useShellRegistry.ts +0 -123
- package/src/store/useSuggestionsStore.ts +0 -57
- package/src/store/useThemeStore.ts +0 -399
- package/src/store/useUIComponentStore.ts +0 -179
- package/src/types/DecidoStoryDefinition.ts +0 -43
- package/src/utils/ai/ai-architect.ts +0 -92
- package/src/utils/ai/ai-code.ts +0 -187
- package/src/utils/ai/ai-core.ts +0 -50
- package/src/utils/ai/ai-media.ts +0 -292
- package/src/utils/layoutGraph.ts +0 -67
- package/tsconfig.json +0 -17
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { BaseNode } from '@decido/macia-core';
|
|
3
|
-
import {
|
|
4
|
-
Car, Palette, Calendar, Scale, ChevronRight,
|
|
5
|
-
Star, Fuel, Gauge, Zap, Check, ArrowLeftRight
|
|
6
|
-
} from 'lucide-react';
|
|
7
|
-
|
|
8
|
-
/* ═══════════════════════════════════════════════════════════════
|
|
9
|
-
KIA SHOWROOM DIGITAL NODE — Configurador · Grecco Motors
|
|
10
|
-
Catálogo, configurador modelo+color+paquete, comparador, agenda
|
|
11
|
-
═══════════════════════════════════════════════════════════════ */
|
|
12
|
-
|
|
13
|
-
interface Model {
|
|
14
|
-
name: string;
|
|
15
|
-
price: number;
|
|
16
|
-
type: 'ICE' | 'HEV' | 'EV';
|
|
17
|
-
hp: number;
|
|
18
|
-
kmpl: number;
|
|
19
|
-
colors: { name: string; hex: string }[];
|
|
20
|
-
packages: { name: string; price: number }[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const MODELS: Model[] = [
|
|
24
|
-
{ name: 'Sportage HEV', price: 159900000, type: 'HEV', hp: 230, kmpl: 18.2, colors: [{ name: 'Snow White', hex: '#f1f0eb' }, { name: 'Steel Grey', hex: '#71717a' }, { name: 'Black Cherry', hex: '#4a0e1b' }], packages: [{ name: 'Comfort', price: 0 }, { name: 'Premium', price: 8500000 }, { name: 'GT-Line', price: 14200000 }] },
|
|
25
|
-
{ name: 'Seltos', price: 109900000, type: 'ICE', hp: 160, kmpl: 14.5, colors: [{ name: 'Gravity Grey', hex: '#52525b' }, { name: 'Orange Fusion', hex: '#ea580c' }, { name: 'White Pearl', hex: '#f5f5f4' }], packages: [{ name: 'Zenith', price: 0 }, { name: 'Premium', price: 6200000 }] },
|
|
26
|
-
{ name: 'EV6 GT', price: 289900000, type: 'EV', hp: 585, kmpl: 0, colors: [{ name: 'Moonscape', hex: '#a8a29e' }, { name: 'Yacht Blue', hex: '#1e40af' }, { name: 'Snow White', hex: '#f1f0eb' }], packages: [{ name: 'Wind', price: 0 }, { name: 'GT-Line', price: 12000000 }, { name: 'GT', price: 28000000 }] },
|
|
27
|
-
{ name: 'Picanto', price: 59900000, type: 'ICE', hp: 84, kmpl: 19.8, colors: [{ name: 'Signal Red', hex: '#dc2626' }, { name: 'Lime Green', hex: '#65a30d' }, { name: 'Alice Blue', hex: '#60a5fa' }], packages: [{ name: 'Emotion', price: 0 }, { name: 'Emotion+', price: 3500000 }] },
|
|
28
|
-
{ name: 'EV9', price: 359900000, type: 'EV', hp: 384, kmpl: 0, colors: [{ name: 'Ocean Blue', hex: '#1d4ed8' }, { name: 'Pebble Grey', hex: '#a1a1aa' }, { name: 'Aurora Black', hex: '#18181b' }], packages: [{ name: 'Earth', price: 0 }, { name: 'GT-Line', price: 18000000 }] },
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
const fmtPrice = (n: number) => `$${(n / 1000000).toFixed(0)}M`;
|
|
32
|
-
|
|
33
|
-
const SLOTS = ['9:00 AM', '10:30 AM', '12:00 PM', '2:00 PM', '3:30 PM', '5:00 PM'];
|
|
34
|
-
|
|
35
|
-
export const KiaShowroomNode = (props: any) => {
|
|
36
|
-
const [tab, setTab] = useState<'config' | 'compare' | 'agenda'>('config');
|
|
37
|
-
const [selected, setSelected] = useState(0);
|
|
38
|
-
const [colorIdx, setColorIdx] = useState(0);
|
|
39
|
-
const [pkgIdx, setPkgIdx] = useState(0);
|
|
40
|
-
const [compareIdx, setCompareIdx] = useState(2);
|
|
41
|
-
|
|
42
|
-
const model = MODELS[selected];
|
|
43
|
-
const totalPrice = model.price + model.packages[pkgIdx].price;
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<BaseNode {...props} title="Kia Showroom Digital" width={500} height={620}>
|
|
47
|
-
<div className="flex flex-col h-full bg-slate-950 text-white overflow-hidden">
|
|
48
|
-
|
|
49
|
-
{/* Header */}
|
|
50
|
-
<div className="flex items-center gap-3 p-3 bg-slate-900 border-b border-slate-800">
|
|
51
|
-
<div className="w-9 h-9 rounded-full bg-indigo-600/20 flex items-center justify-center border border-indigo-500/30">
|
|
52
|
-
<Car size={16} className="text-indigo-400" />
|
|
53
|
-
</div>
|
|
54
|
-
<div className="flex-1">
|
|
55
|
-
<div className="text-xs font-bold tracking-wide">SHOWROOM DIGITAL</div>
|
|
56
|
-
<div className="text-[10px] text-slate-400">Grecco Motors · {MODELS.length} modelos · Configurador 360°</div>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
|
|
60
|
-
{/* Tabs */}
|
|
61
|
-
<div className="flex gap-1 p-2 bg-slate-900/50 border-b border-slate-800">
|
|
62
|
-
{([
|
|
63
|
-
{ key: 'config' as const, label: '🎨 Configurador' },
|
|
64
|
-
{ key: 'compare' as const, label: '⚖️ Comparar' },
|
|
65
|
-
{ key: 'agenda' as const, label: '📅 Test Drive' },
|
|
66
|
-
]).map(t => (
|
|
67
|
-
<button key={t.key} onClick={() => setTab(t.key)}
|
|
68
|
-
className={`flex-1 py-1.5 rounded text-[9px] font-bold transition-all ${tab === t.key ? 'bg-indigo-600/20 text-indigo-400 border border-indigo-500/30' : 'text-slate-500'
|
|
69
|
-
}`}>
|
|
70
|
-
{t.label}
|
|
71
|
-
</button>
|
|
72
|
-
))}
|
|
73
|
-
</div>
|
|
74
|
-
|
|
75
|
-
{/* Content */}
|
|
76
|
-
<div className="flex-1 overflow-y-auto p-3 space-y-2">
|
|
77
|
-
|
|
78
|
-
{tab === 'config' && (
|
|
79
|
-
<>
|
|
80
|
-
{/* Model selector */}
|
|
81
|
-
<div className="flex gap-1 flex-wrap">
|
|
82
|
-
{MODELS.map((m, i) => (
|
|
83
|
-
<button key={m.name} onClick={() => { setSelected(i); setColorIdx(0); setPkgIdx(0); }}
|
|
84
|
-
className={`px-2 py-1 rounded text-[9px] font-bold transition-all ${i === selected ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-500'
|
|
85
|
-
}`}>{m.name}</button>
|
|
86
|
-
))}
|
|
87
|
-
</div>
|
|
88
|
-
|
|
89
|
-
{/* Color preview */}
|
|
90
|
-
<div className="bg-slate-900/50 rounded-lg p-3 border border-slate-800">
|
|
91
|
-
<div className="h-24 rounded-lg flex items-center justify-center mb-2"
|
|
92
|
-
style={{ background: `linear-gradient(135deg, ${model.colors[colorIdx].hex}44 0%, ${model.colors[colorIdx].hex}22 100%)`, border: `1px solid ${model.colors[colorIdx].hex}44` }}>
|
|
93
|
-
<Car size={48} style={{ color: model.colors[colorIdx].hex }} />
|
|
94
|
-
</div>
|
|
95
|
-
<div className="flex gap-2 justify-center">
|
|
96
|
-
{model.colors.map((c, i) => (
|
|
97
|
-
<button key={c.name} onClick={() => setColorIdx(i)}
|
|
98
|
-
className={`w-6 h-6 rounded-full border-2 transition-all ${i === colorIdx ? 'border-white scale-110' : 'border-slate-700'}`}
|
|
99
|
-
style={{ background: c.hex }} title={c.name} />
|
|
100
|
-
))}
|
|
101
|
-
</div>
|
|
102
|
-
<div className="text-[9px] text-center text-slate-400 mt-1">{model.colors[colorIdx].name}</div>
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
|
-
{/* Specs */}
|
|
106
|
-
<div className="flex gap-2">
|
|
107
|
-
<div className="flex-1 bg-slate-900/50 rounded p-2 border border-slate-800 text-center">
|
|
108
|
-
<div className="text-sm font-bold text-blue-400">{model.hp} HP</div>
|
|
109
|
-
<div className="text-[8px] text-slate-500">Potencia</div>
|
|
110
|
-
</div>
|
|
111
|
-
<div className="flex-1 bg-slate-900/50 rounded p-2 border border-slate-800 text-center">
|
|
112
|
-
<div className="text-sm font-bold text-green-400">{model.type === 'EV' ? '500+ km' : `${model.kmpl} km/l`}</div>
|
|
113
|
-
<div className="text-[8px] text-slate-500">{model.type === 'EV' ? 'Autonomía' : 'Rendimiento'}</div>
|
|
114
|
-
</div>
|
|
115
|
-
<div className="flex-1 bg-slate-900/50 rounded p-2 border border-slate-800 text-center">
|
|
116
|
-
<div className={`text-sm font-bold ${model.type === 'EV' ? 'text-green-400' : model.type === 'HEV' ? 'text-cyan-400' : 'text-slate-400'}`}>{model.type}</div>
|
|
117
|
-
<div className="text-[8px] text-slate-500">Motor</div>
|
|
118
|
-
</div>
|
|
119
|
-
</div>
|
|
120
|
-
|
|
121
|
-
{/* Package */}
|
|
122
|
-
<div className="bg-slate-900/50 rounded-lg p-2 border border-slate-800">
|
|
123
|
-
<div className="text-[9px] text-slate-500 font-bold uppercase mb-1">Paquete</div>
|
|
124
|
-
<div className="flex gap-1">
|
|
125
|
-
{model.packages.map((p, i) => (
|
|
126
|
-
<button key={p.name} onClick={() => setPkgIdx(i)}
|
|
127
|
-
className={`flex-1 py-1.5 rounded text-[9px] font-bold ${i === pkgIdx ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-500'
|
|
128
|
-
}`}>{p.name} {p.price > 0 ? `+${fmtPrice(p.price)}` : ''}</button>
|
|
129
|
-
))}
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
|
|
133
|
-
{/* Total */}
|
|
134
|
-
<div className="bg-indigo-500/10 rounded-lg p-3 border border-indigo-500/20 text-center">
|
|
135
|
-
<div className="text-[9px] text-slate-400">PRECIO TOTAL</div>
|
|
136
|
-
<div className="text-xl font-black text-indigo-400">{fmtPrice(totalPrice)}</div>
|
|
137
|
-
<div className="text-[9px] text-slate-500">{model.name} · {model.colors[colorIdx].name} · {model.packages[pkgIdx].name}</div>
|
|
138
|
-
</div>
|
|
139
|
-
</>
|
|
140
|
-
)}
|
|
141
|
-
|
|
142
|
-
{tab === 'compare' && (
|
|
143
|
-
<>
|
|
144
|
-
<div className="flex gap-1 mb-2">
|
|
145
|
-
{MODELS.map((m, i) => i !== selected && (
|
|
146
|
-
<button key={m.name} onClick={() => setCompareIdx(i)}
|
|
147
|
-
className={`px-2 py-1 rounded text-[9px] font-bold ${i === compareIdx ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-500'}`}>{m.name}</button>
|
|
148
|
-
))}
|
|
149
|
-
</div>
|
|
150
|
-
<div className="bg-slate-900/50 rounded-lg border border-slate-800 overflow-hidden">
|
|
151
|
-
<div className="grid grid-cols-3 text-[9px] font-bold border-b border-slate-800 bg-slate-800/50">
|
|
152
|
-
<div className="p-2 text-slate-400">Spec</div>
|
|
153
|
-
<div className="p-2 text-indigo-400 text-center">{model.name}</div>
|
|
154
|
-
<div className="p-2 text-purple-400 text-center">{MODELS[compareIdx].name}</div>
|
|
155
|
-
</div>
|
|
156
|
-
{[
|
|
157
|
-
{ label: 'Precio', a: fmtPrice(model.price), b: fmtPrice(MODELS[compareIdx].price) },
|
|
158
|
-
{ label: 'Motor', a: model.type, b: MODELS[compareIdx].type },
|
|
159
|
-
{ label: 'Potencia', a: `${model.hp} HP`, b: `${MODELS[compareIdx].hp} HP` },
|
|
160
|
-
{ label: 'Rendimiento', a: model.type === 'EV' ? '500+ km' : `${model.kmpl} km/l`, b: MODELS[compareIdx].type === 'EV' ? '500+ km' : `${MODELS[compareIdx].kmpl} km/l` },
|
|
161
|
-
{ label: 'Colores', a: model.colors.length.toString(), b: MODELS[compareIdx].colors.length.toString() },
|
|
162
|
-
{ label: 'Paquetes', a: model.packages.length.toString(), b: MODELS[compareIdx].packages.length.toString() },
|
|
163
|
-
].map(r => (
|
|
164
|
-
<div key={r.label} className="grid grid-cols-3 text-[9px] border-b border-slate-800/50">
|
|
165
|
-
<div className="p-1.5 text-slate-500">{r.label}</div>
|
|
166
|
-
<div className="p-1.5 text-center font-semibold">{r.a}</div>
|
|
167
|
-
<div className="p-1.5 text-center font-semibold">{r.b}</div>
|
|
168
|
-
</div>
|
|
169
|
-
))}
|
|
170
|
-
</div>
|
|
171
|
-
</>
|
|
172
|
-
)}
|
|
173
|
-
|
|
174
|
-
{tab === 'agenda' && (
|
|
175
|
-
<>
|
|
176
|
-
<div className="text-[9px] text-slate-500 font-bold uppercase mb-1">📅 Agendar Test Drive — {model.name}</div>
|
|
177
|
-
<div className="grid grid-cols-3 gap-1.5">
|
|
178
|
-
{SLOTS.map(s => (
|
|
179
|
-
<button key={s} className="bg-slate-900/50 border border-slate-800 rounded-lg p-2 text-center hover:bg-indigo-600/20 hover:border-indigo-500/30 transition-all">
|
|
180
|
-
<div className="text-[10px] font-bold">{s}</div>
|
|
181
|
-
<div className="text-[8px] text-green-400">Disponible</div>
|
|
182
|
-
</button>
|
|
183
|
-
))}
|
|
184
|
-
</div>
|
|
185
|
-
<div className="bg-green-500/10 rounded-lg p-2.5 border border-green-500/20 text-[9px] text-green-400">
|
|
186
|
-
✅ Selecciona un slot y se enviará confirmación por WhatsApp al cliente.
|
|
187
|
-
</div>
|
|
188
|
-
</>
|
|
189
|
-
)}
|
|
190
|
-
</div>
|
|
191
|
-
</div>
|
|
192
|
-
</BaseNode>
|
|
193
|
-
);
|
|
194
|
-
};
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { BaseNode } from '@decido/macia-core';
|
|
3
|
-
import {
|
|
4
|
-
ShoppingCart, Search, Star, Heart, Package, Truck,
|
|
5
|
-
Plus, Minus, X, Sparkles, Tag, TrendingUp, BarChart3, Eye
|
|
6
|
-
} from 'lucide-react';
|
|
7
|
-
|
|
8
|
-
/* ═══════════════════════════════════════════════════════════════
|
|
9
|
-
KIA STORE NODE — Accessories Store · Grecco Motors
|
|
10
|
-
E-Commerce con recomendaciones IA y analytics de revenue
|
|
11
|
-
═══════════════════════════════════════════════════════════════ */
|
|
12
|
-
|
|
13
|
-
const PRODUCTS = [
|
|
14
|
-
{ id: 1, name: 'Tapetes Originales Sportage', price: 280000, rating: 4.8, reviews: 142, category: 'Interior', image: '🏎️', badge: 'Más vendido', stock: 23 },
|
|
15
|
-
{ id: 2, name: 'Cámara de Reversa HD 4K', price: 450000, rating: 4.6, reviews: 89, category: 'Tecnología', image: '📷', badge: null, stock: 8 },
|
|
16
|
-
{ id: 3, name: 'Barras de Techo Seltos', price: 670000, rating: 4.9, reviews: 56, category: 'Exterior', image: '🔩', badge: 'Premium', stock: 12 },
|
|
17
|
-
{ id: 4, name: 'Kit Stickers Deportivos GT', price: 150000, rating: 4.3, reviews: 210, category: 'Exterior', image: '🎨', badge: null, stock: 45 },
|
|
18
|
-
{ id: 5, name: 'Cargador Inalámbrico QI 15W', price: 320000, rating: 4.7, reviews: 74, category: 'Tecnología', image: '🔋', badge: 'Nuevo', stock: 18 },
|
|
19
|
-
{ id: 6, name: 'Protector de Baúl EV6', price: 190000, rating: 4.5, reviews: 38, category: 'Interior', image: '🧳', badge: null, stock: 31 },
|
|
20
|
-
{ id: 7, name: 'Polarizado Nano-Cerámico 3M', price: 850000, rating: 4.9, reviews: 167, category: 'Servicio', image: '🪟', badge: 'Top Rated', stock: 99 },
|
|
21
|
-
{ id: 8, name: 'Dash Cam Inteligente IA', price: 520000, rating: 4.4, reviews: 43, category: 'Tecnología', image: '📹', badge: 'Nuevo', stock: 15 },
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
const AI_RECOMMENDATIONS = [
|
|
25
|
-
{ text: 'Combo Sportage: Tapetes + Protector Baúl con 15% OFF', related: [1, 6], savings: '$70.500' },
|
|
26
|
-
{ text: 'Kit Tech: Cámara 4K + Cargador QI + Dash Cam = 12% OFF', related: [2, 5, 8], savings: '$154.800' },
|
|
27
|
-
{ text: 'Ideal para tu EV6: Barras de Techo + Kit GT', related: [3, 4], savings: '$82.000' },
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
const jitter = (n: number, r: number) => n + Math.round((Math.random() - 0.5) * r);
|
|
31
|
-
|
|
32
|
-
export const KiaStoreNode = (props: any) => {
|
|
33
|
-
const [cart, setCart] = useState<Record<number, number>>({});
|
|
34
|
-
const [search, setSearch] = useState('');
|
|
35
|
-
const [favorites, setFavorites] = useState<Set<number>>(new Set([1, 3, 7]));
|
|
36
|
-
const [showCart, setShowCart] = useState(false);
|
|
37
|
-
const [showAI, setShowAI] = useState(false);
|
|
38
|
-
const [monthRevenue] = useState(47800000);
|
|
39
|
-
const [todayOrders] = useState(12);
|
|
40
|
-
|
|
41
|
-
const cartCount = Object.values(cart).reduce((a, b) => a + b, 0);
|
|
42
|
-
const cartTotal = Object.entries(cart).reduce((acc, [id, qty]) => {
|
|
43
|
-
const product = PRODUCTS.find(p => p.id === Number(id));
|
|
44
|
-
return acc + (product ? product.price * qty : 0);
|
|
45
|
-
}, 0);
|
|
46
|
-
|
|
47
|
-
const addToCart = (id: number) => setCart(prev => ({ ...prev, [id]: (prev[id] || 0) + 1 }));
|
|
48
|
-
const removeFromCart = (id: number) => setCart(prev => {
|
|
49
|
-
const next = { ...prev };
|
|
50
|
-
if (next[id] > 1) next[id]--;
|
|
51
|
-
else delete next[id];
|
|
52
|
-
return next;
|
|
53
|
-
});
|
|
54
|
-
const toggleFav = (id: number) => setFavorites(prev => {
|
|
55
|
-
const next = new Set(prev);
|
|
56
|
-
next.has(id) ? next.delete(id) : next.add(id);
|
|
57
|
-
return next;
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const filtered = PRODUCTS.filter(p =>
|
|
61
|
-
p.name.toLowerCase().includes(search.toLowerCase()) ||
|
|
62
|
-
p.category.toLowerCase().includes(search.toLowerCase())
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
const formatCOP = (n: number) => `$${n.toLocaleString('es-CO')}`;
|
|
66
|
-
|
|
67
|
-
return (
|
|
68
|
-
<BaseNode {...props} title="Kia Accessories Store" width={480} height={660}>
|
|
69
|
-
<div className="flex flex-col h-full bg-slate-950 text-white overflow-hidden">
|
|
70
|
-
|
|
71
|
-
{/* Header */}
|
|
72
|
-
<div className="flex items-center gap-3 p-3 bg-slate-900 border-b border-slate-800">
|
|
73
|
-
<div className="w-9 h-9 rounded-full bg-red-600/20 flex items-center justify-center border border-red-500/30">
|
|
74
|
-
<span className="text-red-500 font-bold text-[7px] tracking-widest">KIA</span>
|
|
75
|
-
</div>
|
|
76
|
-
<div className="flex-1">
|
|
77
|
-
<div className="text-xs font-bold tracking-wide">ACCESSORIES STORE</div>
|
|
78
|
-
<div className="text-[10px] text-slate-400">Grecco Motors · {PRODUCTS.length} productos</div>
|
|
79
|
-
</div>
|
|
80
|
-
<button
|
|
81
|
-
onClick={() => { setShowAI(!showAI); setShowCart(false); }}
|
|
82
|
-
className={`p-1.5 rounded-lg border transition-all ${showAI ? 'bg-violet-500/20 border-violet-500/40 text-violet-400' : 'bg-slate-800 border-slate-700 text-slate-400'}`}
|
|
83
|
-
>
|
|
84
|
-
<Sparkles size={14} />
|
|
85
|
-
</button>
|
|
86
|
-
<button
|
|
87
|
-
onClick={() => { setShowCart(!showCart); setShowAI(false); }}
|
|
88
|
-
className="relative p-1.5 rounded-lg bg-slate-800 border border-slate-700 text-slate-400 hover:text-white transition-all"
|
|
89
|
-
>
|
|
90
|
-
<ShoppingCart size={14} />
|
|
91
|
-
{cartCount > 0 && (
|
|
92
|
-
<span className="absolute -top-1 -right-1 w-4 h-4 bg-red-500 rounded-full text-[8px] font-bold flex items-center justify-center">{cartCount}</span>
|
|
93
|
-
)}
|
|
94
|
-
</button>
|
|
95
|
-
</div>
|
|
96
|
-
|
|
97
|
-
{/* Revenue Mini Stats */}
|
|
98
|
-
<div className="flex items-center justify-between px-3 py-1.5 bg-slate-900/50 border-b border-slate-800 text-[10px]">
|
|
99
|
-
<span className="text-slate-500">Revenue Mes: <span className="text-green-400 font-bold">{formatCOP(monthRevenue)}</span></span>
|
|
100
|
-
<span className="text-slate-500">Pedidos Hoy: <span className="text-blue-400 font-bold">{todayOrders}</span></span>
|
|
101
|
-
<span className="text-slate-500">Ticket Prom: <span className="text-purple-400 font-bold">{formatCOP(Math.round(monthRevenue / 128))}</span></span>
|
|
102
|
-
</div>
|
|
103
|
-
|
|
104
|
-
{/* Search */}
|
|
105
|
-
<div className="p-2 border-b border-slate-800">
|
|
106
|
-
<div className="relative">
|
|
107
|
-
<Search size={12} className="absolute left-2.5 top-2.5 text-slate-500" />
|
|
108
|
-
<input
|
|
109
|
-
type="text" placeholder="Buscar accesorios..."
|
|
110
|
-
value={search} onChange={e => setSearch(e.target.value)}
|
|
111
|
-
className="w-full bg-slate-900 border border-slate-800 rounded-lg py-2 pl-8 pr-3 text-xs text-white focus:outline-none focus:border-red-500/50 transition-colors"
|
|
112
|
-
/>
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
|
|
116
|
-
{/* AI Recommendations */}
|
|
117
|
-
{showAI && (
|
|
118
|
-
<div className="p-2 border-b border-slate-800 bg-violet-500/5">
|
|
119
|
-
<div className="text-[9px] text-violet-400 font-bold uppercase mb-1.5 flex items-center gap-1"><Sparkles size={10} /> Combos IA — Ahorra más</div>
|
|
120
|
-
<div className="space-y-1.5">
|
|
121
|
-
{AI_RECOMMENDATIONS.map((r, i) => (
|
|
122
|
-
<div key={i} className="bg-slate-900 border border-violet-500/20 rounded-lg p-2">
|
|
123
|
-
<div className="text-[10px] text-slate-300 mb-1">{r.text}</div>
|
|
124
|
-
<div className="flex items-center justify-between">
|
|
125
|
-
<div className="flex gap-1">
|
|
126
|
-
{r.related.map(id => (
|
|
127
|
-
<button key={id} onClick={() => addToCart(id)} className="bg-violet-500/20 hover:bg-violet-500/30 text-violet-300 px-1.5 py-0.5 rounded text-[8px] transition-colors">
|
|
128
|
-
+ {PRODUCTS.find(p => p.id === id)?.name.split(' ').slice(0, 2).join(' ')}
|
|
129
|
-
</button>
|
|
130
|
-
))}
|
|
131
|
-
</div>
|
|
132
|
-
<span className="text-[9px] text-green-400 font-bold">Ahorra {r.savings}</span>
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
))}
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
)}
|
|
139
|
-
|
|
140
|
-
{/* Cart Drawer */}
|
|
141
|
-
{showCart && (
|
|
142
|
-
<div className="p-2 border-b border-slate-800 bg-red-500/5">
|
|
143
|
-
<div className="text-[9px] text-red-400 font-bold uppercase mb-1.5 flex items-center gap-1"><ShoppingCart size={10} /> Carrito ({cartCount})</div>
|
|
144
|
-
{Object.keys(cart).length === 0 ? (
|
|
145
|
-
<div className="text-[10px] text-slate-500 text-center py-3">Tu carrito está vacío</div>
|
|
146
|
-
) : (
|
|
147
|
-
<>
|
|
148
|
-
{Object.entries(cart).map(([id, qty]) => {
|
|
149
|
-
const product = PRODUCTS.find(p => p.id === Number(id))!;
|
|
150
|
-
return (
|
|
151
|
-
<div key={id} className="flex items-center gap-2 py-1 text-[10px]">
|
|
152
|
-
<span className="text-sm">{product.image}</span>
|
|
153
|
-
<div className="flex-1 min-w-0 truncate text-slate-300">{product.name}</div>
|
|
154
|
-
<div className="flex items-center gap-1">
|
|
155
|
-
<button onClick={() => removeFromCart(Number(id))} className="p-0.5 bg-slate-800 rounded"><Minus size={8} /></button>
|
|
156
|
-
<span className="w-4 text-center font-bold">{qty}</span>
|
|
157
|
-
<button onClick={() => addToCart(Number(id))} className="p-0.5 bg-slate-800 rounded"><Plus size={8} /></button>
|
|
158
|
-
</div>
|
|
159
|
-
<span className="font-bold text-white">{formatCOP(product.price * qty)}</span>
|
|
160
|
-
</div>
|
|
161
|
-
);
|
|
162
|
-
})}
|
|
163
|
-
<div className="flex justify-between items-center pt-2 mt-1 border-t border-slate-800">
|
|
164
|
-
<span className="text-xs font-bold">Total</span>
|
|
165
|
-
<span className="text-sm font-bold text-red-400">{formatCOP(cartTotal)}</span>
|
|
166
|
-
</div>
|
|
167
|
-
<button className="w-full mt-2 bg-red-600 hover:bg-red-500 text-white text-xs font-bold py-2 rounded-lg flex items-center justify-center gap-2 transition-all">
|
|
168
|
-
<Truck size={12} /> Agendar Instalación
|
|
169
|
-
</button>
|
|
170
|
-
</>
|
|
171
|
-
)}
|
|
172
|
-
</div>
|
|
173
|
-
)}
|
|
174
|
-
|
|
175
|
-
{/* Product Grid */}
|
|
176
|
-
<div className="flex-1 overflow-y-auto p-2">
|
|
177
|
-
<div className="grid grid-cols-2 gap-2">
|
|
178
|
-
{filtered.map(p => (
|
|
179
|
-
<div key={p.id} className="bg-slate-900 rounded-xl border border-slate-800 overflow-hidden hover:border-slate-700 transition-all group">
|
|
180
|
-
<div className="relative h-16 bg-slate-800/50 flex items-center justify-center">
|
|
181
|
-
<span className="text-3xl group-hover:scale-110 transition-transform">{p.image}</span>
|
|
182
|
-
<button onClick={() => toggleFav(p.id)} className="absolute top-1.5 right-1.5">
|
|
183
|
-
<Heart size={12} className={favorites.has(p.id) ? 'fill-red-500 text-red-500' : 'text-slate-500'} />
|
|
184
|
-
</button>
|
|
185
|
-
{p.badge && (
|
|
186
|
-
<span className={`absolute top-1.5 left-1.5 text-[7px] font-bold px-1.5 py-0.5 rounded ${p.badge === 'Más vendido' ? 'bg-green-500' : p.badge === 'Premium' ? 'bg-blue-500' : p.badge === 'Top Rated' ? 'bg-yellow-500 text-black' : 'bg-red-500'}`}>
|
|
187
|
-
{p.badge}
|
|
188
|
-
</span>
|
|
189
|
-
)}
|
|
190
|
-
</div>
|
|
191
|
-
<div className="p-2">
|
|
192
|
-
<div className="text-[10px] font-semibold leading-tight mb-0.5">{p.name}</div>
|
|
193
|
-
<div className="flex items-center gap-1 text-[9px] mb-1">
|
|
194
|
-
<Star size={8} className="text-yellow-400 fill-yellow-400" />
|
|
195
|
-
<span className="text-slate-400">{p.rating} ({p.reviews})</span>
|
|
196
|
-
<span className="text-slate-600">·</span>
|
|
197
|
-
<span className={`${p.stock < 10 ? 'text-red-400' : 'text-slate-500'}`}>
|
|
198
|
-
{p.stock < 10 ? `¡${p.stock} left!` : `${p.stock} disp`}
|
|
199
|
-
</span>
|
|
200
|
-
</div>
|
|
201
|
-
<div className="flex items-center justify-between">
|
|
202
|
-
<span className="text-xs font-bold text-white">{formatCOP(p.price)}</span>
|
|
203
|
-
<button onClick={() => addToCart(p.id)} className="p-1 bg-red-600 hover:bg-red-500 rounded text-white transition-colors">
|
|
204
|
-
<Plus size={10} />
|
|
205
|
-
</button>
|
|
206
|
-
</div>
|
|
207
|
-
</div>
|
|
208
|
-
</div>
|
|
209
|
-
))}
|
|
210
|
-
</div>
|
|
211
|
-
</div>
|
|
212
|
-
</div>
|
|
213
|
-
</BaseNode>
|
|
214
|
-
);
|
|
215
|
-
};
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { BaseNode } from '@decido/macia-core';
|
|
3
|
-
import {
|
|
4
|
-
Leaf, Zap, Droplets, Sun, TrendingUp,
|
|
5
|
-
BarChart3, Award, Battery, Car, Factory
|
|
6
|
-
} from 'lucide-react';
|
|
7
|
-
|
|
8
|
-
/* ═══════════════════════════════════════════════════════════════
|
|
9
|
-
KIA SUSTAINABILITY NODE — ESG & Green Dealer · Grecco Motors
|
|
10
|
-
Huella CO₂, mix EV/ICE, ESG indicators, Green Dealer Score
|
|
11
|
-
═══════════════════════════════════════════════════════════════ */
|
|
12
|
-
|
|
13
|
-
const CARBON = [
|
|
14
|
-
{ source: 'Showroom (electricidad)', co2: 12.4, unit: 'ton/mes', trend: -8, color: '#f59e0b' },
|
|
15
|
-
{ source: 'Taller (operación)', co2: 8.2, unit: 'ton/mes', trend: -5, color: '#ef4444' },
|
|
16
|
-
{ source: 'Flota Demo (combustible)', co2: 3.1, unit: 'ton/mes', trend: -22, color: '#3b82f6' },
|
|
17
|
-
{ source: 'V2G Grid Return', co2: -4.6, unit: 'ton/mes', trend: 15, color: '#22c55e' },
|
|
18
|
-
{ source: 'Paneles Solares', co2: -2.8, unit: 'ton/mes', trend: 12, color: '#10b981' },
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
const EV_MIX = [
|
|
22
|
-
{ month: 'Sep', ev: 8, hev: 15, ice: 77 },
|
|
23
|
-
{ month: 'Oct', ev: 10, hev: 16, ice: 74 },
|
|
24
|
-
{ month: 'Nov', ev: 12, hev: 18, ice: 70 },
|
|
25
|
-
{ month: 'Dic', ev: 14, hev: 19, ice: 67 },
|
|
26
|
-
{ month: 'Ene', ev: 16, hev: 20, ice: 64 },
|
|
27
|
-
{ month: 'Feb', ev: 18, hev: 22, ice: 60 },
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
const ESG_INDICATORS = [
|
|
31
|
-
{ category: '🌱 Ambiental', score: 82, items: ['Huella de carbono ↓18%', 'EV ratio 18%', 'Reciclaje 92%'] },
|
|
32
|
-
{ category: '👥 Social', score: 88, items: ['NPS 95.3', 'Capacitación 100%', 'Equity hiring ✓'] },
|
|
33
|
-
{ category: '🏛️ Gobernanza', score: 91, items: ['Compliance 98%', 'Auditoría Q4 ✓', 'Anti-corruption ✓'] },
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
export const KiaSustainabilityNode = (props: any) => {
|
|
37
|
-
const [tab, setTab] = useState<'carbon' | 'ev' | 'esg'>('carbon');
|
|
38
|
-
const [carbon, setCarbon] = useState(CARBON.map(c => ({ ...c })));
|
|
39
|
-
|
|
40
|
-
const netCarbon = carbon.reduce((s, c) => s + c.co2, 0).toFixed(1);
|
|
41
|
-
const currentEV = EV_MIX[EV_MIX.length - 1];
|
|
42
|
-
const greenScore = Math.round(ESG_INDICATORS.reduce((s, e) => s + e.score, 0) / ESG_INDICATORS.length);
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
const interval = setInterval(() => {
|
|
46
|
-
setCarbon(prev => prev.map(c => ({
|
|
47
|
-
...c,
|
|
48
|
-
co2: parseFloat((c.co2 + (Math.random() - 0.52) * 0.2).toFixed(1)),
|
|
49
|
-
})));
|
|
50
|
-
}, 6000);
|
|
51
|
-
return () => clearInterval(interval);
|
|
52
|
-
}, []);
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<BaseNode {...props} title="Kia Sustainability" width={480} height={620}>
|
|
56
|
-
<div className="flex flex-col h-full bg-[#040a06] text-white overflow-hidden">
|
|
57
|
-
|
|
58
|
-
{/* Header */}
|
|
59
|
-
<div className="flex items-center gap-3 p-3 bg-[#0a1a0e] border-b border-green-900/30">
|
|
60
|
-
<div className="w-9 h-9 rounded-full bg-green-600/20 flex items-center justify-center border border-green-500/30">
|
|
61
|
-
<Leaf size={16} className="text-green-400" />
|
|
62
|
-
</div>
|
|
63
|
-
<div className="flex-1">
|
|
64
|
-
<div className="text-xs font-bold tracking-wide flex items-center gap-2">
|
|
65
|
-
SUSTAINABILITY & ESG
|
|
66
|
-
<span className="text-[8px] px-1.5 py-0.5 bg-green-500/20 text-green-400 rounded">{greenScore} GREEN SCORE</span>
|
|
67
|
-
</div>
|
|
68
|
-
<div className="text-[10px] text-slate-400">Grecco Motors · Net CO₂: {netCarbon} ton/mes · EV Mix {currentEV.ev}%</div>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
|
-
{/* Tabs */}
|
|
73
|
-
<div className="flex gap-1 p-2 bg-[#060e08] border-b border-green-900/20">
|
|
74
|
-
{([
|
|
75
|
-
{ key: 'carbon' as const, label: '🌍 Carbono' },
|
|
76
|
-
{ key: 'ev' as const, label: '⚡ EV Mix' },
|
|
77
|
-
{ key: 'esg' as const, label: '📊 ESG' },
|
|
78
|
-
]).map(t => (
|
|
79
|
-
<button key={t.key} onClick={() => setTab(t.key)}
|
|
80
|
-
className={`flex-1 py-1.5 rounded text-[9px] font-bold transition-all ${tab === t.key ? 'bg-green-600/20 text-green-400 border border-green-500/30' : 'text-slate-500'
|
|
81
|
-
}`}>
|
|
82
|
-
{t.label}
|
|
83
|
-
</button>
|
|
84
|
-
))}
|
|
85
|
-
</div>
|
|
86
|
-
|
|
87
|
-
<div className="flex-1 overflow-y-auto p-3 space-y-2">
|
|
88
|
-
|
|
89
|
-
{tab === 'carbon' && (
|
|
90
|
-
<>
|
|
91
|
-
<div className="bg-green-500/5 rounded-lg p-3 border border-green-500/20 text-center">
|
|
92
|
-
<div className="text-[9px] text-slate-400 uppercase">Huella Neta Mensual</div>
|
|
93
|
-
<div className={`text-2xl font-black ${parseFloat(netCarbon) > 0 ? 'text-yellow-400' : 'text-green-400'}`}>{netCarbon} ton CO₂</div>
|
|
94
|
-
<div className="text-[9px] text-green-400">↓ 18% vs año anterior</div>
|
|
95
|
-
</div>
|
|
96
|
-
{carbon.map(c => (
|
|
97
|
-
<div key={c.source} className="bg-slate-900/50 rounded-lg p-2.5 border border-slate-800"
|
|
98
|
-
style={{ borderLeftWidth: '2px', borderLeftColor: c.color }}>
|
|
99
|
-
<div className="flex items-center justify-between">
|
|
100
|
-
<span className="text-[10px] font-semibold">{c.source}</span>
|
|
101
|
-
<div className="flex items-center gap-2">
|
|
102
|
-
<span className={`text-[8px] font-bold ${c.trend < 0 ? 'text-green-400' : 'text-red-400'}`}>
|
|
103
|
-
{c.trend > 0 ? '↑' : '↓'}{Math.abs(c.trend)}%
|
|
104
|
-
</span>
|
|
105
|
-
<span className={`text-sm font-bold ${c.co2 < 0 ? 'text-green-400' : 'text-yellow-400'}`}>{c.co2}</span>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
))}
|
|
110
|
-
</>
|
|
111
|
-
)}
|
|
112
|
-
|
|
113
|
-
{tab === 'ev' && (
|
|
114
|
-
<>
|
|
115
|
-
<div className="text-[9px] text-slate-500 font-bold uppercase mb-1">Mix Ventas EV / HEV / ICE — 6 meses</div>
|
|
116
|
-
{EV_MIX.map(m => (
|
|
117
|
-
<div key={m.month} className="bg-slate-900/50 rounded-lg p-2 border border-slate-800">
|
|
118
|
-
<div className="text-[9px] text-slate-400 font-bold mb-1">{m.month}</div>
|
|
119
|
-
<div className="flex h-3 rounded-full overflow-hidden">
|
|
120
|
-
<div className="bg-green-500 transition-all" style={{ width: `${m.ev}%` }} title={`EV ${m.ev}%`} />
|
|
121
|
-
<div className="bg-cyan-500 transition-all" style={{ width: `${m.hev}%` }} title={`HEV ${m.hev}%`} />
|
|
122
|
-
<div className="bg-slate-700 transition-all" style={{ width: `${m.ice}%` }} title={`ICE ${m.ice}%`} />
|
|
123
|
-
</div>
|
|
124
|
-
<div className="flex justify-between text-[8px] text-slate-500 mt-0.5">
|
|
125
|
-
<span className="text-green-400">EV {m.ev}%</span>
|
|
126
|
-
<span className="text-cyan-400">HEV {m.hev}%</span>
|
|
127
|
-
<span className="text-slate-500">ICE {m.ice}%</span>
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
))}
|
|
131
|
-
<div className="bg-green-500/5 rounded-lg p-2.5 border border-green-500/20 text-[9px] text-green-400">
|
|
132
|
-
🎯 Meta KIA 2027: EV 35% · Actual: {currentEV.ev}% · Progreso: {((currentEV.ev / 35) * 100).toFixed(0)}%
|
|
133
|
-
</div>
|
|
134
|
-
</>
|
|
135
|
-
)}
|
|
136
|
-
|
|
137
|
-
{tab === 'esg' && (
|
|
138
|
-
<>
|
|
139
|
-
<div className="bg-green-500/5 rounded-lg p-3 border border-green-500/20 flex items-center justify-between">
|
|
140
|
-
<div>
|
|
141
|
-
<div className="text-[9px] text-slate-400">GREEN DEALER SCORE</div>
|
|
142
|
-
<div className="text-2xl font-black text-green-400">{greenScore}</div>
|
|
143
|
-
</div>
|
|
144
|
-
<Award size={32} className="text-green-500/30" />
|
|
145
|
-
</div>
|
|
146
|
-
{ESG_INDICATORS.map(e => (
|
|
147
|
-
<div key={e.category} className="bg-slate-900/50 rounded-lg p-3 border border-slate-800">
|
|
148
|
-
<div className="flex items-center justify-between mb-1.5">
|
|
149
|
-
<span className="text-[11px] font-bold">{e.category}</span>
|
|
150
|
-
<span className="text-sm font-bold text-green-400">{e.score}/100</span>
|
|
151
|
-
</div>
|
|
152
|
-
<div className="flex items-center gap-2 mb-2">
|
|
153
|
-
<div className="flex-1 h-2 bg-slate-800 rounded-full">
|
|
154
|
-
<div className="h-full rounded-full bg-linear-to-r from-green-600 to-emerald-400"
|
|
155
|
-
style={{ width: `${e.score}%` }} />
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
<div className="space-y-0.5">
|
|
159
|
-
{e.items.map(item => (
|
|
160
|
-
<div key={item} className="text-[8px] text-slate-400 flex items-center gap-1">
|
|
161
|
-
<span className="text-green-400">✓</span> {item}
|
|
162
|
-
</div>
|
|
163
|
-
))}
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
166
|
-
))}
|
|
167
|
-
</>
|
|
168
|
-
)}
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
</BaseNode>
|
|
172
|
-
);
|
|
173
|
-
};
|