first commit with existing project files

This commit is contained in:
Vincent Guillet
2025-07-12 11:22:38 +02:00
commit b65e27e424
7 changed files with 327 additions and 0 deletions

1
README.md Normal file
View File

@@ -0,0 +1 @@
# tp-javascript-crm

180
app.js Normal file
View File

@@ -0,0 +1,180 @@
import {User} from './models/User.js';
import {Address} from "./models/Address.js";
import {Geo} from "./models/Geo.js";
import {Company} from "./models/Company.js";
const usersTab = [];
const contactList = document.getElementById('contact-list');
const loadBtn = document.getElementById('load-contacts');
const contactForm = document.getElementById('contact-form');
function fetchUsers(limit) {
return fetch(`https://jsonplaceholder.typicode.com/users?_limit=${limit}`)
.then(response => response.json())
.then(data => data.forEach(user => {
addUserToTab(user);
})
);
}
function addUserToTab(user) {
const newUser = new User(
user.id,
user.name,
user.username,
user.email,
user.address,
user.phone,
user.website,
user.company
);
if (!usersTab.some(existingUser => existingUser.email === user.email)) {
usersTab.push(newUser);
createContactItem(user);
}
}
function createEditButton() {
const btn = document.createElement('button');
btn.classList.add('btn');
btn.classList.add('btn-secondary');
btn.innerHTML = `<i class="bi bi-pencil-square"></i>`;
btn.style.margin = '0 3px';
return btn;
}
function createDeleteButton() {
const btn = document.createElement('button');
btn.classList.add('btn');
btn.classList.add('btn-danger');
btn.innerHTML = `<i class="bi bi-trash"></i>`;
btn.style.margin = '0 3px';
return btn;
}
function createContactItem(user) {
const editBtn = createEditButton();
const deleteBtn = createDeleteButton();
const card = document.createElement('div');
const li = document.createElement('li');
li.classList.add('list-group-item');
li.classList.add("card");
li.classList.add("shadow-sm");
li.classList.add("p-4");
li.innerHTML = `
<div>
<h5>${user.name}</h5>
<p><strong>Email:</strong> ${user.email}</p>
</div>
`;
li.style.margin = '5px 0';
li.appendChild(deleteBtn);
li.appendChild(editBtn);
editBtn.addEventListener('click', () => {
li.innerHTML = `
<h5 id="form-title">Modifier le contact</h5>
<div class="mb-3">
<label for="name" class="form-label">Nom</label>
<input type="text" id="newName" class="form-control" name="name" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" id="newEmail" class="form-control" name="email" required>
</div>
<button type="submit" class="btn btn-secondary btn-success update-btn">Mettre à jour</button>
<button type="button" class="btn btn-secondary btn-danger cancel-btn">Annuler</button>
`;
const updateBtn = li.querySelector('.update-btn');
updateBtn.addEventListener('click', (e) => {
e.preventDefault();
const newName = li.querySelector('#newName').value;
const newEmail = li.querySelector('#newEmail').value;
usersTab[usersTab.findIndex(u => u.email === user.email)].name = newName;
usersTab[usersTab.findIndex(u => u.email === user.email)].email = newEmail;
user.name = newName;
user.email = newEmail;
createContactItem(user);
contactList.removeChild(li);
});
const cancelBtn = li.querySelector('.cancel-btn');
cancelBtn.addEventListener('click', (e) => {
e.preventDefault();
createContactItem(user);
contactList.removeChild(li);
})
});
deleteBtn.addEventListener('click', () => {
const index = usersTab.findIndex(u => u.email === user.email);
if (index !== -1) {
usersTab.splice(index, 1);
contactList.removeChild(li);
}
})
contactList.appendChild(li);
}
function createUserFromForm() {
const formData = new FormData(contactForm);
return new User(
usersTab.length + 1,
formData.get('name'),
formData.get('username'),
formData.get('email'),
new Address(
formData.get('street'),
formData.get('suite'),
formData.get('city'),
formData.get('zipcode'),
new Geo(formData.get('lat'), formData.get('lng'))
),
formData.get('phone'),
formData.get('website'),
new Company(formData.get('companyName'), formData.get('catchPhrase'), formData.get('bs'))
);
}
function postNewUser(newUser) {
fetch(`https://jsonplaceholder.typicode.com/users`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newUser)
})
.then(response => {
console.log(response);
if (response.ok) {
addUserToTab(newUser);
}
}
);
}
loadBtn.addEventListener('click', async (e) => {
e.preventDefault();
await fetchUsers(2);
});
contactForm.addEventListener('submit', (e) => {
e.preventDefault();
const newUser = createUserFromForm();
postNewUser(newUser);
contactForm.reset();
});

