AUDITPRO / components /SettingsPanel.tsx
MMOON's picture
Upload 5 files
8c03bde verified
import React, { useState } from 'react';
import { AppSettings } from '../types';
import {
Save,
Globe,
User,
Info,
Database,
FileSpreadsheet,
Copy,
CheckCircle2,
Lock,
ExternalLink,
ShieldCheck,
Hash,
Download,
// Added missing AlertTriangle icon import
AlertTriangle
} from 'lucide-react';
interface SettingsPanelProps {
settings: AppSettings;
onSave: (settings: AppSettings) => void;
}
const SettingsPanel: React.FC<SettingsPanelProps> = ({ settings, onSave }) => {
const [localSettings, setLocalSettings] = useState<AppSettings>(settings);
const [copied, setCopied] = useState(false);
const [activeTab, setActiveTab] = useState<'profile' | 'google' | 'info'>('profile');
const googleScriptCode = `
/**
* AUDITPRO UNIVERSAL SYNC SCRIPT
* Copiez ce code dans Extensions > Apps Script de votre Google Sheet
*/
function doPost(e) {
try {
var payload = JSON.parse(e.postData.contents);
var audit = payload.data;
// On utilise l'ID envoyé par l'app pour cibler la bonne feuille
var sheetId = audit.sheetId;
var ss = sheetId ? SpreadsheetApp.openById(sheetId) : SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// En-têtes si feuille vide
if (sheet.getLastRow() == 0) {
sheet.appendRow(["DATE", "INSPECTEUR", "MODÈLE", "QUESTION", "RÉPONSE", "OBSERVATION", "PHOTOS (NB)"]);
sheet.getRange(1, 1, 1, 7).setFontWeight("bold").setBackground("#4F46E5").setFontColor("white");
}
audit.responses.forEach(function(resp) {
sheet.appendRow([
new Date(audit.startedAt).toLocaleString(),
audit.inspectorName,
audit.checklistName,
resp.itemLabel,
resp.value,
resp.comment || "",
resp.photos ? resp.photos.length : 0
]);
});
return ContentService.createTextOutput("SUCCESS").setMimeType(ContentService.MimeType.TEXT);
} catch(f) {
return ContentService.createTextOutput("ERROR: " + f.message).setMimeType(ContentService.MimeType.TEXT);
}
}
`.trim();
const copyScript = () => {
navigator.clipboard.writeText(googleScriptCode);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div className="space-y-6 pb-20 animate-in fade-in duration-500">
<div className="bg-white rounded-[3rem] shadow-2xl border border-slate-200 overflow-hidden">
{/* Navigation Tabs */}
<div className="flex border-b border-slate-100 bg-slate-50/30 overflow-x-auto">
<button onClick={() => setActiveTab('profile')} className={`px-8 py-6 flex items-center gap-2 text-[11px] font-black uppercase tracking-widest transition-all border-b-2 ${activeTab === 'profile' ? 'border-indigo-600 text-indigo-600 bg-white' : 'border-transparent text-slate-400 hover:text-slate-600'}`}>
<User size={16} /> Identité
</button>
<button onClick={() => setActiveTab('google')} className={`px-8 py-6 flex items-center gap-2 text-[11px] font-black uppercase tracking-widest transition-all border-b-2 ${activeTab === 'google' ? 'border-indigo-600 text-indigo-600 bg-white' : 'border-transparent text-slate-400 hover:text-slate-600'}`}>
<Globe size={16} /> Synchro Google
</button>
<button onClick={() => setActiveTab('info')} className={`px-8 py-6 flex items-center gap-2 text-[11px] font-black uppercase tracking-widest transition-all border-b-2 ${activeTab === 'info' ? 'border-indigo-600 text-indigo-600 bg-white' : 'border-transparent text-slate-400 hover:text-slate-600'}`}>
<Database size={16} /> Mon Espace
</button>
</div>
<div className="p-8 sm:p-12">
{activeTab === 'profile' && (
<div className="space-y-8 animate-in slide-in-from-left-4 duration-300">
<div className="space-y-3">
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest block">Signature Inspecteur</label>
<input
type="text"
value={localSettings.inspectorName}
onChange={(e) => setLocalSettings({...localSettings, inspectorName: e.target.value})}
placeholder="Votre nom complet"
className="w-full border-2 border-slate-100 rounded-2xl p-5 text-slate-800 font-bold focus:border-indigo-600 outline-none bg-slate-50/50 transition-all text-lg"
/>
<p className="text-[10px] text-slate-400 font-bold italic italic">Ce nom sera gravé dans chaque audit que vous réaliserez.</p>
</div>
</div>
)}
{activeTab === 'google' && (
<div className="space-y-10 animate-in slide-in-from-left-4 duration-300">
<div className="p-8 bg-indigo-600 rounded-[2rem] text-white shadow-xl shadow-indigo-100 flex items-start gap-6">
<div className="bg-white/20 p-4 rounded-2xl backdrop-blur-md">
<ShieldCheck size={32} />
</div>
<div>
<h4 className="text-xl font-black mb-2">Liaison de Données</h4>
<p className="text-sm text-indigo-100/90 leading-relaxed font-medium">
Ces identifiants sont strictement personnels. Ils permettent à l'application de savoir exactement dans quelle Google Sheet envoyer vos rapports.
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-3">
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest flex items-center gap-2">
<Hash size={14} /> ID de la Google Sheet
</label>
<input
type="text"
value={localSettings.sheetId}
onChange={(e) => setLocalSettings({...localSettings, sheetId: e.target.value})}
placeholder="Ex: 1bc-DEFgH..."
className="w-full border-2 border-slate-100 rounded-2xl p-5 text-slate-700 font-mono text-sm outline-none bg-slate-50 focus:border-indigo-600 transition-all"
/>
</div>
<div className="space-y-3">
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest flex items-center gap-2">
<Globe size={14} /> URL du Script (Web App)
</label>
<input
type="url"
value={localSettings.webhookUrl}
onChange={(e) => setLocalSettings({...localSettings, webhookUrl: e.target.value})}
placeholder="https://script.google.com/macros/s/..."
className="w-full border-2 border-slate-100 rounded-2xl p-5 text-slate-700 font-mono text-sm outline-none bg-slate-50 focus:border-indigo-600 transition-all"
/>
</div>
</div>
<div className="space-y-5 pt-4">
<div className="flex items-center justify-between">
<h4 className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Script Apps Script Requis</h4>
<button onClick={copyScript} className={`flex items-center gap-2 px-5 py-2.5 rounded-xl text-xs font-black transition-all shadow-sm ${copied ? 'bg-emerald-500 text-white' : 'bg-slate-100 text-slate-600 hover:bg-slate-200'}`}>
{copied ? <CheckCircle2 size={16} /> : <Copy size={16} />} {copied ? 'Copié !' : 'Copier le script'}
</button>
</div>
<div className="bg-slate-900 rounded-[1.5rem] p-6 relative group">
<pre className="text-[10px] text-emerald-400 font-mono overflow-x-auto max-h-56 leading-relaxed whitespace-pre-wrap">
{googleScriptCode}
</pre>
</div>
</div>
</div>
)}
{activeTab === 'info' && (
<div className="space-y-8 animate-in slide-in-from-left-4 duration-300">
<div className="p-10 bg-slate-50 rounded-[2.5rem] border border-slate-100 space-y-6">
<div className="flex items-center gap-4 text-indigo-600">
<Database size={32} />
<h4 className="text-2xl font-black tracking-tight">Souveraineté Totale</h4>
</div>
<p className="text-sm text-slate-600 leading-relaxed font-bold">
Votre espace contient tout votre ADN professionnel : modèles, audits et réglages cloud.
L'application ne stocke rien en ligne de son côté.
</p>
<div className="space-y-4 pt-4 border-t border-slate-200">
<div className="flex items-start gap-3">
<div className="bg-amber-100 text-amber-600 p-2 rounded-lg mt-1"><AlertTriangle size={16} /></div>
<p className="text-xs text-slate-500 font-medium leading-relaxed">
Chaque fois que vous changez d'ordinateur ou que vous videz votre navigateur, vous devez importer votre fichier <code>.auditpro</code>.
</p>
</div>
<div className="flex items-start gap-3">
<div className="bg-indigo-100 text-indigo-600 p-2 rounded-lg mt-1"><Download size={16} /></div>
<p className="text-xs text-slate-500 font-medium leading-relaxed">
Pensez à sauvegarder votre "Clé" régulièrement pour ne perdre aucun audit récent.
</p>
</div>
</div>
</div>
</div>
)}
<div className="mt-12 pt-10 border-t border-slate-100 flex justify-end">
<button
onClick={() => onSave(localSettings)}
className="bg-indigo-600 text-white px-12 py-5 rounded-2xl hover:bg-indigo-700 shadow-2xl shadow-indigo-100 font-black transition-all flex items-center gap-3 active:scale-95"
>
<Save size={20} /> ENREGISTRER L'ESPACE
</button>
</div>
</div>
</div>
</div>
);
};
export default SettingsPanel;