Spaces:
Running
Running
Guilherme Silberfarb Costa commited on
Commit ·
918e0df
1
Parent(s): 385f196
correcao de erro de login
Browse files- frontend/src/App.jsx +31 -9
- frontend/src/api.js +20 -7
frontend/src/App.jsx
CHANGED
|
@@ -39,6 +39,21 @@ export default function App() {
|
|
| 39 |
const logsEnabled = Boolean(logsStatus?.enabled)
|
| 40 |
const logsDisabledReason = String(logsStatus?.reason || 'Logs indisponíveis')
|
| 41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
useEffect(() => {
|
| 43 |
let mounted = true
|
| 44 |
|
|
@@ -69,6 +84,18 @@ export default function App() {
|
|
| 69 |
}
|
| 70 |
}, [])
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
useEffect(() => {
|
| 73 |
let mounted = true
|
| 74 |
|
|
@@ -88,7 +115,9 @@ export default function App() {
|
|
| 88 |
setBootError('')
|
| 89 |
})
|
| 90 |
.catch((err) => {
|
| 91 |
-
if (mounted)
|
|
|
|
|
|
|
| 92 |
})
|
| 93 |
|
| 94 |
return () => {
|
|
@@ -137,14 +166,7 @@ export default function App() {
|
|
| 137 |
} catch {
|
| 138 |
// Ignore falha de logout remoto para garantir limpeza local.
|
| 139 |
}
|
| 140 |
-
|
| 141 |
-
setAuthUser(null)
|
| 142 |
-
setSessionId('')
|
| 143 |
-
setLogsStatus(null)
|
| 144 |
-
setLogsOpen(false)
|
| 145 |
-
setLogsEvents([])
|
| 146 |
-
setLogsError('')
|
| 147 |
-
setActiveTab(TABS[0].key)
|
| 148 |
}
|
| 149 |
|
| 150 |
async function carregarLogsStatus() {
|
|
|
|
| 39 |
const logsEnabled = Boolean(logsStatus?.enabled)
|
| 40 |
const logsDisabledReason = String(logsStatus?.reason || 'Logs indisponíveis')
|
| 41 |
|
| 42 |
+
function resetToLogin(message = '') {
|
| 43 |
+
setAuthToken('')
|
| 44 |
+
setAuthUser(null)
|
| 45 |
+
setAuthLoading(false)
|
| 46 |
+
setLoginLoading(false)
|
| 47 |
+
setSessionId('')
|
| 48 |
+
setBootError('')
|
| 49 |
+
setLogsStatus(null)
|
| 50 |
+
setLogsOpen(false)
|
| 51 |
+
setLogsEvents([])
|
| 52 |
+
setLogsError('')
|
| 53 |
+
setActiveTab(TABS[0].key)
|
| 54 |
+
setAuthError(message)
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
useEffect(() => {
|
| 58 |
let mounted = true
|
| 59 |
|
|
|
|
| 84 |
}
|
| 85 |
}, [])
|
| 86 |
|
| 87 |
+
useEffect(() => {
|
| 88 |
+
function onAuthRequired(event) {
|
| 89 |
+
const message = String(event?.detail?.message || '').trim() || 'Sessão expirada. Faça login novamente.'
|
| 90 |
+
resetToLogin(message)
|
| 91 |
+
}
|
| 92 |
+
if (typeof window !== 'undefined') {
|
| 93 |
+
window.addEventListener('mesa:auth-required', onAuthRequired)
|
| 94 |
+
return () => window.removeEventListener('mesa:auth-required', onAuthRequired)
|
| 95 |
+
}
|
| 96 |
+
return undefined
|
| 97 |
+
}, [])
|
| 98 |
+
|
| 99 |
useEffect(() => {
|
| 100 |
let mounted = true
|
| 101 |
|
|
|
|
| 115 |
setBootError('')
|
| 116 |
})
|
| 117 |
.catch((err) => {
|
| 118 |
+
if (!mounted) return
|
| 119 |
+
if (Number(err?.status) === 401) return
|
| 120 |
+
setBootError(err.message || 'Falha ao criar sessão')
|
| 121 |
})
|
| 122 |
|
| 123 |
return () => {
|
|
|
|
| 166 |
} catch {
|
| 167 |
// Ignore falha de logout remoto para garantir limpeza local.
|
| 168 |
}
|
| 169 |
+
resetToLogin('')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
}
|
| 171 |
|
| 172 |
async function carregarLogsStatus() {
|
frontend/src/api.js
CHANGED
|
@@ -27,7 +27,13 @@ function authHeaders(extraHeaders = {}) {
|
|
| 27 |
return headers
|
| 28 |
}
|
| 29 |
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
if (!response.ok) {
|
| 32 |
let detail = 'Erro inesperado'
|
| 33 |
try {
|
|
@@ -36,7 +42,14 @@ async function handleResponse(response) {
|
|
| 36 |
} catch {
|
| 37 |
detail = response.statusText || detail
|
| 38 |
}
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
}
|
| 41 |
return response
|
| 42 |
}
|
|
@@ -47,7 +60,7 @@ async function postJson(path, body) {
|
|
| 47 |
headers: authHeaders({ 'Content-Type': 'application/json' }),
|
| 48 |
body: JSON.stringify(body),
|
| 49 |
})
|
| 50 |
-
await handleResponse(response)
|
| 51 |
return response.json()
|
| 52 |
}
|
| 53 |
|
|
@@ -57,19 +70,19 @@ async function postForm(path, formData) {
|
|
| 57 |
headers: authHeaders(),
|
| 58 |
body: formData,
|
| 59 |
})
|
| 60 |
-
await handleResponse(response)
|
| 61 |
return response.json()
|
| 62 |
}
|
| 63 |
|
| 64 |
async function getJson(path) {
|
| 65 |
const response = await fetch(`${API_BASE}${path}`, { headers: authHeaders() })
|
| 66 |
-
await handleResponse(response)
|
| 67 |
return response.json()
|
| 68 |
}
|
| 69 |
|
| 70 |
async function getBlob(path) {
|
| 71 |
const response = await fetch(`${API_BASE}${path}`, { headers: authHeaders() })
|
| 72 |
-
await handleResponse(response)
|
| 73 |
return response.blob()
|
| 74 |
}
|
| 75 |
|
|
@@ -183,7 +196,7 @@ export const api = {
|
|
| 183 |
headers: authHeaders({ 'Content-Type': 'application/json' }),
|
| 184 |
body: JSON.stringify({ session_id: sessionId, nome_arquivo: nomeArquivo, elaborador }),
|
| 185 |
})
|
| 186 |
-
await handleResponse(response)
|
| 187 |
return response.blob()
|
| 188 |
},
|
| 189 |
exportBase: (sessionId, filtered = true) => getBlob(`/api/elaboracao/export-base?session_id=${encodeURIComponent(sessionId)}&filtered=${String(filtered)}`),
|
|
|
|
| 27 |
return headers
|
| 28 |
}
|
| 29 |
|
| 30 |
+
function emitAuthRequired(detail = 'Login obrigatorio') {
|
| 31 |
+
if (typeof window === 'undefined') return
|
| 32 |
+
const event = new CustomEvent('mesa:auth-required', { detail: { message: detail } })
|
| 33 |
+
window.dispatchEvent(event)
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
async function handleResponse(response, path = '') {
|
| 37 |
if (!response.ok) {
|
| 38 |
let detail = 'Erro inesperado'
|
| 39 |
try {
|
|
|
|
| 42 |
} catch {
|
| 43 |
detail = response.statusText || detail
|
| 44 |
}
|
| 45 |
+
if (response.status === 401 && path !== '/api/auth/login') {
|
| 46 |
+
setAuthToken('')
|
| 47 |
+
emitAuthRequired(detail)
|
| 48 |
+
}
|
| 49 |
+
const error = new Error(detail)
|
| 50 |
+
error.status = response.status
|
| 51 |
+
error.path = path
|
| 52 |
+
throw error
|
| 53 |
}
|
| 54 |
return response
|
| 55 |
}
|
|
|
|
| 60 |
headers: authHeaders({ 'Content-Type': 'application/json' }),
|
| 61 |
body: JSON.stringify(body),
|
| 62 |
})
|
| 63 |
+
await handleResponse(response, path)
|
| 64 |
return response.json()
|
| 65 |
}
|
| 66 |
|
|
|
|
| 70 |
headers: authHeaders(),
|
| 71 |
body: formData,
|
| 72 |
})
|
| 73 |
+
await handleResponse(response, path)
|
| 74 |
return response.json()
|
| 75 |
}
|
| 76 |
|
| 77 |
async function getJson(path) {
|
| 78 |
const response = await fetch(`${API_BASE}${path}`, { headers: authHeaders() })
|
| 79 |
+
await handleResponse(response, path)
|
| 80 |
return response.json()
|
| 81 |
}
|
| 82 |
|
| 83 |
async function getBlob(path) {
|
| 84 |
const response = await fetch(`${API_BASE}${path}`, { headers: authHeaders() })
|
| 85 |
+
await handleResponse(response, path)
|
| 86 |
return response.blob()
|
| 87 |
}
|
| 88 |
|
|
|
|
| 196 |
headers: authHeaders({ 'Content-Type': 'application/json' }),
|
| 197 |
body: JSON.stringify({ session_id: sessionId, nome_arquivo: nomeArquivo, elaborador }),
|
| 198 |
})
|
| 199 |
+
await handleResponse(response, '/api/elaboracao/export-model')
|
| 200 |
return response.blob()
|
| 201 |
},
|
| 202 |
exportBase: (sessionId, filtered = true) => getBlob(`/api/elaboracao/export-base?session_id=${encodeURIComponent(sessionId)}&filtered=${String(filtered)}`),
|