From 7facd84b99829ddc75c9a0b7442dac7d04fba5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Fri, 7 Mar 2025 17:32:02 +0100 Subject: [PATCH] first commit --- README.md | 0 backend/index.js | 140 ++++++++++++++++++++++ backend/package.json | 15 +++ frontend/package.json | 18 +++ frontend/src/Admin.js | 205 +++++++++++++++++++++++++++++++++ frontend/src/App.css | 87 ++++++++++++++ frontend/src/App.js | 23 ++++ frontend/src/CampaignDetail.js | 48 ++++++++ frontend/src/HomePage.js | 34 ++++++ frontend/src/Login.js | 64 ++++++++++ 10 files changed, 634 insertions(+) create mode 100644 README.md create mode 100644 backend/index.js create mode 100644 backend/package.json create mode 100644 frontend/package.json create mode 100644 frontend/src/Admin.js create mode 100644 frontend/src/App.css create mode 100644 frontend/src/App.js create mode 100644 frontend/src/CampaignDetail.js create mode 100644 frontend/src/HomePage.js create mode 100644 frontend/src/Login.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/backend/index.js b/backend/index.js new file mode 100644 index 0000000..0951e63 --- /dev/null +++ b/backend/index.js @@ -0,0 +1,140 @@ +const express = require('express'); +const cors = require('cors'); +const bodyParser = require('body-parser'); +const sqlite3 = require('sqlite3').verbose(); + +const app = express(); +app.use(cors()); +app.use(bodyParser.json()); + +const PORT = 4000; +const ADMIN_LOGIN = 'admin'; +const ADMIN_PASSWORD = 'admin123'; + +const db = new sqlite3.Database('./donations.db', (err) => { + if (err) { + console.error('Błąd otwarcia bazy danych', err); + } else { + console.log('Połączono z bazą SQLite.'); + } +}); + +// Tworzenie tabel: campaigns oraz donations +db.serialize(() => { + db.run(` + CREATE TABLE IF NOT EXISTS campaigns ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + title TEXT NOT NULL, + description TEXT NOT NULL, + target REAL NOT NULL + ) + `); + + db.run(` + CREATE TABLE IF NOT EXISTS donations ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + campaign_id INTEGER NOT NULL, + amount REAL NOT NULL, + description TEXT NOT NULL, + date TEXT NOT NULL, + FOREIGN KEY (campaign_id) REFERENCES campaigns(id) + ) + `); +}); + +// ----------------------- +// Endpointy publiczne +// ----------------------- + +// Lista wszystkich kampanii +app.get('/api/campaigns', (req, res) => { + db.all("SELECT * FROM campaigns", (err, rows) => { + if (err) return res.status(500).json({ error: 'Błąd bazy danych' }); + res.json(rows); + }); +}); + +// Pobranie szczegółów kampanii (razem z sumą wpłat) +app.get('/api/campaigns/:id', (req, res) => { + const campaignId = req.params.id; + db.get("SELECT * FROM campaigns WHERE id = ?", [campaignId], (err, campaign) => { + if (err) return res.status(500).json({ error: 'Błąd bazy danych' }); + if (!campaign) return res.status(404).json({ error: 'Kampania nie znaleziona' }); + + db.get( + "SELECT SUM(amount) as totalDonations FROM donations WHERE campaign_id = ?", + [campaignId], + (err, row) => { + if (err) return res.status(500).json({ error: 'Błąd bazy danych' }); + const totalDonations = row.totalDonations || 0; + res.json({ ...campaign, totalDonations }); + } + ); + }); +}); + +// Lista wpłat dla kampanii +app.get('/api/campaigns/:id/donations', (req, res) => { + const campaignId = req.params.id; + db.all("SELECT * FROM donations WHERE campaign_id = ? ORDER BY date DESC", [campaignId], (err, rows) => { + if (err) return res.status(500).json({ error: 'Błąd bazy danych' }); + res.json(rows); + }); +}); + +// ----------------------- +// Endpointy chronione – panel administratora +// ----------------------- + +// Logowanie – bardzo uproszczone +app.post('/api/login', (req, res) => { + const { login, password } = req.body; + if (login === ADMIN_LOGIN && password === ADMIN_PASSWORD) { + res.json({ token: 'admin-session-token-abc123' }); + } else { + res.status(401).json({ error: 'Błędne dane logowania' }); + } +}); + +// Tworzenie nowej kampanii (admin) +app.post('/api/campaigns', (req, res) => { + const { title, description, target, token } = req.body; + if (!token) return res.status(401).json({ error: 'Brak uprawnień' }); + const stmt = db.prepare("INSERT INTO campaigns (title, description, target) VALUES (?, ?, ?)"); + stmt.run(title, description, target, function(err) { + if (err) return res.status(500).json({ error: 'Błąd bazy danych' }); + const newCampaign = { id: this.lastID, title, description, target }; + res.status(201).json(newCampaign); + }); + stmt.finalize(); +}); + +// Aktualizacja celu kampanii (admin) +app.post('/api/campaigns/:id/target', (req, res) => { + const campaignId = req.params.id; + const { newTarget, token } = req.body; + if (!token) return res.status(401).json({ error: 'Brak uprawnień' }); + db.run("UPDATE campaigns SET target = ? WHERE id = ?", [newTarget, campaignId], function(err) { + if (err) return res.status(500).json({ error: 'Błąd bazy danych' }); + res.json({ target: newTarget }); + }); +}); + +// Dodawanie wpłaty do kampanii (admin) +app.post('/api/campaigns/:id/donations', (req, res) => { + const campaignId = req.params.id; + const { amount, description, token } = req.body; + if (!token) return res.status(401).json({ error: 'Brak uprawnień' }); + const date = new Date().toISOString(); + const stmt = db.prepare("INSERT INTO donations (campaign_id, amount, description, date) VALUES (?, ?, ?, ?)"); + stmt.run(campaignId, amount, description, date, function(err) { + if (err) return res.status(500).json({ error: 'Błąd bazy danych' }); + const newDonation = { id: this.lastID, campaign_id: campaignId, amount, description, date }; + res.status(201).json(newDonation); + }); + stmt.finalize(); +}); + +app.listen(PORT, () => { + console.log(`Server działa na porcie ${PORT}`); +}); diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..8c6dbda --- /dev/null +++ b/backend/package.json @@ -0,0 +1,15 @@ +{ + "name": "donation-backend", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "body-parser": "^1.20.2", + "cors": "^2.8.5", + "express": "^4.18.2", + "sqlite3": "^5.1.6" + } + } + \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..ea131c3 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,18 @@ +{ + "name": "donation-frontend", + "version": "1.0.0", + "private": true, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.3.0", + "react-scripts": "5.0.1" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + } + } + \ No newline at end of file diff --git a/frontend/src/Admin.js b/frontend/src/Admin.js new file mode 100644 index 0000000..240faf6 --- /dev/null +++ b/frontend/src/Admin.js @@ -0,0 +1,205 @@ +// Admin.js +import React, { useState, useEffect } from 'react'; +import { useNavigate, Routes, Route, Link, useParams } from 'react-router-dom'; +import './App.css'; + +function AdminHome() { + const [campaigns, setCampaigns] = useState([]); + + useEffect(() => { + fetch('http://localhost:4000/api/campaigns') + .then((res) => res.json()) + .then((data) => setCampaigns(data)) + .catch((err) => console.error(err)); + }, []); + + return ( +
+

Panel Administratora

+ + Dodaj nową zbiórkę + +

Zbiórki

+ +
+ ); +} + +function NewCampaign() { + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); + const [target, setTarget] = useState(''); + const navigate = useNavigate(); + + const handleSubmit = (e) => { + e.preventDefault(); + const token = sessionStorage.getItem('authToken'); + fetch('http://localhost:4000/api/campaigns', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ title, description, target: parseFloat(target), token }), + }) + .then((res) => { + if (!res.ok) throw new Error('Błąd tworzenia zbiórki'); + return res.json(); + }) + .then(() => { + alert('Zbiórka dodana'); + navigate('/admin'); + }) + .catch((err) => alert('Błąd podczas dodawania zbiórki')); + }; + + return ( +
+
+

Dodaj nową zbiórkę

+
+
+ + setTitle(e.target.value)} required /> +
+
+ +