feat: replace mock system with real backend, RBAC, and Teams management
All checks were successful
Build and Deploy / build-and-push (push) Successful in 2m3s

- Implemented real JWT authentication and persistent user sessions
- Replaced all hardcoded mock data with dynamic MySQL-backed API calls
- Created new 'Times' (Teams) dashboard with performance metrics
- Renamed 'Equipe' to 'Membros' and centralized team management
- Added Role-Based Access Control (RBAC) for Admin/Manager/Agent roles
- Implemented secure invite-only member creation and password setup flow
- Enhanced Login with password visibility and real-time validation
- Added safe delete confirmation modal and custom Toast notifications
This commit is contained in:
Cauê Faleiros
2026-03-02 10:26:20 -03:00
parent 76b919d857
commit b7e73fce3d
19 changed files with 1707 additions and 553 deletions

View File

@@ -5,8 +5,8 @@ import {
import {
Users, Clock, Phone, TrendingUp, Filter
} from 'lucide-react';
import { getAttendances, getUsers } from '../services/dataService';
import { CURRENT_TENANT_ID, COLORS } from '../constants';
import { getAttendances, getUsers, getTeams } from '../services/dataService';
import { COLORS } from '../constants';
import { Attendance, DashboardFilter, FunnelStage, User } from '../types';
import { KPICard } from '../components/KPICard';
import { DateRangePicker } from '../components/DateRangePicker';
@@ -26,6 +26,7 @@ export const Dashboard: React.FC = () => {
const [loading, setLoading] = useState(true);
const [data, setData] = useState<Attendance[]>([]);
const [users, setUsers] = useState<User[]>([]);
const [teams, setTeams] = useState<any[]>([]);
const [filters, setFilters] = useState<DashboardFilter>({
dateRange: {
@@ -40,14 +41,19 @@ export const Dashboard: React.FC = () => {
const fetchData = async () => {
setLoading(true);
try {
// Fetch users and attendances in parallel
const [fetchedUsers, fetchedData] = await Promise.all([
getUsers(CURRENT_TENANT_ID),
getAttendances(CURRENT_TENANT_ID, filters)
const tenantId = localStorage.getItem('ctms_tenant_id');
if (!tenantId) return;
// Fetch users, attendances and teams in parallel
const [fetchedUsers, fetchedData, fetchedTeams] = await Promise.all([
getUsers(tenantId),
getAttendances(tenantId, filters),
getTeams(tenantId)
]);
setUsers(fetchedUsers);
setData(fetchedData);
setTeams(fetchedTeams);
} catch (error) {
console.error("Error loading dashboard data:", error);
} finally {
@@ -158,7 +164,7 @@ export const Dashboard: React.FC = () => {
};
if (loading && data.length === 0) {
return <div className="flex h-full items-center justify-center text-slate-400">Carregando Dashboard...</div>;
return <div className="flex h-full items-center justify-center text-slate-400 p-12">Carregando Dashboard...</div>;
}
return (
@@ -191,8 +197,7 @@ export const Dashboard: React.FC = () => {
onChange={(e) => handleFilterChange('teamId', e.target.value)}
>
<option value="all">Todas Equipes</option>
<option value="sales_1">Vendas Alpha</option>
<option value="sales_2">Vendas Beta</option>
{teams.map(t => <option key={t.id} value={t.id}>{t.name}</option>)}
</select>
</div>
</div>
@@ -311,4 +316,4 @@ export const Dashboard: React.FC = () => {
<ProductLists requested={productStats.requested} sold={productStats.sold} />
</div>
);
};
};