42
index.html Normal file
View File

@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mini CRM AJAX</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css">
<script type="module" src="app.js" defer></script>
</head>
<body>
<div class="container py-4">
<h1 class="mb-4">Gestion de Contacts</h1>
<!-- Statut -->
<div id="status-message" class="alert d-none" role="alert"></div>
<!-- Bouton charger -->
<div class="mb-3">
<button id="load-contacts" class="btn btn-primary">Charger les contacts</button>
</div>
<!-- Liste des contacts -->
<ul id="contact-list" class="list-group mb-4"></ul>
<!-- Formulaire dajout/modification -->
<form id="contact-form" class="card card-body">
<h5 id="form-title">Ajouter un contact</h5>
<div class="mb-3">
<label for="name" class="form-label">Nom</label>
<input type="text" id="name" class="form-control" name="name" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" id="email" class="form-control" name="email" required>
</div>
<input type="hidden" id="contact-id">
<button type="submit" class="btn btn-primary">Enregistrer</button>
</form>
</div>
</body>
</html>

29
models/Address.js Normal file
View File

@@ -0,0 +1,29 @@
export class Address {
constructor(street, suite, city, zipcode, geo) {
this._street = street;
this._suite = suite;
this._city = city;
this._zipcode = zipcode;
this._geo = geo;
}
get street() { return this._street; }
get suite() { return this._suite; }
get city() { return this._city; }
get zipcode() { return this._zipcode; }
get geo() { return this._geo; }
set street(street) { this._street = street; }
set suite(suite) { this._suite = suite; }
set city(city) { this._city = city; }
set zipcode(zipcode) { this._zipcode = zipcode; }
set geo(geo) { this._geo = geo; }
}

19
models/Company.js Normal file
View File

@@ -0,0 +1,19 @@
export class Company {
constructor(name, catchPhrase, bs) {
this._name = name;
this._catchPhrase = catchPhrase;
this._bs = bs;
}
get name() { return this._name; }
get catchPhrase() { return this._catchPhrase; }
get bs() { return this._bs; }
set name(name) { this._name = name; }
set catchPhrase(catchPhrase) { this._catchPhrase = catchPhrase; }
set bs(bs) { this._bs = bs; }
}

14
models/Geo.js Normal file
View File

@@ -0,0 +1,14 @@
export class Geo {
constructor(lat, lng) {
this._lat = lat;
this._lng = lng;
}
get lat() { return this._lat; }
get lng() { return this._lng; }
set lat(lat) { this._lat = lat; }
set lng(lng) { this._lng = lng; }
}

42
models/User.js Normal file
View File

@@ -0,0 +1,42 @@
export class User {
constructor(id, name, username, email, address, phone, website, company) {
this._id = id;
this._name = name;
this._username = username;
this._email = email;
this._address = address;
this._phone = phone;
this._website = website;
this._company = company;
}
get id() {return this._id;}
get name() {return this._name;}
get username() {return this._username;}
get email() {return this._email;}
get address() {return this._address;}
get phone() {return this._phone;}
get website() {return this._website;}
get company() {return this._company;}
set name(name) {this._name = name;}
set username(username) {this._username = username;}
set email(email) {this._email = email;}
set address(address) {this._address = address;}
set phone(phone) {this._phone = phone;}
set website(website) {this._website = website;}
set company(company) {this._company = company;}
}