linguagem
This commit is contained in:
119
index.html
119
index.html
@@ -18,9 +18,8 @@
|
||||
dark: {
|
||||
bg: '#0f172a',
|
||||
surface: '#1e293b',
|
||||
card: '#334155',
|
||||
border: '#475569',
|
||||
text: '#f1f5f9',
|
||||
border: '#334155',
|
||||
card: '#1e293b',
|
||||
mute: '#94a3b8'
|
||||
}
|
||||
}
|
||||
@@ -28,6 +27,24 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Google Translate Script -->
|
||||
<script type="text/javascript">
|
||||
function googleTranslateElementInit() {
|
||||
new google.translate.TranslateElement({pageLanguage: 'pt', includedLanguages: 'pt,en,es,fr', autoDisplay: false}, 'google_translate_element');
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript" src="https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
|
||||
|
||||
<style>
|
||||
/* Esconder a barra e o widget do Google Translate nativos */
|
||||
.skiptranslate iframe, .goog-te-banner-frame { display: none !important; }
|
||||
body { top: 0px !important; }
|
||||
#google_translate_element { display: none !important; }
|
||||
.goog-tooltip { display: none !important; }
|
||||
.goog-tooltip:hover { display: none !important; }
|
||||
.goog-text-highlight { background-color: transparent !important; border: none !important; box-shadow: none !important; }
|
||||
</style>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
@@ -490,7 +507,7 @@
|
||||
userId = 'admin_001';
|
||||
} else {
|
||||
const residentUser = residents.find(r => r.email && r.email.toLowerCase() === email.toLowerCase());
|
||||
if (residentUser && (password === residentUser.password || password === '1234')) {
|
||||
if (residentUser && (password === residentUser.password || (!residentUser.password && password === residentUser.contact) || password === '1234')) {
|
||||
role = residentUser.role || 'morador';
|
||||
userName = residentUser.name + (residentUser.unit && residentUser.unit !== 'Pendente' ? ` (${residentUser.unit})` : '');
|
||||
userId = residentUser.id || userId;
|
||||
@@ -735,8 +752,12 @@
|
||||
} else if (type === 'emitir_fatura') {
|
||||
setFormData(initialFaturaForm);
|
||||
} else if (type === 'booking') {
|
||||
const baseForm = initialBookingForm;
|
||||
const baseForm = { ...initialBookingForm };
|
||||
if (defaultFacility) baseForm.facility = defaultFacility;
|
||||
|
||||
// Preenche sempre o nome do utilizador logado por defeito
|
||||
baseForm.resident = currentUserName;
|
||||
|
||||
setFormData(baseForm);
|
||||
}
|
||||
};
|
||||
@@ -1332,6 +1353,43 @@
|
||||
setFormData(prev => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
const [passwordData, setPasswordData] = useState({ current: '', new: '', confirm: '' });
|
||||
const handlePasswordChange = (field, value) => {
|
||||
setPasswordData(prev => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
const handleSavePassword = async () => {
|
||||
if (passwordData.new !== passwordData.confirm) {
|
||||
showNotification('As novas palavras-passe não coincidem.', 'error');
|
||||
return;
|
||||
}
|
||||
if (passwordData.new.length < 4) {
|
||||
showNotification('A nova palavra-passe deve ter pelo menos 4 caracteres.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMorador) {
|
||||
const currentUserData = residents.find(r => r.id === currentUserId);
|
||||
const currentPassword = currentUserData.password || currentUserData.contact || '1234';
|
||||
if (passwordData.current !== currentPassword) {
|
||||
showNotification('A palavra-passe atual está incorreta.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await set(ref(db, `condominos/${currentUserData.id}/password`), passwordData.new);
|
||||
showNotification('Palavra-passe alterada com sucesso!', 'success');
|
||||
setPasswordData({ current: '', new: '', confirm: '' });
|
||||
sendSystemNotification('Um utilizador alterou a sua palavra-passe.', 'info', 'admin');
|
||||
} catch (error) {
|
||||
console.error("Erro ao alterar palavra-passe:", error);
|
||||
showNotification('Erro ao alterar a palavra-passe.', 'error');
|
||||
}
|
||||
} else {
|
||||
showNotification('A conta de administrador usa o Firebase Auth para gerir passwords.', 'info');
|
||||
}
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
if (isMorador) {
|
||||
const currentUserData = residents.find(r => r.id === currentUserId);
|
||||
@@ -1438,16 +1496,13 @@
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<InputGroup label="Palavra-passe Atual" type="password" placeholder="••••••••" />
|
||||
<InputGroup label="Palavra-passe Atual" type="password" placeholder="••••••••" value={passwordData.current} onChange={(e) => handlePasswordChange('current', e.target.value)} />
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<InputGroup label="Nova Palavra-passe" type="password" placeholder="Min. 8 caracteres" />
|
||||
<InputGroup label="Confirmar Nova Palavra-passe" type="password" placeholder="Confirmar" />
|
||||
<InputGroup label="Nova Palavra-passe" type="password" placeholder="Min. 8 caracteres" value={passwordData.new} onChange={(e) => handlePasswordChange('new', e.target.value)} />
|
||||
<InputGroup label="Confirmar Nova Palavra-passe" type="password" placeholder="Confirmar" value={passwordData.confirm} onChange={(e) => handlePasswordChange('confirm', e.target.value)} />
|
||||
</div>
|
||||
<div className="flex justify-end mt-6">
|
||||
<button onClick={() => {
|
||||
showNotification('Segurança atualizada com sucesso!', 'success');
|
||||
sendSystemNotification('Um utilizador alterou a palavra-passe.', 'info', 'admin');
|
||||
}} className="bg-slate-800 dark:bg-slate-700 text-white px-6 py-2 rounded-lg font-medium hover:bg-slate-900 dark:hover:bg-slate-600 shadow-sm transition-colors">
|
||||
<button onClick={handleSavePassword} className="bg-slate-800 dark:bg-slate-700 text-white px-6 py-2 rounded-lg font-medium hover:bg-slate-900 dark:hover:bg-slate-600 shadow-sm transition-colors">
|
||||
Atualizar Segurança
|
||||
</button>
|
||||
</div>
|
||||
@@ -1504,6 +1559,43 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="text-sm font-bold text-slate-700 dark:text-slate-300 mb-3">Idioma da Aplicação</h4>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ code: 'pt', label: 'Português', flag: '🇵🇹' },
|
||||
{ code: 'en', label: 'English', flag: '🇬🇧' },
|
||||
{ code: 'es', label: 'Español', flag: '🇪🇸' },
|
||||
{ code: 'fr', label: 'Français', flag: '🇫🇷' }
|
||||
].map(lang => {
|
||||
const match = document.cookie.match(/googtrans=\/pt\/([a-z]{2})/);
|
||||
const activeLang = match ? match[1] : 'pt';
|
||||
const isActive = activeLang === lang.code;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={lang.code}
|
||||
onClick={() => {
|
||||
if(lang.code === 'pt') {
|
||||
document.cookie = "googtrans=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
document.cookie = "googtrans=; expires=Thu, 01 Jan 1970 00:00:00 UTC; domain=" + window.location.hostname + "; path=/;";
|
||||
} else {
|
||||
document.cookie = `googtrans=/pt/${lang.code}; path=/;`;
|
||||
document.cookie = `googtrans=/pt/${lang.code}; domain=${window.location.hostname}; path=/;`;
|
||||
}
|
||||
window.location.reload();
|
||||
}}
|
||||
className={`border-2 p-3 rounded-lg text-center cursor-pointer transition-colors ${isActive ? 'border-blue-500 bg-blue-50 dark:bg-blue-900/30' : 'border-slate-200 dark:border-dark-border bg-white dark:bg-dark-card hover:bg-slate-50 dark:hover:bg-dark-surface'}`}
|
||||
>
|
||||
<div className="text-2xl mb-1">{lang.flag}</div>
|
||||
<div className="text-xs font-bold text-slate-700 dark:text-slate-300">{lang.label}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400 mt-2">A tradução é efetuada automaticamente e afetará toda a aplicação após recarregar a página.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="text-sm font-bold text-slate-700 mb-3">Aparência</h4>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
@@ -2426,7 +2518,7 @@
|
||||
<InputGroup label="Data" type="date" name="date" value={formData.date || ''} onChange={handleInputChange} required />
|
||||
<InputGroup label="Horário" name="time" value={formData.time || ''} onChange={handleInputChange} placeholder="Ex: 14:00 - 16:00" required />
|
||||
</div>
|
||||
<InputGroup label="Reservado para (Condómino)" name="resident" value={formData.resident || ''} onChange={handleInputChange} placeholder="Nome do residente" required />
|
||||
<InputGroup label="Reservado para (Condómino)" name="resident" value={formData.resident || ''} onChange={handleInputChange} placeholder="Nome do residente" required disabled={userRole !== 'admin'} />
|
||||
|
||||
<div className="bg-slate-50 dark:bg-dark-card p-4 rounded-lg border border-slate-200 dark:border-dark-border mt-2 mb-4 flex justify-between items-center transition-colors">
|
||||
<span className="text-sm font-medium text-slate-600 dark:text-slate-300">Custo Estimado:</span>
|
||||
@@ -2498,6 +2590,7 @@
|
||||
</ErrorBoundary>
|
||||
);
|
||||
</script>
|
||||
<div id="google_translate_element"></div>
|
||||
<!-- Firebase configs moved to top in React Module -->
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user