import React, { useState, useEffect } from 'react' import { Button } from './ui/8bit/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './ui/8bit/card' import { Input } from './ui/8bit/input' import { Label } from './ui/8bit/label' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from './ui/8bit/dialog' import { Edit3, Save, X, Plus, Trash2, Eye, EyeOff, GitCommit, FileEdit, AlertTriangle } from 'lucide-react' import type { DraftVariable, VariableChange, DraftSession } from '../types' interface DraftModeProps { projectPath?: string onPublish?: () => void onDiscard?: () => void playSound?: (type: 'success' | 'error' | 'powerup' | 'hit') => void } export default function DraftMode({ projectPath, onPublish, onDiscard, playSound }: DraftModeProps) { const [draft, setDraft] = useState(null) const [draftVariables, setDraftVariables] = useState([]) const [changes, setChanges] = useState([]) const [isLoading, setIsLoading] = useState(false) const [publishDescription, setPublishDescription] = useState('') const [showSensitive, setShowSensitive] = useState>(new Set()) const [editingVariable, setEditingVariable] = useState(null) useEffect(() => { loadDraftState() }, [projectPath]) const loadDraftState = async () => { setIsLoading(true) try { const res = await fetch(`/api/draft${projectPath ? `?projectPath=${encodeURIComponent(projectPath)}` : ''}`) if (res.ok) { const data = await res.json() setDraft(data.draft) setDraftVariables(data.variables || []) setChanges(data.changes || []) setPublishDescription(data.draft?.description || '') } } catch (error) { console.error('Failed to load draft state:', error) playSound?.('error') } setIsLoading(false) } const createDraft = async () => { try { const res = await fetch('/api/draft', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'create', projectPath, description: publishDescription }) }) if (res.ok) { await loadDraftState() playSound?.('powerup') } } catch (error) { console.error('Failed to create draft:', error) playSound?.('error') } } const updateDraftVariable = async (name: string, updates: Partial) => { try { const res = await fetch('/api/draft', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'update_variable', projectPath, name, updates }) }) if (res.ok) { await loadDraftState() setEditingVariable(null) playSound?.('hit') } } catch (error) { console.error('Failed to update draft variable:', error) playSound?.('error') } } const addVariableToDraft = async (variable: Partial) => { try { const res = await fetch('/api/draft', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'add_variable', projectPath, variable }) }) if (res.ok) { await loadDraftState() playSound?.('powerup') } } catch (error) { console.error('Failed to add variable to draft:', error) playSound?.('error') } } const removeFromDraft = async (name: string) => { try { const res = await fetch('/api/draft', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'remove_variable', projectPath, name }) }) if (res.ok) { await loadDraftState() playSound?.('hit') } } catch (error) { console.error('Failed to remove variable from draft:', error) playSound?.('error') } } const publishDraft = async () => { if (!draft || changes.length === 0) return try { const res = await fetch('/api/draft', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'publish', projectPath, description: publishDescription }) }) if (res.ok) { const data = await res.json() await loadDraftState() onPublish?.() playSound?.('success') setPublishDescription('') } } catch (error) { console.error('Failed to publish draft:', error) playSound?.('error') } } const discardDraft = async () => { if (!confirm('Are you sure you want to discard all draft changes? This cannot be undone.')) { return } try { const res = await fetch('/api/draft', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'discard', projectPath }) }) if (res.ok) { await loadDraftState() onDiscard?.() playSound?.('hit') setPublishDescription('') } } catch (error) { console.error('Failed to discard draft:', error) playSound?.('error') } } const toggleSensitiveVisibility = (name: string) => { const newSet = new Set(showSensitive) if (newSet.has(name)) { newSet.delete(name) } else { newSet.add(name) } setShowSensitive(newSet) } const getChangeTypeDisplay = (type: 'create' | 'update' | 'delete' | 'none') => { switch (type) { case 'create': return { text: 'NEW', color: 'bg-green-500/20 text-green-400', icon: Plus } case 'update': return { text: 'MODIFIED', color: 'bg-yellow-500/20 text-yellow-400', icon: Edit3 } case 'delete': return { text: 'DELETE', color: 'bg-red-500/20 text-red-400', icon: Trash2 } case 'none': default: return { text: 'UNCHANGED', color: 'bg-gray-500/20 text-gray-400', icon: Edit3 } } } if (isLoading) { return (
Loading draft state...
) } if (!draft) { return ( DRAFT MODE Start drafting changes to edit multiple variables before publishing

No active draft session

) } return (
{/* Draft Header */}
DRAFT MODE ACTIVE
Publish Draft Changes You're about to publish {changes.length} change(s). This will apply all modifications to your environment variables.
setPublishDescription(e.target.value)} placeholder="Describe what you changed..." />
{changes.length > 0 && (

Changes to be published:

{changes.map((change, idx) => { const { text, color, icon: Icon } = getChangeTypeDisplay(change.type) return (
{change.name}
{text}
) })}
)}
{changes.length > 0 && ( {changes.length} pending change(s) ready to publish )}
{/* Draft Variables */} Draft Variables Variables that are currently being modified in this draft {draftVariables.length === 0 ? (

No variables in draft

Add or modify variables to start drafting changes

) : (
{draftVariables.map((variable) => { const { text, color, icon: Icon } = getChangeTypeDisplay(variable.changeType) const isEditing = editingVariable === variable.name const isVisible = showSensitive.has(variable.name) return (
{text}
{variable.name} {variable.sensitive && ( SENSITIVE )}
{variable.sensitive && ( )}
{isEditing ? (
updateDraftVariable(variable.name, { value: e.target.value })} placeholder="Enter value..." />
{variable.description && (
updateDraftVariable(variable.name, { description: e.target.value })} placeholder="Variable description..." />
)}
) : (
Current Value:
{variable.sensitive && !isVisible ? '••••••••••••••••' : variable.value || Not set }
{variable.originalValue && variable.originalValue !== variable.value && (
Original Value:
{variable.sensitive && !isVisible ? '••••••••••••••••' : variable.originalValue }
)} {variable.description && (
Description:
{variable.description}
)}
)}
) })}
)}
) }