DOVE CG Tech frontend
Ekemini Thompson is a Machine Learning Engineer and Data Scientist, specializing in AI solutions, predictive analytics, and healthcare innovations, with a passion for leveraging technology to solve real-world problems.
Step-by-Step Instructions for Beginners
Open Your Project:
Open VS Code.
Click File > Open Folder and select your dove-cg-tech folder.
In the file explorer (left side), open the frontend folder to see public and src.
Create New Folders:
In frontend/src, right-click src, select New Folder, and create:
api
context
hooks
redux
utils
Inside components, create: auth, company, courses, payments, dashboard, certificates
Inside pages, create: company, courses, dashboard, payments, certificates, cart
Inside redux, create: slices
In frontend/public, right-click public, select New Folder, and create assets.
Inside assets, create: images, fonts.
Create/Update Files:
For each file below, navigate to the specified folder in the file explorer.
To create a file: Right-click the folder, select New File, name it exactly as shown, paste the code, and save (Ctrl+S or Cmd+S).
To update a file: Open the existing file, replace its content with the provided code, and save.
Install New Dependencies:
Open a terminal in VS Code (Terminal > New Terminal).
Ensure you’re in the frontend folder (type cd frontend if needed).
Run: npm install @reduxjs/toolkit react-redux
Verify existing dependencies (react, react-dom, react-router-dom@6, axios, @mui/material, @mui/icons-material, @emotion/react, @emotion/styled, framer-motion) are installed. If not, run:
npm install react react-dom react-router-dom@6 axios @mui/material @mui/icons-material @emotion/react @emotion/styled framer-motionTest Your Website:
- In the terminal, type: npm start
Your browser should open to http://localhost:3000.
Check the navbar, home page, login/register pages, and try a wrong URL (e.g., /random) to see the 404 page.
If errors appear, check the terminal or browser console (right-click page > Inspect > Console).
Code Files
1. Update public/index.html
Location: frontend/public/index.html Purpose: Sets up the webpage with a dark background and root div for React.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#121212" />
<meta name="description" content="DOVE CG Tech - Corporate eLearning Platform" />
<title>DOVE CG Tech</title>
</head>
<body style="background-color: #121212; margin: 0;">
<div id="root"></div>
</body>
</html>
How to Update:
Open frontend/public/index.html in the file explorer.
Replace its content with the code above.
Save.
2. Update src/styles/global.css
Location: frontend/src/styles/global.css Purpose: Defines the black, green, and yellow color scheme.
:root {
--black-primary: #121212;
--black-secondary: #1A1A1A;
--green-primary: #00FF7F;
--green-secondary: #2ECC71;
--yellow-primary: #FFD700;
--yellow-secondary: #F1C40F;
--text-light: #E0E0E0;
--text-muted: #AAAAAA;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--black-primary);
color: var(--text-light);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
a {
text-decoration: none;
color: var(--green-primary);
}
button {
cursor: pointer;
}
How to Update:
Open frontend/src/styles/global.css.
Replace its content with the code above.
Save.
3. Update src/components/ui/Navbar.js
Location: frontend/src/components/ui/Navbar.js Purpose: Navigation bar with dynamic buttons based on auth state, using the new MUI theme and auth hook.
import React from 'react';
import { AppBar, Toolbar, Typography, Button, Box } from '@mui/material';
import { styled } from '@mui/material/styles';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../../hooks/useAuth';
const StyledAppBar = styled(AppBar)(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
color: theme.palette.primary.main,
}));
const NavButton = styled(Button)(({ theme }) => ({
color: theme.palette.text.primary,
'&:hover': {
color: theme.palette.primary.main,
backgroundColor: 'rgba(0, 255, 127, 0.1)',
},
}));
const Navbar = () => {
const { user, logout } = useAuth();
const navigate = useNavigate();
return (
<StyledAppBar position="static">
<Toolbar>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
DOVE CG Tech
</Typography>
<Box>
<NavButton onClick={() => navigate('/')}>Home</NavButton>
<NavButton onClick={() => navigate('/courses')}>Courses</NavButton>
<NavButton onClick={() => navigate('/company')}>Company</NavButton>
{user ? (
<>
<NavButton onClick={() => navigate('/dashboard')}>Dashboard</NavButton>
<NavButton onClick={() => { logout(); navigate('/'); }}>Logout</NavButton>
</>
) : (
<>
<NavButton onClick={() => navigate('/login')}>Login</NavButton>
<NavButton
variant="contained"
onClick={() => navigate('/register')}
sx={{
backgroundColor: 'var(--green-primary)',
color: 'var(--black-primary)',
'&:hover': { backgroundColor: 'var(--green-secondary)' },
}}
>
Sign Up
</NavButton>
</>
)}
</Box>
</Toolbar>
</StyledAppBar>
);
};
export default Navbar;
How to Update:
Open frontend/src/components/ui/Navbar.js.
Replace its content with the code above.
Save.
4. Update src/components/ui/Footer.js
Location: frontend/src/components/ui/Footer.js Purpose: Footer with links and copyright, styled with the new theme.
import React from 'react';
import { Box, Typography, Container, Link } from '@mui/material';
import { styled } from '@mui/material/styles';
const FooterContainer = styled(Box)({
backgroundColor: 'var(--black-secondary)',
color: 'var(--text-light)',
padding: '20px 0',
marginTop: 'auto',
borderTop: '1px solid var(--green-primary)',
});
const Footer = () => {
return (
<FooterContainer component="footer">
<Container maxWidth="lg">
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
flexWrap: 'wrap',
gap: 2,
}}
>
<Typography variant="body2">
© {new Date().getFullYear()} DOVE CG Tech. All rights reserved.
</Typography>
<Box sx={{ display: 'flex', gap: 2 }}>
<Link
href="/about"
sx={{
color: 'var(--green-primary)',
'&:hover': { color: 'var(--yellow-primary)' },
}}
>
About
</Link>
<Link
href="/contact"
sx={{
color: 'var(--green-primary)',
'&:hover': { color: 'var(--yellow-primary)' },
}}
>
Contact
</Link>
<Link
href="/privacy"
sx={{
color: 'var(--green-primary)',
'&:hover': { color: 'var(--yellow-primary)' },
}}
>
Privacy Policy
</Link>
</Box>
</Box>
</Container>
</FooterContainer>
);
};
export default Footer;
How to Update:
Open frontend/src/components/ui/Footer.js.
Replace its content with the code above.
Save.
5. Update src/pages/Home.js
Location: frontend/src/pages/Home.js Purpose: Home page with a hero section, updated to use the MUI theme.
import React from 'react';
import { Box, Typography, Button, Container } from '@mui/material';
import { styled } from '@mui/material/styles';
const HeroSection = styled(Box)(({ theme }) => ({
minHeight: '80vh',
background: 'linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)), url(/assets/hero-bg.jpg)',
backgroundSize: 'cover',
backgroundPosition: 'center',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center',
color: theme.palette.text.primary,
}));
const Home = () => {
return (
<HeroSection>
<Container maxWidth="md">
<Typography variant="h2" component="h1" gutterBottom sx={{ fontWeight: 'bold', color: 'var(--green-primary)' }}>
Transform Your Workforce with DOVE CG Tech
</Typography>
<Typography variant="h5" component="p" gutterBottom sx={{ mb: 4 }}>
Cutting-edge eLearning solutions for corporate excellence
</Typography>
<Button
variant="contained"
size="large"
sx={{
bgcolor: 'var(--green-primary)',
color: 'var(--black-primary)',
fontWeight: 'bold',
px: 4,
py: 2,
'&:hover': {
bgcolor: 'var(--green-secondary)',
boxShadow: '0 0 15px var(--yellow-primary)',
}
}}
>
Explore Courses
</Button>
</Container>
</HeroSection>
);
};
export default Home;
How to Update:
Open frontend/src/pages/Home.js.
Replace its content with the code above.
Save.
6. Update src/pages/auth/Client/Login.js
Location: frontend/src/pages/auth/Client/Login.js Purpose: Login page with API integration and auth context.
import React, { useState } from 'react';
import { Box, Typography, TextField, Button, Container, CircularProgress } from '@mui/material';
import { styled } from '@mui/material/styles';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../../../hooks/useAuth';
import { login } from '../../../api/auth';
const LoginContainer = styled(Box)({
minHeight: '80vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '20px',
});
const LoginForm = styled(Box)(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
padding: '40px',
borderRadius: '8px',
boxShadow: `0 0 10px ${theme.palette.primary.main}`,
width: '100%',
maxWidth: '400px',
}));
const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const { login: authLogin } = useAuth();
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
const data = await login(email, password);
authLogin(email, data.token);
navigate('/dashboard');
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
return (
<LoginContainer>
<Container maxWidth="sm">
<LoginForm component="form" onSubmit={handleSubmit}>
<Typography
variant="h4"
component="h1"
gutterBottom
sx={{ color: 'var(--green-primary)', textAlign: 'center' }}
>
Login
</Typography>
{error && (
<Typography color="error" sx={{ mb: 2, textAlign: 'center' }}>
{error}
</Typography>
)}
<TextField
label="Email"
variant="outlined"
fullWidth
margin="normal"
value={email}
onChange={(e) => setEmail(e.target.value)}
sx={{ '& .MuiInputLabel-root': { color: 'var(--text-muted)' } }}
/>
<TextField
label="Password"
type="password"
variant="outlined"
fullWidth
margin="normal"
value={password}
onChange={(e) => setPassword(e.target.value)}
sx={{ '& .MuiInputLabel-root': { color: 'var(--text-muted)' } }}
/>
<Button
variant="contained"
fullWidth
type="submit"
disabled={loading}
sx={{
mt: 2,
py: 1.5,
bgcolor: 'var(--green-primary)',
color: 'var(--black-primary)',
'&:hover': { bgcolor: 'var(--green-secondary)' },
}}
>
{loading ? <CircularProgress size={24} color="inherit" /> : 'Sign In'}
</Button>
</LoginForm>
</Container>
</LoginContainer>
);
};
export default Login;
How to Update:
Open frontend/src/pages/auth/Client/Login.js.
Replace its content with the code above.
Save.
7. Update src/pages/auth/Client/Register.js
Location: frontend/src/pages/auth/Client/Register.js Purpose: Registration page with API integration.
import React, { useState } from 'react';
import { Box, Typography, TextField, Button, Container, CircularProgress } from '@mui/material';
import { styled } from '@mui/material/styles';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../../../hooks/useAuth';
import { register } from '../../../api/auth';
const RegisterContainer = styled(Box)({
minHeight: '80vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '20px',
});
const RegisterForm = styled(Box)(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
padding: '40px',
borderRadius: '8px',
boxShadow: `0 0 10px ${theme.palette.primary.main}`,
width: '100%',
maxWidth: '400px',
}));
const Register = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const { login: authLogin } = useAuth();
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
const data = await register(name, email, password);
authLogin(email, data.token);
navigate('/dashboard');
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
return (
<RegisterContainer>
<Container maxWidth="sm">
<RegisterForm component="form" onSubmit={handleSubmit}>
<Typography
variant="h4"
component="h1"
gutterBottom
sx={{ color: 'var(--green-primary)', textAlign: 'center' }}
>
Register
</Typography>
{error && (
<Typography color="error" sx={{ mb: 2, textAlign: 'center' }}>
{error}
</Typography>
)}
<TextField
label="Full Name"
variant="outlined"
fullWidth
margin="normal"
value={name}
onChange={(e) => setName(e.target.value)}
sx={{ '& .MuiInputLabel-root': { color: 'var(--text-muted)' } }}
/>
<TextField
label="Email"
variant="outlined"
fullWidth
margin="normal"
value={email}
onChange={(e) => setEmail(e.target.value)}
sx={{ '& .MuiInputLabel-root': { color: 'var(--text-muted)' } }}
/>
<TextField
label="Password"
type="password"
variant="outlined"
fullWidth
margin="normal"
value={password}
onChange={(e) => setPassword(e.target.value)}
sx={{ '& .MuiInputLabel-root': { color: 'var(--text-muted)' } }}
/>
<Button
variant="contained"
fullWidth
type="submit"
disabled={loading}
sx={{
mt: 2,
py: 1.5,
bgcolor: 'var(--green-primary)',
color: 'var(--black-primary)',
'&:hover': { bgcolor: 'var(--green-secondary)' },
}}
>
{loading ? <CircularProgress size={24} color="inherit" /> : 'Sign Up'}
</Button>
</RegisterForm>
</Container>
</RegisterContainer>
);
};
export default Register;
How to Update:
Open frontend/src/pages/auth/Client/Register.js.
Replace its content with the code above.
Save.
8. Update src/App.js
Location: frontend/src/App.js Purpose: Main app structure with Redux, MUI theme, and new routes.
import React from 'react';
import { Provider } from 'react-redux';
import { ThemeProvider } from '@mui/material/styles';
import { AuthProvider } from './context/authContext';
import store from './redux/store';
import theme from './styles/theme';
import AppRoutes from './routes';
import Navbar from './components/ui/Navbar';
import Footer from './components/ui/Footer';
import './styles/global.css';
function App() {
return (
<Provider store={store}>
<ThemeProvider theme={theme}>
<AuthProvider>
<div className="app" style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
<Navbar />
<main style={{ flex: 1 }}>
<AppRoutes />
</main>
<Footer />
</div>
</AuthProvider>
</ThemeProvider>
</Provider>
);
}
export default App;
How to Update:
Open frontend/src/App.js.
Replace its content with the code above.
Save.
9. Update src/index.js
Location: frontend/src/index.js Purpose: Renders the app with React 18’s createRoot.
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
How to Update:
Open frontend/src/index.js.
Replace its content with the code above.
Save.
10. Create src/api/auth.js
Location: frontend/src/api/auth.js Purpose: Handles API calls for login and registration.
import axios from 'axios';
const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';
export const login = async (email, password) => {
try {
const response = await axios.post(`${API_URL}/auth/login`, { email, password });
return response.data;
} catch (error) {
throw error.response?.data?.message || 'Login failed';
}
};
export const register = async (name, email, password) => {
try {
const response = await axios.post(`${API_URL}/auth/register`, { name, email, password });
return response.data;
} catch (error) {
throw error.response?.data?.message || 'Registration failed';
}
};
How to Create:
In frontend/src/api, right-click, select New File, name it auth.js.
Paste the code above.
Save.
11. Create src/context/authContext.js
Location: frontend/src/context/authContext.js Purpose: Manages user authentication state.
import React, { createContext, useState, useEffect } from 'react';
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const token = localStorage.getItem('token');
if (token) {
setUser({ token });
}
setLoading(false);
}, []);
const login = async (email, password) => {
// Use api/auth.js login function
setUser({ email, token: 'dummy-token' });
localStorage.setItem('token', 'dummy-token');
};
const logout = () => {
setUser(null);
localStorage.removeItem('token');
};
return (
<AuthContext.Provider value={{ user, loading, login, logout }}>
{children}
</AuthContext.Provider>
);
};
How to Create:
In frontend/src/context, right-click, select New File, name it authContext.js.
Paste the code above.
Save.
12. Create src/hooks/useAuth.js
Location: frontend/src/hooks/useAuth.js Purpose: Custom hook to access auth context.
import { useContext } from 'react';
import { AuthContext } from '../context/authContext';
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};
How to Create:
In frontend/src/hooks, right-click, select New File, name it useAuth.js.
Paste the code above.
Save.
13. Create src/styles/theme.js
Location: frontend/src/styles/theme.js Purpose: MUI theme with black, green, yellow colors.
import { createTheme } from '@mui/material/styles';
const theme = createTheme({
palette: {
primary: {
main: '#00FF7F', // Green
},
secondary: {
main: '#FFD700', // Yellow
},
background: {
default: '#121212', // Black
paper: '#1A1A1A', // Darker black
},
text: {
primary: '#E0E0E0', // Light text
secondary: '#AAAAAA', // Muted text
},
},
typography: {
fontFamily: "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif",
},
});
export default theme;
How to Create:
In frontend/src/styles, right-click, select New File, name it theme.js.
Paste the code above.
Save.
14. Create src/routes.js
Location: frontend/src/routes.js Purpose: Centralizes routing configuration.
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import Login from './pages/auth/Client/Login';
import Register from './pages/auth/Client/Register';
import NotFound from './pages/404';
const AppRoutes = () => (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="*" element={<NotFound />} />
</Routes>
);
export default AppRoutes;
How to Create:
In frontend/src, right-click, select New File, name it routes.js.
Paste the code above.
Save.
15. Create src/pages/404.js
Location: frontend/src/pages/404.js Purpose: Displays a "Page Not Found" page.
import React from 'react';
import { Box, Typography, Button, Container } from '@mui/material';
import { styled } from '@mui/material/styles';
import { useNavigate } from 'react-router-dom';
const NotFoundContainer = styled(Box)({
minHeight: '80vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center',
color: 'var(--text-light)',
});
const NotFound = () => {
const navigate = useNavigate();
return (
<NotFoundContainer>
<Container maxWidth="sm">
<Typography variant="h1" sx={{ color: 'var(--green-primary)', fontWeight: 'bold' }}>
404
</Typography>
<Typography variant="h5" gutterBottom>
Page Not Found
</Typography>
<Typography variant="body1" sx={{ mb: 4 }}>
Sorry, the page you're looking for doesn't exist.
</Typography>
<Button
variant="contained"
onClick={() => navigate('/')}
sx={{
bgcolor: 'var(--green-primary)',
color: 'var(--black-primary)',
'&:hover': { bgcolor: 'var(--green-secondary)' },
}}
>
Go Home
</Button>
</Container>
</NotFoundContainer>
);
};
export default NotFound;
How to Create:
In frontend/src/pages, right-click, select New File, name it 404.js.
Paste the code above.
Save.
16. Create src/redux/store.js
Location: frontend/src/redux/store.js Purpose: Sets up Redux store for state management.
import { configureStore } from '@reduxjs/toolkit';
import authReducer from './slices/authSlice';
import courseReducer from './slices/courseSlice';
const store = configureStore({
reducer: {
auth: authReducer,
courses: courseReducer,
},
});
export default store;
How to Create:
In frontend/src/redux, right-click, select New File, name it store.js.
Paste the code above.
Save.
17. Create src/redux/slices/authSlice.js
Location: frontend/src/redux/slices/authSlice.js Purpose: Manages authentication state in Redux.
import { createSlice } from '@reduxjs/toolkit';
const authSlice = createSlice({
name: 'auth',
initialState: {
user: null,
token: null,
isAuthenticated: false,
},
reducers: {
setUser: (state, action) => {
state.user = action.payload.user;
state.token = action.payload.token;
state.isAuthenticated: true;
},
clearUser: (state) => {
state.user = null;
state.token = null;
state.isAuthenticated = false;
},
},
});
export const { setUser, clearUser } = authSlice.actions;
export default authSlice.reducer;
How to Create:
In frontend/src/redux/slices, right-click, select New File, name it authSlice.js.
Paste the code above.
Save.
18. Create src/redux/slices/courseSlice.js
Location: frontend/src/redux/slices/courseSlice.js Purpose: Placeholder for course state management (required by store.js).
import { createSlice } from '@reduxjs/toolkit';
const courseSlice = createSlice({
name: 'courses',
initialState: {
courses: [],
},
reducers: {
setCourses: (state, action) => {
state.courses = action.payload;
},
},
});
export const { setCourses } = courseSlice.actions;
export default courseSlice.reducer;
How to Create:
In frontend/src/redux/slices, right-click, select New File, name it courseSlice.js.
Paste the code above.
Save.
19. Create src/utils/constants.js
Location: frontend/src/utils/constants.js Purpose: Stores shared constants like colors and API URL.
export const COLORS = {
BLACK_PRIMARY: '#121212',
BLACK_SECONDARY: '#1A1A1A',
GREEN_PRIMARY: '#00FF7F',
GREEN_SECONDARY: '#2ECC71',
YELLOW_PRIMARY: '#FFD700',
YELLOW_SECONDARY: '#F1C40F',
TEXT_LIGHT: '#E0E0E0',
TEXT_MUTED: '#AAAAAA',
};
export const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';
How to Create:
In frontend/src/utils, right-click, select New File, name it constants.js.
Paste the code above.
Save.
Notes for Beginners
Folder Structure:
Your frontend/src should now have:
styles/global.css, styles/theme.js
components/ui/Navbar.js, components/ui/Footer.js
pages/Home.js, pages/404.js, pages/auth/Client/Login.js, pages/auth/Client/Register.js
api/auth.js
context/authContext.js
hooks/useAuth.js
redux/store.js, redux/slices/authSlice.js, redux/slices/courseSlice.js
utils/constants.js
App.js, index.js, routes.js
What’s Missing:
Files like courses.js, cartContext.js, useCart.js, etc., weren’t created as they’re not critical for the initial setup. You can add them later.
The Login.js and Register.js files assume a backend API at http://localhost:5000/api. Update API_URL in constants.js if your backend is different.
Testing:
Run npm start to check the site.
Test navigation (Home, Login, Register, 404 page).
The Navbar should show “Dashboard” and “Logout” when logged in (currently uses a dummy token).
Errors:
If you see errors, check:
File names and paths are exact (case-sensitive).
All dependencies are installed.
Save all files.
Check the terminal or browser console for details.
Tips:
Save often (Ctrl+S or Cmd+S).
The Home.js file references /assets/hero-bg.jpg. Add an image to frontend/public/assets/images or remove the background line if not needed.
Have fun! You’re building a real website!
If you need additional files (e.g., courses.js, cartContext.js) or run into errors, let me know, and I’ll provide the code or help troubleshoot!