diff --git a/src/components/EditorPanel.jsx b/src/components/EditorPanel.jsx
index d96b02e..02f99e2 100644
--- a/src/components/EditorPanel.jsx
+++ b/src/components/EditorPanel.jsx
@@ -8,7 +8,7 @@ export default function EditorPanel({ code, onChange }) {
border: '1px solid #444',
borderRadius: '8px',
backgroundColor: '#1e1e1e',
- height: '90%',
+ height: '80%',
boxShadow: '0 0 10px rgba(255, 0, 255, 0.2)',
overflow: 'hidden'
}}>
diff --git a/src/components/PreviewPanel.jsx b/src/components/PreviewPanel.jsx
index 3e66bd7..09c70af 100644
--- a/src/components/PreviewPanel.jsx
+++ b/src/components/PreviewPanel.jsx
@@ -1,28 +1,19 @@
import React, { useState } from 'react';
-export default function PreviewPanel({ code }) {
- const [gameUrl, setGameUrl] = useState('');
- const [settings, setSettings] = useState(null);
- const [loadingSetup, setLoadingSetup] = useState(false);
+const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
- const fetchBoard = async () => {
- if (!gameUrl.trim()) return;
- setLoadingSetup(true);
- try {
- const res = await fetch(
- `/api/fetch-board?url=${encodeURIComponent(gameUrl.trim())}`
- );
- if (!res.ok) throw new Error('Fetch board failed');
- setSettings(await res.json());
- } catch (err) {
- console.error(err);
- } finally {
- setLoadingSetup(false);
+export default function PreviewPanel({ code }) {
+ const [gameId, setGameId] = useState('');
+ const [submitted, setSubmitted] = useState(false);
+
+ const isValid = uuidRegex.test(gameId);
+
+ const handleClick = () => {
+ if (isValid) {
+ setSubmitted(true);
}
};
- const gameId = gameUrl.trim().split('/').pop();
-
return (
setGameUrl(e.target.value)}
+ placeholder="Game ID (UUID)"
+ value={gameId}
+ onChange={e => { setGameId(e.target.value.trim()); setSubmitted(false); }}
style={{
width: '100%',
padding: '0.5rem',
@@ -75,44 +66,42 @@ export default function PreviewPanel({ code }) {
outline: 'none'
}}
/>
+ {!isValid && gameId && (
+
+ Invalid Game ID format.
+
+ )}
- {/*
-
*/}
-
- {settings && gameId && (
+ {submitted && (
)}
diff --git a/src/pages/CodeEditor.jsx b/src/pages/CodeEditor.jsx
index 054a4d2..4038e47 100644
--- a/src/pages/CodeEditor.jsx
+++ b/src/pages/CodeEditor.jsx
@@ -3,6 +3,8 @@ import { useLocation } from "react-router-dom";
import EditorPanel from "../components/EditorPanel";
import PreviewPanel from "../components/PreviewPanel";
+const ASSIGNMENT_BASE = "http://localhost:8082";
+
export default function PageCodeEditor() {
const location = useLocation();
@@ -12,13 +14,15 @@ export default function PageCodeEditor() {
const [appName, setAppName] = useState("");
const [code, setCode] = useState("# NOW LOADING");
+ const [isSaving, setIsSaving] = useState(false);
+ const [isDeploying, setIsDeploying] = useState(false);
useEffect(() => {
document.title = "Snake Brain Editor";
}, []);
useEffect(() => {
- fetch(`http://localhost:8082/student/assignment/${qrCodeNumber}`)
+ fetch(`${ASSIGNMENT_BASE}/student/assignment/${qrCodeNumber}`)
.then((res) => {
if (!res.ok) throw new Error("Failed to fetch assignment");
return res.json();
@@ -29,7 +33,7 @@ export default function PageCodeEditor() {
useEffect(() => {
if (!appName) return;
- fetch(`http://localhost:8082/notebook/${appName}`)
+ fetch(`${ASSIGNMENT_BASE}/notebook/${appName}`)
.then((res) => {
if (!res.ok) throw new Error("Failed to fetch notebook");
return res.json();
@@ -44,6 +48,44 @@ export default function PageCodeEditor() {
.catch((err) => console.error("Notebook fetch error:", err));
}, [appName]);
+ const handleSave = async () => {
+ if (isSaving) return;
+ setIsSaving(true);
+ try {
+ const res = await fetch(`${ASSIGNMENT_BASE}/student/save`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ appName, code })
+ });
+ if (!res.ok) throw new Error("Save failed");
+ alert("Notebook saved");
+ } catch (err) {
+ console.error("Save error:", err);
+ alert(`Save error: ${err.message}`);
+ } finally {
+ setIsSaving(false);
+ }
+ };
+
+ const handleDeploy = async () => {
+ if (isDeploying) return;
+ setIsDeploying(true);
+ try {
+ const res = await fetch(`${ASSIGNMENT_BASE}/student/restart`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ appName })
+ });
+ if (!res.ok) throw new Error("Restart failed");
+ alert("App restarted");
+ } catch (err) {
+ console.error("Restart error:", err);
+ alert(`Restart error: ${err.message}`);
+ } finally {
+ setIsDeploying(false);
+ }
+ };
+
return (
{/* Python Editor */}
@@ -66,7 +108,7 @@ export default function PageCodeEditor() {
padding: "1rem",
color: "#eee",
minHeight: "80vh",
- overflow: "auto",
+ overflow: "auto"
}}
>
🐍 Snake Brain (Python)
@@ -83,31 +125,38 @@ export default function PageCodeEditor() {
+
+
@@ -121,7 +170,7 @@ export default function PageCodeEditor() {
borderRadius: "12px",
padding: "1rem",
color: "#eee",
- minHeight: "80vh",
+ minHeight: "80vh"
}}
>
🎯 Live Arena Output
@@ -141,7 +190,7 @@ export default function PageCodeEditor() {
style={{
color: "#fff",
textAlign: "center",
- marginBottom: "1rem",
+ marginBottom: "1rem"
}}
>
Battlesnake Preview