commit b65e27e424b425695570f59b3741acee6e265d5a Author: Vincent Guillet Date: Sat Jul 12 11:22:38 2025 +0200 first commit with existing project files diff --git a/README.md b/README.md new file mode 100644 index 0000000..27c3598 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# tp-javascript-crm \ No newline at end of file diff --git a/app.js b/app.js new file mode 100644 index 0000000..5058477 --- /dev/null +++ b/app.js @@ -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 = ``; + 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 = ``; + 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 = ` +
+
${user.name}
+

Email: ${user.email}

+
+ `; + li.style.margin = '5px 0'; + li.appendChild(deleteBtn); + li.appendChild(editBtn); + + editBtn.addEventListener('click', () => { + li.innerHTML = ` +
Modifier le contact
+
+ + +
+
+ + +
+ + + `; + + 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(); +}); + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..0fc4f7f --- /dev/null +++ b/index.html @@ -0,0 +1,42 @@ + + + + + + Mini CRM AJAX + + + + + +
+

Gestion de Contacts

+ + + + + +
+ +
+ + + + + +
+
Ajouter un contact
+
+ + +
+
+ + +
+ + +
+
+ + diff --git a/models/Address.js b/models/Address.js new file mode 100644 index 0000000..2c1d31e --- /dev/null +++ b/models/Address.js @@ -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; } +} \ No newline at end of file diff --git a/models/Company.js b/models/Company.js new file mode 100644 index 0000000..e2d1617 --- /dev/null +++ b/models/Company.js @@ -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; } +} \ No newline at end of file diff --git a/models/Geo.js b/models/Geo.js new file mode 100644 index 0000000..4725cf8 --- /dev/null +++ b/models/Geo.js @@ -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; } +} \ No newline at end of file diff --git a/models/User.js b/models/User.js new file mode 100644 index 0000000..82a6fda --- /dev/null +++ b/models/User.js @@ -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;} +} \ No newline at end of file