"use client" import { useSocket } from "@/context/SocketContext" import { closeTerminal as closeTerminalHelper, createTerminal as createTerminalHelper, } from "@/lib/terminal" import { Terminal } from "@xterm/xterm" import React, { createContext, useContext, useState } from "react" interface TerminalContextType { terminals: { id: string; terminal: Terminal | null }[] setTerminals: React.Dispatch< React.SetStateAction<{ id: string; terminal: Terminal | null }[]> > activeTerminalId: string setActiveTerminalId: React.Dispatch> creatingTerminal: boolean setCreatingTerminal: React.Dispatch> createNewTerminal: (command?: string) => Promise closeTerminal: (id: string) => void deploy: (callback: () => void) => void getAppExists: | ((appName: string) => Promise<{ success: boolean; exists?: boolean }>) | null } const TerminalContext = createContext( undefined ) export const TerminalProvider: React.FC<{ children: React.ReactNode }> = ({ children, }) => { const { socket } = useSocket() const [terminals, setTerminals] = useState< { id: string; terminal: Terminal | null }[] >([]) const [activeTerminalId, setActiveTerminalId] = useState("") const [creatingTerminal, setCreatingTerminal] = useState(false) const [isSocketReady, setIsSocketReady] = useState(false) // Listen for the "ready" signal from the socket React.useEffect(() => { if (socket) { socket.on("ready", () => { setIsSocketReady(true) }) } return () => { if (socket) socket.off("ready") } }, [socket]) const createNewTerminal = async (command?: string): Promise => { if (!socket) return setCreatingTerminal(true) try { createTerminalHelper({ setTerminals, setActiveTerminalId, setCreatingTerminal, command, socket, }) } catch (error) { console.error("Error creating terminal:", error) } finally { setCreatingTerminal(false) } } const closeTerminal = (id: string) => { if (!socket) return const terminalToClose = terminals.find((term) => term.id === id) if (terminalToClose) { closeTerminalHelper({ term: terminalToClose, terminals, setTerminals, setActiveTerminalId, setClosingTerminal: () => {}, socket, activeTerminalId, }) } } const deploy = (callback: () => void) => { if (!socket) console.error("Couldn't deploy: No socket") console.log("Deploying...") socket?.emit("deploy", {}, () => { callback() }) } const getAppExists = async ( appName: string ): Promise<{ success: boolean; exists?: boolean }> => { console.log("Is there a socket: " + !!socket) if (!socket) { console.error("Couldn't check if app exists: No socket") return { success: false } } const response: { success: boolean; exists?: boolean } = await new Promise( (resolve) => socket.emit("getAppExists", { appName }, resolve) ) return response } const value = { terminals, setTerminals, activeTerminalId, setActiveTerminalId, creatingTerminal, setCreatingTerminal, createNewTerminal, closeTerminal, deploy, getAppExists: isSocketReady ? getAppExists : null, } return ( {children} ) } export const useTerminal = (): TerminalContextType => { const context = useContext(TerminalContext) if (!context) { throw new Error("useTerminal must be used within a TerminalProvider") } return context }