import React, { useEffect, useMemo, useState } from 'react'; import { createRoot } from 'react-dom/client'; import './styles.css'; const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:10000'; function formatDate(date) { if (!date) return 'No deadline'; return new Date(date + 'T00:00:00').toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }); } function isOverdue(task) { if (!task.deadline || task.completed) return false; const today = new Date(); today.setHours(0, 0, 0, 0); return new Date(task.deadline + 'T00:00:00') < today; } function App() { const [tasks, setTasks] = useState([]); const [status, setStatus] = useState('Loading...'); const [filter, setFilter] = useState('all'); const [form, setForm] = useState({ title: '', description: '', subject: '', task_type: 'assignment', priority: 'normal', deadline: '', }); async function loadTasks() { try { const res = await fetch(`${API_URL}/api/tasks`); if (!res.ok) throw new Error('API error'); const data = await res.json(); setTasks(data); setStatus('Connected to backend and PostgreSQL'); } catch (error) { setStatus('Backend is not reachable. Check VITE_API_URL and backend logs.'); } } useEffect(() => { loadTasks(); }, []); async function addTask(event) { event.preventDefault(); if (!form.title.trim()) return; await fetch(`${API_URL}/api/tasks`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form), }); setForm({ title: '', description: '', subject: '', task_type: 'assignment', priority: 'normal', deadline: '' }); loadTasks(); } async function toggleTask(id) { await fetch(`${API_URL}/api/tasks/${id}/toggle`, { method: 'PATCH' }); loadTasks(); } async function deleteTask(id) { await fetch(`${API_URL}/api/tasks/${id}`, { method: 'DELETE' }); loadTasks(); } const stats = useMemo(() => { const total = tasks.length; const completed = tasks.filter(t => t.completed).length; const pending = total - completed; const high = tasks.filter(t => t.priority === 'high' && !t.completed).length; const overdue = tasks.filter(isOverdue).length; return { total, pending, completed, high, overdue }; }, [tasks]); const filteredTasks = tasks.filter((task) => { if (filter === 'pending') return !task.completed; if (filter === 'completed') return task.completed; if (filter === 'high') return task.priority === 'high' && !task.completed; if (filter === 'overdue') return isOverdue(task); return true; }); return (
Final cloud exam project

Student Study Planner

Manage assignments, exams, projects and study deadlines. Data is stored in PostgreSQL, so it survives restarts and redeploys.

Cloud architecture React frontend Node.js backend API PostgreSQL persistent database
Total tasks{stats.total}
Pending{stats.pending}
Completed{stats.completed}
High priority{stats.high}
Overdue{stats.overdue}

Add a study task

Create a clear plan for homework, exams and projects.

{status}
setForm({ ...form, title: e.target.value })} placeholder="Task title, e.g. Prepare Kubernetes defense" /> setForm({ ...form, subject: e.target.value })} placeholder="Subject, e.g. Cloud Technologies" />