import React,{useEffect,useState} from "react";import{createRoot}from"react-dom/client";import Dexie from "dexie";import"./style.css";
const db=new Dexie("PWAContactsDB");db.version(1).stores({contacts:"++localId,clientId,email,synced,createdAt"});
function App(){const[f,setF]=useState({name:"",email:"",phone:""}),[cs,setCs]=useState([]),[online,setOnline]=useState(navigator.onLine),[syncing,setSyncing]=useState(false),[msg,setMsg]=useState("");
async function load(){setCs(await db.contacts.orderBy("createdAt").reverse().toArray())}
async function sync(){if(!navigator.onLine||syncing)return;setSyncing(true);try{for(const c of await db.contacts.where("synced").equals(0).toArray()){const r=await fetch("/api/contacts/sync",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clientId:c.clientId,name:c.name,email:c.email,phone:c.phone,createdAt:c.createdAt})});if(!r.ok)throw Error("sync");const x=await r.json();await db.contacts.update(c.localId,{synced:1,serverId:x.id})}setMsg("Sync complete")}catch(e){setMsg("Sync paused — will retry automatically.")}finally{setSyncing(false);load()}}
useEffect(()=>{load();const on=()=>{setOnline(true);sync()},off=()=>{setOnline(false);setMsg("Offline — saved locally.")};addEventListener("online",on);addEventListener("offline",off);if("serviceWorker"in navigator)navigator.serviceWorker.register("/sw.js");sync();return()=>{removeEventListener("online",on);removeEventListener("offline",off)}},[]);
async function save(e){e.preventDefault();await db.contacts.add({clientId:crypto.randomUUID(),...f,createdAt:new Date().toISOString(),synced:0});setF({name:"",email:"",phone:""});setMsg(online?"Saved locally — syncing...":"Saved locally — waiting for internet.");load();if(navigator.onLine)sync()}
return <main><header><div><h1>Offline Contacts</h1><p>Works offline and syncs automatically.</p></div><b className={online?"on":"off"}>{online?"● Online":"● Offline"}</b></header><section><form onSubmit={save}><input required placeholder="Name" value={f.name} onChange={e=>setF({...f,name:e.target.value})}/><input required type="email" placeholder="Email" value={f.email} onChange={e=>setF({...f,email:e.target.value})}/><input required placeholder="Phone" value={f.phone} onChange={e=>setF({...f,phone:e.target.value})}/><button>Save Contact</button></form><p>{syncing?"Syncing...":msg}</p></section><section><div className="title"><h2>Contacts</h2><button onClick={sync} disabled={!online||syncing}>Sync Now</button></div>{cs.map(c=><article key={c.clientId}><div><strong>{c.name}</strong><small>{c.email} · {c.phone}</small></div><span>{c.synced?"✓ Synced":"⏳ Pending"}</span></article>)}</section></main>}createRoot(document.getElementById("root")).render(<App/>);