src/
├── components/
│ ├── Auth/
│ │ ├── Register.jsx
│ │ ├── Login.jsx
│ │ └── index.jsx
│ └── ChildrenManagement.jsx
├── App.jsx
└── main.jsx
APP.JSX
// src/App.js
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate, Link } from
'react-router-dom';
import Register from './components/Auth/Register.jsx';
import Login from './components/Auth/Login.jsx';
import ChildrenManagement from './components/ChildrenManagement';
// Protected Route Component
const ProtectedRoute = ({ children }) => {
const token = localStorage.getItem('token');
if (!token) {
return <Navigate to="/login" />;
}
return children;
};
// Navigation Component
const Navigation = () => {
const token = localStorage.getItem('token');
const handleLogout = () => {
localStorage.removeItem('token');
localStorage.removeItem('userId');
window.location.href = '/login';
};
return (
<nav className="bg-gray-800 text-white p-4">
<div className="max-w-6xl mx-auto flex justify-between items-
center">
<Link to="/" className="text-xl font-bold">
Children Manager
</Link>
<div className="space-x-4">
{!token ? (
<>
<Link to="/login" className="hover:text-gray-300">
Login
</Link>
<Link to="/register" className="hover:text-gray-300">
Register
</Link>
</>
) : (
<>
<Link to="/children" className="hover:text-gray-300">
Children
</Link>
<button
onClick={handleLogout}
className="hover:text-gray-300"
>
Logout
</button>
</>
)}
</div>
</div>
</nav>
);
};
// Home Component
const Home = () => {
return (
<div className="max-w-4xl mx-auto mt-10 p-6 text-center">
<h1 className="text-4xl font-bold mb-4">Welcome to Children
Manager</h1>
<p className="text-xl text-gray-600 mb-8">
Manage your children's information easily and securely.
</p>
{!localStorage.getItem('token') && (
<div className="space-x-4">
<Link
to="/register"
className="bg-blue-500 text-white px-6 py-2 rounded hover:bg-
blue-600"
>
Get Started
</Link>
<Link
to="/login"
className="bg-gray-500 text-white px-6 py-2 rounded hover:bg-
gray-600"
>
Login
</Link>
</div>
)}
</div>
);
};
// Main App Component
const App = () => {
return (
<Router>
<div className="min-h-screen bg-gray-100">
<Navigation />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/register" element={<Register />} />
<Route path="/login" element={<Login />} />
<Route
path="/children"
element={
<ProtectedRoute>
<ChildrenManagement />
</ProtectedRoute>
}
/>
</Routes>
</div>
</Router>
);
};
export default App;
MAIN.JSX
// src/main.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
// Include Tailwind CSS
import 'tailwindcss/tailwind.css';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
ChildrenManagement.jsx
// src/components/ChildrenManagement.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const ChildrenManagement = () => {
const [children, setChildren] = useState([]);
const [newChild, setNewChild] = useState('');
const [editingChild, setEditingChild] = useState(null);
const [error, setError] = useState('');
const [loading, setLoading] = useState(true);
const [successMessage, setSuccessMessage] = useState('');
const token = localStorage.getItem('token');
const axiosConfig = {
headers: { Authorization: `Bearer ${token}` }
};
useEffect(() => {
fetchChildren();
}, []);
const fetchChildren = async () => {
try {
setLoading(true);
const response = await
axios.get('http://localhost:5000/api/children', axiosConfig);
setChildren(response.data);
setError('');
} catch (err) {
setError('Failed to fetch children');
} finally {
setLoading(false);
}
};
const addChild = async (e) => {
e.preventDefault();
if (!newChild.trim()) {
setError("Child's name cannot be empty");
return;
}
try {
await axios.post('http://localhost:5000/api/children',
{ children_name: newChild },
axiosConfig
);
setNewChild('');
setSuccessMessage('Child added successfully!');
setTimeout(() => setSuccessMessage(''), 3000);
fetchChildren();
} catch (err) {
setError('Failed to add child');
}
};
const updateChild = async (id, newName) => {
if (!newName.trim()) {
setError("Child's name cannot be empty");
return;
}
try {
await axios.put(`http://localhost:5000/api/children/${id}`,
{ children_name: newName },
axiosConfig
);
setEditingChild(null);
setSuccessMessage('Child updated successfully!');
setTimeout(() => setSuccessMessage(''), 3000);
fetchChildren();
} catch (err) {
setError('Failed to update child');
}
};
const deleteChild = async (id) => {
if (window.confirm('Are you sure you want to delete this child?')) {
try {
await axios.delete(`http://localhost:5000/api/children/${id}`,
axiosConfig);
setSuccessMessage('Child deleted successfully!');
setTimeout(() => setSuccessMessage(''), 3000);
fetchChildren();
} catch (err) {
setError('Failed to delete child');
}
}
};
const handleKeyPress = (e, id, name) => {
if (e.key === 'Enter') {
updateChild(id, name);
} else if (e.key === 'Escape') {
setEditingChild(null);
}
};
if (loading) {
return (
<div className="max-w-2xl mx-auto mt-10 p-6 bg-white rounded-lg
shadow-lg">
<div className="text-center text-gray-600">Loading...</div>
</div>
);
}
return (
<div className="max-w-2xl mx-auto mt-10 p-6 bg-white rounded-lg
shadow-lg">
<h2 className="text-2xl font-bold mb-6">Children Management</h2>
{error && <div className="text-red-500 mb-4 p-2 bg-red-50
rounded">{error}</div>}
{successMessage && (
<div className="text-green-500 mb-4 p-2 bg-green-50
rounded">{successMessage}</div>
)}
{/* Add Child Form */}
<form onSubmit={addChild} className="mb-6">
<div className="flex gap-2">
<input
type="text"
placeholder="Child's Name"
className="flex-1 p-2 border rounded"
value={newChild}
onChange={(e) => setNewChild(e.target.value)}
/>
<button
type="submit"
className="bg-green-500 text-white px-4 py-2 rounded
hover:bg-green-600 transition duration-200"
>
Add Child
</button>
</div>
</form>
{/* Children List */}
<div className="space-y-4">
{children.length === 0 ? (
<div className="text-center text-gray-500 py-4">
No children added yet. Add your first child above!
</div>
) : (
children.map((child) => (
<div key={child.id} className="flex items-center justify-
between p-4 border rounded hover:bg-gray-50">
{editingChild === child.id ? (
<input
type="text"
className="flex-1 p-2 border rounded mr-2"
value={child.children_name}
onChange={(e) => {
const updatedChildren = children.map(c =>
c.id === child.id ? { ...c, children_name:
e.target.value } : c
);
setChildren(updatedChildren);
}}
onBlur={() => updateChild(child.id,
child.children_name)}
onKeyDown={(e) => handleKeyPress(e, child.id,
child.children_name)}
autoFocus
/>
) : (
<div>
<span className="font-
medium">#{child.children_number}</span>
<span className="ml-4">{child.children_name}</span>
</div>
)}
<div className="flex gap-2">
<button
onClick={() => setEditingChild(child.id)}
className="bg-blue-500 text-white px-3 py-1 rounded
hover:bg-blue-600 transition duration-200"
>
Edit
</button>
<button
onClick={() => deleteChild(child.id)}
className="bg-red-500 text-white px-3 py-1 rounded
hover:bg-red-600 transition duration-200"
>
Delete
</button>
</div>
</div>
))
)}
</div>
</div>
);
};
export default ChildrenManagement;
index.jsx
// src/components/Auth/index.js
export { default as Register } from './Register';
export { default as Login } from './Login';
Login.jsx
// src/components/Auth/Login.js
import React, { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
const Login = () => {
const [formData, setFormData] = useState({
email: '',
password: ''
});
const [error, setError] = useState('');
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await
axios.post('http://localhost:5000/api/login', formData);
localStorage.setItem('token', response.data.token);
localStorage.setItem('userId', response.data.userId);
navigate('/children');
} catch (err) {
setError(err.response?.data?.error || 'Login failed');
}
};
return (
<div className="max-w-md mx-auto mt-10 p-6 bg-white rounded-lg
shadow-lg">
<h2 className="text-2xl font-bold mb-6">Login</h2>
{error && <div className="text-red-500 mb-4">{error}</div>}
<form onSubmit={handleSubmit}>
<div className="mb-4">
<input
type="email"
placeholder="Email"
className="w-full p-2 border rounded"
value={formData.email}
onChange={(e) => setFormData({...formData, email:
e.target.value})}
/>
</div>
<div className="mb-4">
<input
type="password"
placeholder="Password"
className="w-full p-2 border rounded"
value={formData.password}
onChange={(e) => setFormData({...formData, password:
e.target.value})}
/>
</div>
<button
type="submit"
className="w-full bg-blue-500 text-white p-2 rounded hover:bg-
blue-600"
>
Login
</button>
</form>
</div>
);
};
export default Login;
Register.jsx
// src/components/Auth/Register.js
import React, { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
const Register = () => {
const [formData, setFormData] = useState({
username: '',
email: '',
password: ''
});
const [error, setError] = useState('');
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
try {
await axios.post('http://localhost:5000/api/register', formData);
navigate('/login');
} catch (err) {
setError(err.response?.data?.error || 'Registration failed');
}
};
return (
<div className="max-w-md mx-auto mt-10 p-6 bg-white rounded-lg
shadow-lg">
<h2 className="text-2xl font-bold mb-6">Register</h2>
{error && <div className="text-red-500 mb-4">{error}</div>}
<form onSubmit={handleSubmit}>
<div className="mb-4">
<input
type="text"
placeholder="Username"
className="w-full p-2 border rounded"
value={formData.username}
onChange={(e) => setFormData({...formData, username:
e.target.value})}
/>
</div>
<div className="mb-4">
<input
type="email"
placeholder="Email"
className="w-full p-2 border rounded"
value={formData.email}
onChange={(e) => setFormData({...formData, email:
e.target.value})}
/>
</div>
<div className="mb-4">
<input
type="password"
placeholder="Password"
className="w-full p-2 border rounded"
value={formData.password}
onChange={(e) => setFormData({...formData, password:
e.target.value})}
/>
</div>
<button
type="submit"
className="w-full bg-blue-500 text-white p-2 rounded hover:bg-
blue-600"
>
Register
</button>
</form>
</div>
);
};
export default Register;
server.js
const express = require('express');
const mysql = require('mysql2');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const cors = require('cors');
const app = express();
app.use(express.json());
app.use(cors());
const db = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'testdb'
});
// User Registration
app.post('/api/register', async (req, res) => {
try {
const { username, email, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const query = 'INSERT INTO users (username, email, password)
VALUES (?, ?, ?)';
db.query(query, [username, email, hashedPassword], (err, result)
=> {
if (err) {
return res.status(400).json({ error: 'Username or email
already exists' });
}
res.status(201).json({ message: 'User registered
successfully' });
});
} catch (error) {
res.status(500).json({ error: 'Server error' });
}
});
// User Login
app.post('/api/login', async (req, res) => {
try {
const { email, password } = req.body;
const query = 'SELECT * FROM users WHERE email = ?';
db.query(query, [email], async (err, results) => {
if (err || results.length === 0) {
return res.status(401).json({ error: 'Invalid
credentials' });
}
const user = results[0];
const validPassword = await bcrypt.compare(password,
user.password);
if (!validPassword) {
return res.status(401).json({ error: 'Invalid
credentials' });
}
const token = jwt.sign({ userId: user.id },
'your_jwt_secret', { expiresIn: '24h' });
res.json({ token, userId: user.id });
});
} catch (error) {
res.status(500).json({ error: 'Server error' });
}
});
// Middleware to verify JWT token
const authenticateToken = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Access denied' });
jwt.verify(token, 'your_jwt_secret', (err, user) => {
if (err) return res.status(403).json({ error: 'Invalid token' });
req.user = user;
next();
});
};
// Get all children for a user
app.get('/api/children', authenticateToken, (req, res) => {
const query = 'SELECT * FROM children WHERE user_id = ? ORDER BY
children_number';
db.query(query, [req.user.userId], (err, results) => {
if (err) return res.status(500).json({ error: 'Server error' });
res.json(results);
});
});
// Add a new child
app.post('/api/children', authenticateToken, (req, res) => {
const { children_name } = req.body;
// Get the next children_number
db.query(
'SELECT MAX(children_number) as max_num FROM children WHERE
user_id = ?',
[req.user.userId],
(err, results) => {
if (err) return res.status(500).json({ error: 'Server
error' });
const nextNumber = (results[0].max_num || 0) + 1;
const query = 'INSERT INTO children (user_id, children_name,
children_number) VALUES (?, ?, ?)';
db.query(query, [req.user.userId, children_name, nextNumber],
(err, result) => {
if (err) return res.status(500).json({ error: 'Server
error' });
res.status(201).json({ id: result.insertId,
children_number: nextNumber });
});
}
);
});
// Update a child
app.put('/api/children/:id', authenticateToken, (req, res) => {
const { children_name } = req.body;
const query = 'UPDATE children SET children_name = ? WHERE id = ? AND
user_id = ?';
db.query(query, [children_name, req.params.id, req.user.userId],
(err, result) => {
if (err) return res.status(500).json({ error: 'Server error' });
if (result.affectedRows === 0) return res.status(404).json({
error: 'Child not found' });
res.json({ message: 'Child updated successfully' });
});
});
// Delete a child
app.delete('/api/children/:id', authenticateToken, (req, res) => {
const query = 'DELETE FROM children WHERE id = ? AND user_id = ?';
db.query(query, [req.params.id, req.user.userId], (err, result) => {
if (err) return res.status(500).json({ error: 'Server error' });
if (result.affectedRows === 0) return res.status(404).json({
error: 'Child not found' });
res.json({ message: 'Child deleted successfully' });
});
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));