Skip to main content

Chapter 3: Frontend Integration

🎯 Objectives​

  • Understand the provided test frontend
  • Connect the frontend to the Spring Boot backend
  • Test the contact form in a real environment
  • Configure CORS for Codespaces

πŸ“š Frontend Resources​

Project Resources
ResourceLink
Frontend CodeFrontend folder
Integration Guide27-guide-formulaire-frontend-codespaces.md

🎨 Frontend Overview​

The provided frontend is a simple HTML/CSS/JavaScript application that allows you to:

  • βœ… Submit contact forms
  • βœ… View API responses
  • βœ… Test admin authentication
  • βœ… View the list of leads

Frontend Structure​

frontend/
β”œβ”€β”€ index.html # Contact form page
β”œβ”€β”€ admin.html # Admin page (leads list)
β”œβ”€β”€ login.html # Login page
β”œβ”€β”€ css/
β”‚ └── styles.css # Styles
└── js/
β”œβ”€β”€ contact.js # Contact form logic
β”œβ”€β”€ admin.js # Admin logic
└── auth.js # Authentication management

πŸš€ Starting the Frontend​

Option 1: With Live Server (VS Code / Codespaces)​

  1. Install the Live Server extension in VS Code/Codespaces

  2. Open the frontend folder:

cd frontend
  1. Right-click on index.html β†’ Open with Live Server

  2. The browser automatically opens on the frontend

Option 2: With Python (Simple HTTP Server)​

# In the frontend folder
cd frontend

# Python 3
python -m http.server 3000

# Access http://localhost:3000

Option 3: With Node.js​

# Install serve globally
npm install -g serve

# Start the server
cd frontend
serve -p 3000

βš™οΈ Configuration for Codespaces​

CORS Issue in Codespaces​

In GitHub Codespaces, the URLs are different:

  • Backend: https://xxx-8080.app.github.dev
  • Frontend: https://xxx-3000.app.github.dev

Solution: Configure Codespaces URLs​

  1. Retrieve the Codespaces backend URL:

    • When the Spring Boot application starts
    • Note the public URL (e.g., https://abc123-8080.app.github.dev)
  2. Modify the frontend JavaScript file:

// js/config.js or at the top of contact.js

// API URL configuration
const API_BASE_URL = 'https://YOUR-CODESPACE-8080.app.github.dev';

// OR for local development
// const API_BASE_URL = 'http://localhost:8080';
  1. Update the backend CORS configuration:
// SecurityConfig.java
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOriginPatterns(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}

πŸ“ Using the Contact Form​

Main Page (index.html)​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ CONTACT US β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ Full Name * Company β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚ β”‚ Enter your name β”‚ β”‚ Your company β”‚β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚ β”‚
β”‚ Email * Phone β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚ β”‚ your@email.com β”‚ β”‚ 514-555-1234 β”‚β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚ β”‚
β”‚ Request Type * β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”β”‚
β”‚ β”‚ Information Request β”‚ vβ”‚β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”˜β”‚
β”‚ β”‚
β”‚ Message * β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚ β”‚ Describe your request... β”‚β”‚
β”‚ β”‚ β”‚β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ SEND β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Submission Test​

  1. Fill in all required fields (*)
  2. Click on Send
  3. Observe the response:

Success:

βœ… Message sent successfully!
Your request has been recorded. We will contact you soon.

Error:

❌ Error during sending
Please check the fields and try again.

πŸ” Admin Interface​

Login (login.html)​

  1. Access login.html
  2. Enter the credentials:
    • Email: admin@test.com
    • Password: password123 (or as configured)
  3. Click on Log in

Admin Dashboard (admin.html)​

Once logged in, you can:

  • πŸ“‹ View the list of all contacts/leads
  • πŸ” Filter by status (NEW, CONTACTED, CONVERTED, LOST)
  • ✏️ Change a lead's status
  • πŸ—‘οΈ Delete a lead
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Admin Dashboard - Lead Management [Logout] β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ Filter: [All β–Ό] [NEW] [CONTACTED] [CONVERTED] [LOST] β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚ β”‚ ID β”‚ Name β”‚ Email β”‚ Type β”‚ Status β”‚ βš™ β”‚β”‚
β”‚ β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”‚
β”‚ β”‚ 1 β”‚ John Doe β”‚ john@test.com β”‚ INFO β”‚ NEW β”‚ βœπŸ—‘β”‚β”‚
β”‚ β”‚ 2 β”‚ Mary Smith β”‚ mary@test.com β”‚ QUOTE β”‚ CONTACTβ”‚ βœπŸ—‘β”‚β”‚
β”‚ β”‚ 3 β”‚ Peter Brown β”‚ peter@test.com β”‚ SUPPORT β”‚ NEW β”‚ βœπŸ—‘β”‚β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚ β”‚
β”‚ Total: 3 leads | New: 2 | In progress: 1 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”„ Frontend-Backend Communication Flow​


πŸ“‘ API Calls from the Frontend​

JavaScript to submit the form​

// contact.js
async function submitContact(formData) {
try {
const response = await fetch(`${API_BASE_URL}/api/contact`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
fullName: formData.fullName,
email: formData.email,
company: formData.company,
phone: formData.phone,
requestType: formData.requestType,
message: formData.message
})
});

if (!response.ok) {
throw new Error('Error during submission');
}

const data = await response.json();
showSuccess('Message sent successfully!');
return data;
} catch (error) {
showError('Error: ' + error.message);
}
}

JavaScript for admin authentication​

// auth.js
async function login(email, password) {
const response = await fetch(`${API_BASE_URL}/api/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});

const data = await response.json();

if (response.ok) {
// Store the JWT token
localStorage.setItem('token', data.token);
window.location.href = 'admin.html';
} else {
showError('Incorrect credentials');
}
}

JavaScript to retrieve leads (with token)​

// admin.js
async function getLeads() {
const token = localStorage.getItem('token');

const response = await fetch(`${API_BASE_URL}/api/admin/leads`, {
headers: {
'Authorization': `Bearer ${token}`
}
});

if (!response.ok) {
if (response.status === 401) {
// Token expired, redirect to login
window.location.href = 'login.html';
}
throw new Error('Error during loading');
}

return await response.json();
}

⚠️ Frontend Troubleshooting​

CORS Error​

Access to fetch at 'http://localhost:8080/api/contact' has been blocked by CORS policy

Solution: Check the backend CORS configuration.

Token not sent​

Symptom: 401 on admin endpoints even after login.

Solution: Ensure the token is stored and sent:

console.log('Token:', localStorage.getItem('token'));

Incorrect URL​

Symptom: fetch failed or network error

Solution: Ensure that:

  1. The backend is running
  2. The URL in API_BASE_URL is correct
  3. For Codespaces, use the public .app.github.dev URL

βœ… Validation Checklist​

  • Frontend accessible in the browser
  • Contact form visible
  • Contact submission successful
  • Success response displayed
  • Admin login functional
  • Leads list visible after login

πŸ“– Complete Guide​

Detailed Guide

For all detailed instructions on frontend integration with Codespaces:

πŸ“– 27-guide-formulaire-frontend-codespaces.md


⏭️ Next Step​

Chapter 4: Additional Course β†’


Back to module index