feat: add loading animation to tenant creation button
All checks were successful
Build and Deploy / build-and-push (push) Successful in 1m10s

- Implemented isSaving state in SuperAdmin to provide visual feedback during organization creation and updates.
This commit is contained in:
Cauê Faleiros
2026-03-10 15:10:44 -03:00
parent ab35cf9126
commit ee3b9f4ce6

View File

@@ -1,9 +1,8 @@
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo } from 'react';
import { import {
Building2, Users, MessageSquare, Plus, Search, Building2, Users, MessageSquare, Plus, Search,
Edit, Trash2, ChevronDown, ChevronUp, ChevronsUpDown, X, CheckCircle2 Edit, Trash2, ChevronDown, ChevronUp, ChevronsUpDown, X, CheckCircle2, Loader2
} from 'lucide-react'; } from 'lucide-react';import { getTenants, createTenant, deleteTenant, updateTenant } from '../services/dataService';
import { getTenants, createTenant, deleteTenant, updateTenant } from '../services/dataService';
import { Tenant } from '../types'; import { Tenant } from '../types';
import { DateRangePicker } from '../components/DateRangePicker'; import { DateRangePicker } from '../components/DateRangePicker';
import { KPICard } from '../components/KPICard'; import { KPICard } from '../components/KPICard';
@@ -93,42 +92,53 @@ export const SuperAdmin: React.FC = () => {
const [successMessage, setSuccessMessage] = useState(''); const [successMessage, setSuccessMessage] = useState('');
const [errorMessage, setErrorMessage] = useState(''); const [errorMessage, setErrorMessage] = useState('');
const [isSaving, setIsSaving] = useState(false);
const handleSaveTenant = async (e: React.FormEvent) => { const handleSaveTenant = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
setErrorMessage(''); setErrorMessage('');
setSuccessMessage(''); setSuccessMessage('');
setIsSaving(true);
const form = e.target as HTMLFormElement; const form = e.target as HTMLFormElement;
const name = (form.elements.namedItem('name') as HTMLInputElement).value; const name = (form.elements.namedItem('name') as HTMLInputElement).value;
const slug = (form.elements.namedItem('slug') as HTMLInputElement).value; const slug = (form.elements.namedItem('slug') as HTMLInputElement).value;
const admin_email = (form.elements.namedItem('admin_email') as HTMLInputElement).value; const admin_email = (form.elements.namedItem('admin_email') as HTMLInputElement).value;
const status = (form.elements.namedItem('status') as HTMLSelectElement).value; const status = (form.elements.namedItem('status') as HTMLSelectElement).value;
if (editingTenant) { try {
const success = await updateTenant(editingTenant.id, { name, slug, admin_email, status }); if (editingTenant) {
if (success) { const success = await updateTenant(editingTenant.id, { name, slug, admin_email, status });
setSuccessMessage('Organização atualizada com sucesso!'); if (success) {
loadTenants(); setSuccessMessage('Organização atualizada com sucesso!');
setTimeout(() => { loadTenants();
setIsModalOpen(false); setTimeout(() => {
setSuccessMessage(''); setIsModalOpen(false);
setEditingTenant(null); setSuccessMessage('');
}, 2000); setEditingTenant(null);
setIsSaving(false);
}, 2000);
} else {
setErrorMessage('Erro ao atualizar organização.');
setIsSaving(false);
}
} else { } else {
setErrorMessage('Erro ao atualizar organização.'); const result = await createTenant({ name, slug, admin_email, status });
} if (result.success) {
} else { setSuccessMessage(result.message || 'Organização criada com sucesso!');
const result = await createTenant({ name, slug, admin_email, status }); loadTenants();
if (result.success) { setTimeout(() => {
setSuccessMessage(result.message || 'Organização criada com sucesso!'); setIsModalOpen(false);
loadTenants(); setSuccessMessage('');
setTimeout(() => { setIsSaving(false);
setIsModalOpen(false); }, 3000);
setSuccessMessage(''); } else {
}, 3000); setErrorMessage(result.message || 'Erro ao salvar organização.');
} else { setIsSaving(false);
setErrorMessage(result.message || 'Erro ao salvar organização.'); }
} }
} catch (err) {
setErrorMessage('Ocorreu um erro inesperado.');
setIsSaving(false);
} }
}; };
@@ -282,7 +292,9 @@ export const SuperAdmin: React.FC = () => {
</div> </div>
<div className="pt-4 flex justify-end gap-3 border-t dark:border-dark-border mt-6"> <div className="pt-4 flex justify-end gap-3 border-t dark:border-dark-border mt-6">
<button type="button" onClick={() => setIsModalOpen(false)} className="px-4 py-2 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-dark-border rounded-lg text-sm font-medium transition-colors">Cancelar</button> <button type="button" onClick={() => setIsModalOpen(false)} className="px-4 py-2 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-dark-border rounded-lg text-sm font-medium transition-colors">Cancelar</button>
<button type="submit" className="px-4 py-2 bg-zinc-900 dark:bg-brand-yellow text-white dark:text-zinc-950 rounded-lg text-sm font-bold hover:opacity-90 transition-all shadow-sm">{editingTenant ? 'Salvar Alterações' : 'Criar Organização'}</button> <button type="submit" disabled={isSaving} className="px-4 py-2 bg-zinc-900 dark:bg-brand-yellow text-white dark:text-zinc-950 rounded-lg text-sm font-bold flex items-center gap-2 hover:opacity-90 transition-all shadow-sm disabled:opacity-70">
{isSaving ? <Loader2 className="animate-spin" size={16} /> : (editingTenant ? 'Salvar Alterações' : 'Criar Organização')}
</button>
</div> </div>
</form> </form>
</div> </div>