D’accord, on va créer une **PWA pour enregistrer les contacts des
clients** en utilisant **PHP, Tailwind CSS, JavaScript et un Service
Worker**.
### **1. Fonctionnalités principales**
✅ Ajouter, afficher et supprimer des contacts
✅ Stockage local avec **IndexedDB** pour une utilisation hors ligne
✅ Synchronisation avec une base de données **PHP/MySQL**
### **2. Structure du projet**
📂 `pwa-contacts/`
├── 📂 `css/` → (Styles Tailwind)
├── 📂 `js/` → (Scripts)
├── 📂 `backend/` → (API PHP/MySQL)
├── `index.html` → (Interface principale)
├── `manifest.json` → (Déclaration PWA)
├── `sw.js` → (Service Worker)
### **3. Développement**
#### **a) Interface (`index.html`)**
Ce fichier affichera la liste des contacts et un formulaire pour en ajouter.
```html
< !DOCTYPE html>
<html lang= »fr »>
<head>
<meta charset= »UTF-8 »>
<meta name= »viewport » content= »width=device-width, initial-
scale=1.0 »>
<title>Gestion des Contacts</title>
<link rel= »stylesheet » href= »css/tailwind.css »>
<link rel= »manifest » href= »manifest.json »>
</head>
<body class= »bg-cyan-500 text-white p-4 »>
<h1 class= »text-2xl font-bold »>Contacts Clients</h1>
<form id= »contact-form » class= »mt-4 »>
<input type= »text » id= »name » placeholder= »Nom » class= »p-2
rounded »>
<input type= »text » id= »phone » placeholder= »Téléphone »
class= »p-2 rounded »>
<button type= »submit » class= »bg-white text-cyan-500 p-2
rounded »>Ajouter</button>
</form>
<ul id= »contact-list » class= »mt-4 »></ul>
<script src= »js/app.js »></script>
</body>
</html>
```
#### **b) Stockage Local et Affichage (`js/app.js`)**
Gestion des contacts en local + envoi vers le backend PHP.
```js
Document.addEventListener(« DOMContentLoaded », () => {
Const form = document.getElementById(« contact-form ») ;
Const list = document.getElementById(« contact-list ») ;
Function loadContacts() {
Let contacts = JSON.parse(localStorage.getItem(« contacts »)) || [] ;
List.innerHTML = « « ;
Contacts.forEach((contact, index) => {
Let li = document.createElement(« li ») ;
li.textContent = `${contact.name} - ${contact.phone}` ;
li.innerHTML += ` <button onclick= »deleteContact($
{index}) »>❌</button>` ;
list.appendChild(li) ;
}) ;
Form.addEventListener(« submit », € => {
e.preventDefault() ;
let name = document.getElementById(« name »).value ;
let phone = document.getElementById(« phone »).value ;
let contacts = JSON.parse(localStorage.getItem(« contacts »)) || [] ;
contacts.push({ name, phone }) ;
localStorage.setItem(« contacts », JSON.stringify(contacts)) ;
fetch(« backend/save.php », {
method : « POST »,
body : JSON.stringify({ name, phone }),
headers : { « Content-Type » : « application/json » }
}) ;
loadContacts() ;
}) ;
Window.deleteContact = (index) => {
Let contacts = JSON.parse(localStorage.getItem(« contacts »)) ;
Contacts.splice(index, 1) ;
localStorage.setItem(« contacts », JSON.stringify(contacts)) ;
loadContacts() ;
};
loadContacts() ;
}) ;
```
#### **c) Backend PHP (`backend/save.php`)**
Stocke les contacts dans une base de données.
```php
< ?php
$dsn = « mysql :host=localhost ;dbname=contacts_db ;charset=utf8 » ;
$user = « root » ;
$pass = « « ;
Try {
$pdo = new PDO($dsn, $user, $pass, [PDO ::ATTR_ERRMODE =>
PDO ::ERRMODE_EXCEPTION]) ;
$data = json_decode(file_get_contents(« php://input »), true) ;
$stmt = $pdo->prepare(« INSERT INTO contacts (name, phone) VALUES
( ?, ?) ») ;
$stmt->execute([$data[‘name’], $data[‘phone’]]) ;
Echo json_encode([« message » => « Contact ajouté »]) ;
} catch (PDOException $e) {
Echo json_encode([« error » => $e->getMessage()]) ;
}
?>
```
*Base de données SQL (`contacts_db`) :*
```sql
CREATE TABLE contacts (
Id INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(100),
Phone VARCHAR(20)
);
```
#### **d) PWA : `manifest.json`**
```json
« name » : « Gestion des Contacts »,
« short_name » : « Contacts »,
« start_url » : « /index.html »,
« display » : « standalone »,
« background_color » : « #00BCD4 »,
« theme_color » : « #00BCD4 »,
« icons » : [
« src » : « icon-192.png »,
« sizes » : « 192x192 »,
« type » : « image/png »
},
« src » : « icon-512.png »,
« sizes » : « 512x512 »,
« type » : « image/png »
```
#### **e) Service Worker (`sw.js`)**
Permet le mode hors ligne.
```js
Const CACHE_NAME = « pwa-contacts-cache » ;
Const urlsToCache = [« / », « /index.html », « /css/tailwind.css »,
« /js/app.js »] ;
Self.addEventListener(« install », (event) => {
Event.waitUntil(
Caches.open(CACHE_NAME).then((cache) =>
cache.addAll(urlsToCache))
);
}) ;
Self.addEventListener(« fetch », (event) => {
Event.respondWith(
Caches.match(event.request).then((response) => response ||
fetch(event.request))
);
}) ;
```
### **4. Tester la PWA**
1. Lancer un serveur PHP :
```sh
Php -S localhost :8000
```
2. Ouvrir Chrome sur `http://localhost :8000`
3. Tester l’ajout de contacts (en ligne et hors ligne).
4. Vérifier si l’application propose ** »Ajouter à l’écran d’accueil »** sur
mobile.
### **5. Hébergement**
- Héberge sur **Netlify (sans backend)** ou **Vercel/Firebase**.
- Si tu veux **PHP/MySQL**, utilise **InfinityFree ou un hébergement
payant**.
### **Conclusion**
✅ **Contacts stockés en local et synchronisés avec MySQL**
✅ **Accessible hors ligne avec un Service Worker**
✅ **Ajout possible à l’écran d’accueil comme une vraie app**
Tu veux que j’améliore quelque chose ou ajoute une fonctionnalité ?