Start new chat
Starred
Star chats you use often
Recents
(New chat)
Animated Loading Screen Component
Resizable, Draggable Terminal Component
Enhancing Web App Design Without Changing Logic
Troubleshooting WebContainer deployment issues
Improving WebContainer Integration
Improving Terminal Integration with WebContainer
Troubleshooting React state and API response issues
View all
Free plan

A
<PRESIDIO_ANONYMIZED_EMAIL_ADDRESS>
Help & support

Untitled


What can I help you with today?

and make it perfect

No file chosen



Haiku

Choose style
You are out of free messages until 9:30 PM
Subscribe to Pro


please fix the whole app and the termainla as it is not working and make it best please """ 'use client' import React, { useState, useEffect, useRef } from 'react'; import QueryInput from './QueryInp
pasted
Chat controls

Haiku
Fastest model for daily tasks Learn more

Content
No content added yet
Add images, PDFs, docs, spreadsheets, and more to summarize, analyze, and query content with Claude.
Chat styles
Font

Default

Pasted content

9.74 KB •335 lines
Formatting may be inconsistent from source

please fix the whole app and the termainla as it is not working and make it best please
"""
'use client'

import React, { useState, useEffect, useRef } from 'react';
import QueryInput from './QueryInput';
import useWebContainer from '../hooks/useWebContainer';
import { sendQuery } from '../utils/api';
import { mergeJson } from '../utils/mergeJson';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Terminal as XTerminal } from '@xterm/xterm';
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Terminal, Globe, Code2, RefreshCw, PlusCircle } from 'lucide-react';
import '@xterm/xterm/css/xterm.css';
import { Loader } from './Loader';
import StartTypingScreen from './StartTypingScreen';

