From 18765653b623b3100beaf6b25a1456674a714567 Mon Sep 17 00:00:00 2001 From: hlpaa Date: Sat, 15 Nov 2025 20:03:39 -0300 Subject: [PATCH 001/102] adding backend routes --- server/src/server.ts | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/server/src/server.ts b/server/src/server.ts index 6e2597b3..cfc45ad1 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -25,6 +25,7 @@ app.use(express.json()); const studentSet = new StudentSet(); const classes = new Classes(); const dataFile = path.resolve('./data/app-data.json'); +const scripts: any[] = []; // Persistence functions const ensureDataDirectory = (): void => { @@ -451,4 +452,28 @@ app.post('/api/classes/gradeImport/:classId', upload_dir.single('file'), async ( app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); -}); \ No newline at end of file +}); + + +//POST /api/scripts - Create a new script +app.post('/api/scripts', (req: Request, res: Response) => { + const script = { id: Date.now().toString(), ...req.body }; + scripts.push(script); + res.status(201).json(script); +}); + +//GET /api/scripts - Get all scripts +app.get('/api/scripts', (req: Request, res: Response) => { + res.json(scripts); +}); + +//PUT /api/scripts/:id - Update a script +app.put('/api/scripts/:id', (req: Request, res: Response) => { + const { id } = req.params; + const index = scripts.findIndex(r => r.id === id); + + if (index === -1) return res.status(404).json({ error: 'Script not found' }); + + scripts[index] = { ...scripts[index], ...req.body }; + res.json(scripts[index]); +}); From dba030bea69bbf86bf8a4584446248c9b7496cbc Mon Sep 17 00:00:00 2001 From: hlpaa Date: Sat, 15 Nov 2025 20:25:30 -0300 Subject: [PATCH 002/102] adding classes and methos to create, get by id and update a scirpt --- server/src/models/Script.ts | 32 ++++++++++++++++++++++++++++++++ server/src/models/Scritps.ts | 28 ++++++++++++++++++++++++++++ server/src/server.ts | 25 ++++++++++++++----------- 3 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 server/src/models/Script.ts create mode 100644 server/src/models/Scritps.ts diff --git a/server/src/models/Script.ts b/server/src/models/Script.ts new file mode 100644 index 00000000..e85e2efa --- /dev/null +++ b/server/src/models/Script.ts @@ -0,0 +1,32 @@ +export class Script { + private id: string; + public title?: string; + public content?: any; + + constructor(id: string, title?: string, content?: any) { + this.id = id; + this.title = title; + this.content = content; + } + + getId(): string { + return this.id; + } + + toJSON() { + return { + id: this.id, + title: this.title, + content: this.content + }; + } + + update(data: Partial<{ title: any; content: any }>) { + if (data.title !== undefined) this.title = data.title; + if (data.content !== undefined) this.content = data.content; + } + + static fromJSON(obj: any): Script { + return new Script(obj.id, obj.title, obj.content); + } +} \ No newline at end of file diff --git a/server/src/models/Scritps.ts b/server/src/models/Scritps.ts new file mode 100644 index 00000000..81ec50dd --- /dev/null +++ b/server/src/models/Scritps.ts @@ -0,0 +1,28 @@ +import { Script } from './Script'; + +export class Scripts { + private items: Script[] = []; + + addScript(data: any): Script { + const id = data.id ?? Date.now().toString(); + const script = new Script(id, data.title, data.content); + this.items.push(script); + return script; + } + + getAllScripts(): Script[] { + return this.items; + } + + findById(id: string): Script | undefined { + return this.items.find(s => s.getId() === id); + } + + updateScript(id: string, data: any): Script | undefined { + const script = this.findById(id); + if (!script) return undefined; + script.update(data); + return script; + } + +} \ No newline at end of file diff --git a/server/src/server.ts b/server/src/server.ts index cfc45ad1..5a449583 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -5,6 +5,7 @@ import { Student } from './models/Student'; import { Evaluation } from './models/Evaluation'; import { Classes } from './models/Classes'; import { Class } from './models/Class'; +import { Scripts } from './models/Scritps'; import * as fs from 'fs'; import * as path from 'path'; @@ -25,7 +26,7 @@ app.use(express.json()); const studentSet = new StudentSet(); const classes = new Classes(); const dataFile = path.resolve('./data/app-data.json'); -const scripts: any[] = []; +const scripts = new Scripts(); // Persistence functions const ensureDataDirectory = (): void => { @@ -457,23 +458,25 @@ app.listen(PORT, () => { //POST /api/scripts - Create a new script app.post('/api/scripts', (req: Request, res: Response) => { - const script = { id: Date.now().toString(), ...req.body }; - scripts.push(script); + const script = scripts.addScript(req.body); res.status(201).json(script); }); -//GET /api/scripts - Get all scripts -app.get('/api/scripts', (req: Request, res: Response) => { - res.json(scripts); +//GET /api/scripts/:id - Get one script by ID +app.get('/api/scripts/:id', (req: Request, res: Response) => { + const { id } = req.params; + const script = scripts.findById(id); + if (!script) { + return res.status(404).json({ error: 'Script not found' }); + } + res.json(script.toJSON()); }); //PUT /api/scripts/:id - Update a script app.put('/api/scripts/:id', (req: Request, res: Response) => { const { id } = req.params; - const index = scripts.findIndex(r => r.id === id); - - if (index === -1) return res.status(404).json({ error: 'Script not found' }); + const script = scripts.updateScript(id, req.body); - scripts[index] = { ...scripts[index], ...req.body }; - res.json(scripts[index]); + if (!script) return res.status(404).json({ error: 'Script not found' }); + res.json(script.toJSON()); }); From e0f7a23965d6a3d4fe076f8f2a6bccfcac4da0f2 Mon Sep 17 00:00:00 2001 From: hlpaa Date: Sun, 16 Nov 2025 14:19:44 -0300 Subject: [PATCH 003/102] adding frontend infra to implement scripts functionality --- client/src/App.tsx | 31 ++++-- client/src/components/Scripts.tsx | 151 +++++++++++++++++++++++++++ client/src/services/ScriptService.ts | 46 ++++++++ client/src/types/Script.ts | 24 +++++ 4 files changed, 242 insertions(+), 10 deletions(-) create mode 100644 client/src/components/Scripts.tsx create mode 100644 client/src/services/ScriptService.ts create mode 100644 client/src/types/Script.ts diff --git a/client/src/App.tsx b/client/src/App.tsx index 86a0962e..da9c835f 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,15 +1,16 @@ -import React, { useState, useEffect, useCallback } from 'react'; -import { Student } from './types/Student'; -import { Class } from './types/Class'; -import { studentService } from './services/StudentService'; -import ClassService from './services/ClassService'; -import StudentList from './components/StudentList'; -import StudentForm from './components/StudentForm'; -import Evaluations from './components/Evaluations'; -import Classes from './components/Classes'; +import React, { useCallback, useEffect, useState } from 'react'; import './App.css'; +import Classes from './components/Classes'; +import Evaluations from './components/Evaluations'; +import Scripts from './components/Scripts'; +import StudentForm from './components/StudentForm'; +import StudentList from './components/StudentList'; +import ClassService from './services/ClassService'; +import { studentService } from './services/StudentService'; +import { Class } from './types/Class'; +import { Student } from './types/Student'; -type TabType = 'students' | 'evaluations' | 'classes'; +type TabType = 'students' | 'evaluations' | 'classes' | 'scripts'; const App: React.FC = () => { const [students, setStudents] = useState([]); @@ -143,6 +144,12 @@ const App: React.FC = () => { > Classes + {/* Tab Content */} @@ -212,6 +219,10 @@ const App: React.FC = () => { onError={handleError} /> )} + + {activeTab === 'scripts' && ( + + )} diff --git a/client/src/components/Scripts.tsx b/client/src/components/Scripts.tsx new file mode 100644 index 00000000..270a327f --- /dev/null +++ b/client/src/components/Scripts.tsx @@ -0,0 +1,151 @@ +import React, { useState } from 'react'; +import ScriptService from '../services/ScriptService'; +import { CreateScriptRequest, Script, UpdateScriptRequest, isValidJSON } from '../types/Script'; + +interface Props { + onError: (msg: string) => void; +} + +const Scripts: React.FC = ({ onError }) => { + const [loading, setLoading] = useState(false); + const [message, setMessage] = useState(''); + + // Create form + const [createTitle, setCreateTitle] = useState(''); + const [createContentText, setCreateContentText] = useState(''); + + // Load/update + const [scriptIdToLoad, setScriptIdToLoad] = useState(''); + const [loadedScript, setLoadedScript] = useState