Compare commits
1 Commits
main
...
codex/cria
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d87744dd2 |
@ -1,6 +1,6 @@
|
||||
# Audit360 Hotéis
|
||||
# Audit360 Motéis
|
||||
|
||||
Aplicativo web em React + TypeScript para auditorias de hotéis. O projeto foi criado manualmente com Vite e utiliza um backend simulado via `localStorage`.
|
||||
Aplicativo web em React + TypeScript para auditorias de motéis. O projeto foi criado manualmente com Vite e utiliza um backend simulado via `localStorage`.
|
||||
|
||||
## Scripts
|
||||
|
||||
@ -13,5 +13,7 @@ Aplicativo web em React + TypeScript para auditorias de hotéis. O projeto foi c
|
||||
- Dashboard com listagem de auditorias e botão para iniciar novas auditorias.
|
||||
- Formulários de checklist com opções "Conforme", "Não conforme leve", "Não conforme grave" e upload de fotos.
|
||||
- Relatórios filtrados por unidade, data e responsável.
|
||||
- Agenda de reuniões com cadastro de encontros.
|
||||
- Tela de performance das gestoras (blackbelts) com resumo de auditorias.
|
||||
|
||||
As informações são salvas no `localStorage` do navegador e as imagens ficam codificadas em base64.
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Audit360 Hotéis</title>
|
||||
<title>Audit360 Motéis</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
10
src/App.tsx
10
src/App.tsx
@ -3,6 +3,8 @@ import Login from './pages/Login';
|
||||
import Dashboard from './pages/Dashboard';
|
||||
import AuditForm from './pages/AuditForm';
|
||||
import Reports from './pages/Reports';
|
||||
import Meetings from './pages/Meetings';
|
||||
import Performance from './pages/Performance';
|
||||
import Header from './components/Header';
|
||||
import { useAuth } from './auth';
|
||||
|
||||
@ -30,6 +32,14 @@ export default function App() {
|
||||
path="/reports"
|
||||
element={<PrivateRoute><Reports /></PrivateRoute>}
|
||||
/>
|
||||
<Route
|
||||
path="/meetings"
|
||||
element={<PrivateRoute><Meetings /></PrivateRoute>}
|
||||
/>
|
||||
<Route
|
||||
path="/performance"
|
||||
element={<PrivateRoute><Performance /></PrivateRoute>}
|
||||
/>
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -5,10 +5,12 @@ export default function Header() {
|
||||
const { user, logout } = useAuth();
|
||||
return (
|
||||
<header>
|
||||
<h1>Audit360 Hotéis</h1>
|
||||
<h1>Audit360 Motéis</h1>
|
||||
<nav>
|
||||
<Link to="/">Auditorias</Link>
|
||||
<Link to="/reports">Relatórios</Link>
|
||||
<Link to="/meetings">Reuniões</Link>
|
||||
<Link to="/performance">Performance</Link>
|
||||
</nav>
|
||||
<div>
|
||||
{user && (
|
||||
|
||||
55
src/pages/Meetings.tsx
Normal file
55
src/pages/Meetings.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import { useEffect, useState, FormEvent } from 'react';
|
||||
import { useAuth } from '../auth';
|
||||
import { Meeting } from '../types';
|
||||
|
||||
export default function Meetings() {
|
||||
const { user } = useAuth();
|
||||
const [meetings, setMeetings] = useState<Meeting[]>([]);
|
||||
const [date, setDate] = useState('');
|
||||
const [subject, setSubject] = useState('');
|
||||
const [participants, setParticipants] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const stored = localStorage.getItem('meetings');
|
||||
if (stored) setMeetings(JSON.parse(stored));
|
||||
}, []);
|
||||
|
||||
const handleSubmit = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
const newMeeting: Meeting = {
|
||||
id: Date.now(),
|
||||
date,
|
||||
subject,
|
||||
participants,
|
||||
};
|
||||
const updated = [...meetings, newMeeting];
|
||||
setMeetings(updated);
|
||||
localStorage.setItem('meetings', JSON.stringify(updated));
|
||||
setDate('');
|
||||
setSubject('');
|
||||
setParticipants('');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<h2>Reuniões</h2>
|
||||
{user?.role !== 'Supervisor' && (
|
||||
<form onSubmit={handleSubmit} style={{ marginBottom: '1rem' }}>
|
||||
<label>Data</label>
|
||||
<input type="date" value={date} onChange={(e) => setDate(e.target.value)} required />
|
||||
<label>Assunto</label>
|
||||
<input value={subject} onChange={(e) => setSubject(e.target.value)} required />
|
||||
<label>Participantes</label>
|
||||
<input value={participants} onChange={(e) => setParticipants(e.target.value)} required />
|
||||
<button type="submit">Agendar</button>
|
||||
</form>
|
||||
)}
|
||||
{meetings.map((m) => (
|
||||
<div key={m.id} className="audit-item">
|
||||
<strong>{m.date}</strong> - {m.subject} - {m.participants}
|
||||
</div>
|
||||
))}
|
||||
{meetings.length === 0 && <p>Nenhuma reunião agendada.</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
42
src/pages/Performance.tsx
Normal file
42
src/pages/Performance.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Audit } from '../types';
|
||||
|
||||
interface Metric {
|
||||
responsible: string;
|
||||
total: number;
|
||||
severe: number;
|
||||
}
|
||||
|
||||
export default function Performance() {
|
||||
const [metrics, setMetrics] = useState<Metric[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const stored = localStorage.getItem('audits');
|
||||
if (stored) {
|
||||
const audits: Audit[] = JSON.parse(stored);
|
||||
const map: Record<string, Metric> = {};
|
||||
audits.forEach((a) => {
|
||||
if (!map[a.responsible]) {
|
||||
map[a.responsible] = { responsible: a.responsible, total: 0, severe: 0 };
|
||||
}
|
||||
map[a.responsible].total += 1;
|
||||
if (a.answers.some((ans) => ans.status === 'Não conforme grave')) {
|
||||
map[a.responsible].severe += 1;
|
||||
}
|
||||
});
|
||||
setMetrics(Object.values(map));
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<h2>Performance das Blackbelts</h2>
|
||||
{metrics.map((m) => (
|
||||
<div key={m.responsible} className="audit-item">
|
||||
<strong>{m.responsible}</strong> - Auditorias: {m.total} - Ocorrências graves: {m.severe}
|
||||
</div>
|
||||
))}
|
||||
{metrics.length === 0 && <p>Nenhuma auditoria registrada.</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -10,3 +10,10 @@ export interface Audit {
|
||||
responsible: string;
|
||||
answers: AuditAnswer[];
|
||||
}
|
||||
|
||||
export interface Meeting {
|
||||
id: number;
|
||||
date: string;
|
||||
subject: string;
|
||||
participants: string;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user