const WebContainerApp: React.FC = () => {
const [query, setQuery] = useState('');
const [oldObj, setOldObj] = useState({});
const [isInitialQuery, setIsInitialQuery] = useState(true);
const [isProcessing, setIsProcessing] = useState(false);
const [error, setError] = useState<string | null>(null);
const [status, setStatus] = useState({ serverReady: false, loading: true });
const [activeTab, setActiveTab] = useState('preview');

const iframeRef = useRef<HTMLIFrameElement>(null);
const { webContainerInstance, isInitialized, initializeWebContainer } = useWebContainer();
const terminalRef = useRef<HTMLDivElement>(null);
const terminalInstanceRef = useRef<XTerminal | null>(null);

useEffect(() => {
if (terminalRef.current && !terminalInstanceRef.current) {
const terminal = new XTerminal({
convertEol: true,
rows: 15,
fontSize: 14,
fontFamily: 'JetBrains Mono, monospace',
theme: {
background: '#1a1b26',
foreground: '#a9b1d6',
cursor: '#c0caf5',
selectionForeground: '#33467c',
black: '#32344a',
blue: '#7aa2f7',
cyan: '#449dab',
green: '#9ece6a',
magenta: '#ad8ee6',
red: '#f7768e',
white: '#787c99',
yellow: '#e0af68'
}
});
terminal.open(terminalRef.current);
terminalInstanceRef.current = terminal;
}
}, []);

const writeToTerminal = (message: string, type: 'default' | 'error' | 'success' | 'info' = 'default') => {
if (!terminalInstanceRef.current) return;


const colors = {
  default: '\x1b[37m',
  error: '\x1b[31m',
  success: '\x1b[32m',
  info: '\x1b[34m'
};

const colorCode = colors[type] || colors.default;
terminalInstanceRef.current.writeln(`${colorCode}${message}\x1b[0m`);
};

useEffect(() => {
initializeWebContainer();
}, [initializeWebContainer]);

useEffect(() => {
if (isInitialized && Object.keys(oldObj).length > 0) {
updateWebContainer(oldObj);
}
}, [isInitialized, oldObj]);

const updateWebContainer = async (fileStructure: any) => {
if (!webContainerInstance) {
writeToTerminal('WebContainer not initialized', 'error');
return;
}


try {
  writeToTerminal('Updating project files...', 'info');
  await webContainerInstance.mount(fileStructure);
  
  writeToTerminal('Installing dependencies...', 'info');
  const installProcess = await webContainerInstance.spawn('npm', ['install']);
  installProcess.output.pipeTo(new WritableStream({
    write(data) {
      writeToTerminal(data, 'info');
    }
  }));
  const installResult = await installProcess.exit;
  
  if (installResult !== 0) {
    throw new Error('Dependency installation failed');
  }

  writeToTerminal('Starting development server...', 'info');
  const devProcess = await webContainerInstance.spawn('npm', ['run', 'dev']);
  devProcess.output.pipeTo(new WritableStream({
    write(data) {
      writeToTerminal(data, 'info');
    }
  }));

  webContainerInstance.on('server-ready', (port, url) => {
    writeToTerminal(`Server ready at ${url}`, 'success');
    setStatus(prev => ({
      ...prev, 
      serverReady: true, 
      loading: false
    }));
    
    if (iframeRef.current) {
      iframeRef.current.src = url;
    }
  });
} catch (error: any) {
  writeToTerminal(`WebContainer update failed: ${error.message}`, 'error');
  setError('Failed to update WebContainer: ' + error.message);
}
};

const handleQuerySubmit = async () => {
if (!query.trim() || isProcessing) return;


setIsProcessing(true);
setError(null);

try {
  const response = await sendQuery(query, isInitialQuery ? undefined : oldObj);
  console.log("Full response from server:", response);

  if (!response) {
    throw new Error('No response received from server');
  }

  let mergedObj;

  if (isInitialQuery) {
    const initialFiles = response.initialFiles || {};
    const initialData = response.data || {};
    console.log("Initial Files:", initialFiles);
    console.log("Initial Data:", initialData);
    
    mergedObj = mergeJson(initialFiles, initialData);
    setOldObj(mergedObj);
    setIsInitialQuery(false);
  } else {
    const data = response.data || {};
    console.log("Old Object Before Merge:", oldObj);
    console.log("New Data:", data);

    mergedObj = mergeJson(oldObj, data);
    console.log("Merged Object:", mergedObj);
    setOldObj(mergedObj);
  }

  await updateWebContainer(mergedObj);
} catch (err: any) {
  console.error('Query submission error:', err);
  setError(err.message || 'An error occurred while processing your query.');
} finally {
  setIsProcessing(false);
  setStatus(prev => ({
    ...prev, 
    serverReady: true, 
    loading: false
  }));

  console.log("After setting - Old Object:", oldObj);
}
};

const handleReset = async () => {
setIsProcessing(true);
setError(null);


try {
  // Reset all state
  setQuery('');
  setOldObj({});
  setIsInitialQuery(true);
  setStatus({ serverReady: false, loading: true });
  
  // Clear terminal
  if (terminalInstanceRef.current) {
    terminalInstanceRef.current.clear();
  }
  
  // Reset iframe
  if (iframeRef.current) {
    iframeRef.current.src = 'about:blank';
  }
  
  // Re-initialize WebContainer
  await initializeWebContainer();
  
  writeToTerminal('Environment reset successfully', 'success');
} catch (error: any) {
  setError('Failed to reset environment: ' + error.message);
  writeToTerminal('Failed to reset environment', 'error');
} finally {
  setIsProcessing(false);
}
};

return (
<div className="min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 p-6">
<Card className="max-w-6xl mx-auto bg-white/80 backdrop-blur-sm shadow-xl border-gray-200">
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle className="text-2xl font-bold bg-gradient-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent">
WebContainer Development Environment
</CardTitle>
<div className="flex items-center gap-2">
{status.serverReady ? (
<Button
variant="outline"
size="sm"
onClick={handleReset}
disabled={isProcessing}
className="flex items-center gap-2"
>
<PlusCircle className="w-4 h-4" />
New
</Button>
) : (
<Badge variant="secondary" className="h-6">
Initializing
</Badge>
)}
{isProcessing && <RefreshCw className="w-4 h-4 animate-spin text-blue-600" />}
</div>
</div>
</CardHeader>
<CardContent className="space-y-6">
<QueryInput
query={query}
setQuery={setQuery}
onSubmit={handleQuerySubmit}
isProcessing={isProcessing}
isInitialized={isInitialized}
/>


      {error && (
        <div className="bg-red-50 border-l-4 border-red-500 p-4 rounded-r">
          <div className="flex items-center">
            <div className="flex-shrink-0">
              <svg className="h-5 w-5 text-red-500" viewBox="0 0 20 20" fill="currentColor">
                <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
              </svg>
            </div>
            <div className="ml-3">
              <p className="text-sm text-red-700">{error}</p>
            </div>
          </div>
        </div>
      )}

      <Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
        <TabsList className="grid w-full grid-cols-2 mb-4">
          <TabsTrigger value="preview" className="flex items-center gap-2">
            <Globe className="w-4 h-4" />
            Preview
          </TabsTrigger>
          <TabsTrigger value="terminal" className="flex items-center gap-2">
            <Terminal className="w-4 h-4" />
            Terminal
          </TabsTrigger>
        </TabsList>

        <TabsContent value="preview" className="border rounded-lg overflow-hidden bg-white">
          <div className="h-[600px] relative">
            {!status.serverReady && (
              <div className="absolute inset-0 flex items-center justify-center bg-gray-50">
                <Loader />
              </div>
            )}
            {isProcessing && (
              <div className="absolute inset-0 flex items-center justify-center bg-gray-50">
                <Loader />
              </div>
            )}
            {status.loading && (
              <div className="absolute inset-0 flex items-center justify-center bg-gray-50">
                <StartTypingScreen />
              </div>
            )}
            <iframe
              ref={iframeRef}
              className="w-full h-full"
              title="WebContainer Preview"
            />
          </div>
        </TabsContent>

        <TabsContent value="terminal">
          <div className="border rounded-lg overflow-hidden">
            <div className="bg-gray-900 px-4 py-2 flex items-center justify-between">
              <div className="flex items-center gap-2">
                <Code2 className="w-4 h-4 text-gray-400" />
                <span className="text-sm text-gray-300">Terminal Output</span>
              </div>
            </div>
            <div 
              ref={terminalRef} 
              className="w-full h-[400px] bg-[#1a1b26] p-4"
            />
          </div>
        </TabsContent>
      </Tabs>
    </CardContent>
  </Card>
</div>
);
};

export default WebContainerApp;
""" and make it perfect and think holistically