-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrorMessages.ts
More file actions
458 lines (415 loc) · 13.2 KB
/
errorMessages.ts
File metadata and controls
458 lines (415 loc) · 13.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
/**
* Helper para traduzir mensagens de erro técnicas em mensagens amigáveis
* em múltiplos idiomas (PT, EN, ES)
*/
import type { Locale } from './i18n/translations'
export interface FriendlyError {
message: string
suggestion?: string
code?: string
}
type ErrorTranslations = {
message: string
suggestion?: string
}
type ErrorMessages = Record<string, Record<Locale, ErrorTranslations>>
// Catálogo de mensagens de erro em múltiplos idiomas
const ERROR_CATALOG: ErrorMessages = {
// Erros de autenticação
AUTH_INVALID_CREDENTIALS: {
pt: {
message: 'E-mail ou senha incorretos.',
suggestion: 'Verifique seus dados ou use o link mágico para acessar.'
},
en: {
message: 'Incorrect email or password.',
suggestion: 'Check your credentials or use the magic link to access.'
},
es: {
message: 'Correo o contraseña incorrectos.',
suggestion: 'Verifica tus datos o usa el enlace mágico para acceder.'
}
},
AUTH_EMAIL_NOT_CONFIRMED: {
pt: {
message: 'Esta conta ainda não foi confirmada.',
suggestion: 'Verifique seu e-mail e clique no link de confirmação.'
},
en: {
message: 'This account has not been confirmed yet.',
suggestion: 'Check your email and click the confirmation link.'
},
es: {
message: 'Esta cuenta aún no ha sido confirmada.',
suggestion: 'Verifica tu correo y haz clic en el enlace de confirmación.'
}
},
AUTH_USER_EXISTS: {
pt: {
message: 'Este e-mail já está cadastrado.',
suggestion: 'Tente fazer login ou use a opção "Esqueci minha senha".'
},
en: {
message: 'This email is already registered.',
suggestion: 'Try logging in or use "Forgot password".'
},
es: {
message: 'Este correo ya está registrado.',
suggestion: 'Intenta iniciar sesión o usa "Olvidé mi contraseña".'
}
},
AUTH_SIGNUP_DISABLED: {
pt: {
message: 'Cadastros temporariamente desabilitados.',
suggestion: 'Entre em contato com o suporte para mais informações.'
},
en: {
message: 'Signups temporarily disabled.',
suggestion: 'Contact support for more information.'
},
es: {
message: 'Registros temporalmente deshabilitados.',
suggestion: 'Contacta con soporte para más información.'
}
},
RATE_LIMIT_EXCEEDED: {
pt: {
message: 'Muitas tentativas em pouco tempo.',
suggestion: 'Aguarde alguns minutos e tente novamente.'
},
en: {
message: 'Too many attempts in a short time.',
suggestion: 'Wait a few minutes and try again.'
},
es: {
message: 'Demasiados intentos en poco tiempo.',
suggestion: 'Espera unos minutos e inténtalo de nuevo.'
}
},
SESSION_EXPIRED: {
pt: {
message: 'Sua sessão expirou.',
suggestion: 'Por favor, faça login novamente para continuar.'
},
en: {
message: 'Your session has expired.',
suggestion: 'Please log in again to continue.'
},
es: {
message: 'Tu sesión ha expirado.',
suggestion: 'Por favor, inicia sesión nuevamente para continuar.'
}
},
// Erros de validação
VALIDATION_EMAIL: {
pt: {
message: 'E-mail inválido.',
suggestion: 'Digite um endereço de e-mail válido (exemplo@dominio.com).'
},
en: {
message: 'Invalid email.',
suggestion: 'Enter a valid email address (example@domain.com).'
},
es: {
message: 'Correo inválido.',
suggestion: 'Ingresa una dirección de correo válida (ejemplo@dominio.com).'
}
},
VALIDATION_PASSWORD_LENGTH: {
pt: {
message: 'Senha muito curta.',
suggestion: 'Sua senha deve ter pelo menos 6 caracteres.'
},
en: {
message: 'Password too short.',
suggestion: 'Your password must be at least 6 characters long.'
},
es: {
message: 'Contraseña muy corta.',
suggestion: 'Tu contraseña debe tener al menos 6 caracteres.'
}
},
VALIDATION_REQUIRED: {
pt: {
message: 'Campos obrigatórios não preenchidos.',
suggestion: 'Preencha todos os campos marcados como obrigatórios.'
},
en: {
message: 'Required fields not filled.',
suggestion: 'Fill in all fields marked as required.'
},
es: {
message: 'Campos obligatorios no completados.',
suggestion: 'Completa todos los campos marcados como obligatorios.'
}
},
// Erros de arquivo
FILE_TOO_LARGE: {
pt: {
message: 'Arquivo muito grande.',
suggestion: 'O arquivo deve ter no máximo 10MB. Tente comprimir ou usar outro arquivo.'
},
en: {
message: 'File too large.',
suggestion: 'File must be at most 10MB. Try compressing or using another file.'
},
es: {
message: 'Archivo demasiado grande.',
suggestion: 'El archivo debe tener un máximo de 10MB. Intenta comprimir u usar otro archivo.'
}
},
FILE_INVALID_TYPE: {
pt: {
message: 'Tipo de arquivo não suportado.',
suggestion: 'Use apenas arquivos PDF para documentos e PNG/JPG para assinaturas.'
},
en: {
message: 'Unsupported file type.',
suggestion: 'Use only PDF files for documents and PNG/JPG for signatures.'
},
es: {
message: 'Tipo de archivo no compatible.',
suggestion: 'Usa solo archivos PDF para documentos y PNG/JPG para firmas.'
}
},
STORAGE_ERROR: {
pt: {
message: 'Erro ao salvar arquivo.',
suggestion: 'Verifique sua conexão e tente novamente.'
},
en: {
message: 'Error saving file.',
suggestion: 'Check your connection and try again.'
},
es: {
message: 'Error al guardar archivo.',
suggestion: 'Verifica tu conexión e inténtalo de nuevo.'
}
},
// Erros de rede
NETWORK_ERROR: {
pt: {
message: 'Erro de conexão.',
suggestion: 'Verifique sua internet e tente novamente.'
},
en: {
message: 'Connection error.',
suggestion: 'Check your internet and try again.'
},
es: {
message: 'Error de conexión.',
suggestion: 'Verifica tu internet e inténtalo de nuevo.'
}
},
TIMEOUT: {
pt: {
message: 'A operação demorou muito.',
suggestion: 'O servidor não respondeu a tempo. Tente novamente.'
},
en: {
message: 'Operation took too long.',
suggestion: 'Server did not respond in time. Try again.'
},
es: {
message: 'La operación tardó demasiado.',
suggestion: 'El servidor no respondió a tiempo. Inténtalo de nuevo.'
}
},
// Erros de permissão
PERMISSION_DENIED: {
pt: {
message: 'Você não tem permissão para esta ação.',
suggestion: 'Entre em contato com o administrador se precisar de acesso.'
},
en: {
message: 'You do not have permission for this action.',
suggestion: 'Contact the administrator if you need access.'
},
es: {
message: 'No tienes permiso para esta acción.',
suggestion: 'Contacta con el administrador si necesitas acceso.'
}
},
// Erros genéricos
SERVER_ERROR: {
pt: {
message: 'Erro interno do servidor.',
suggestion: 'Ocorreu um erro inesperado. Tente novamente em alguns minutos.'
},
en: {
message: 'Internal server error.',
suggestion: 'An unexpected error occurred. Try again in a few minutes.'
},
es: {
message: 'Error interno del servidor.',
suggestion: 'Ocurrió un error inesperado. Inténtalo de nuevo en unos minutos.'
}
},
NOT_FOUND: {
pt: {
message: 'Recurso não encontrado.',
suggestion: 'O item que você procura não existe ou foi removido.'
},
en: {
message: 'Resource not found.',
suggestion: 'The item you are looking for does not exist or has been removed.'
},
es: {
message: 'Recurso no encontrado.',
suggestion: 'El elemento que buscas no existe o ha sido eliminado.'
}
},
UNKNOWN_ERROR: {
pt: {
message: 'Ocorreu um erro inesperado.',
suggestion: 'Por favor, tente novamente. Se o problema persistir, entre em contato com o suporte.'
},
en: {
message: 'An unexpected error occurred.',
suggestion: 'Please try again. If the problem persists, contact support.'
},
es: {
message: 'Ocurrió un error inesperado.',
suggestion: 'Por favor, inténtalo de nuevo. Si el problema persiste, contacta con soporte.'
}
},
UNAUTHORIZED: {
pt: {
message: 'Por favor, faça login para acessar este recurso.',
suggestion: 'Você precisa estar autenticado para realizar esta ação.'
},
en: {
message: 'Please log in to access this resource.',
suggestion: 'You need to be authenticated to perform this action.'
},
es: {
message: 'Por favor, inicia sesión para acceder a este recurso.',
suggestion: 'Necesitas estar autenticado para realizar esta acción.'
}
},
}
/**
* Detecta o idioma do navegador ou retorna português como padrão
*/
function detectLocale(): Locale {
if (typeof window === 'undefined') return 'pt'
// Tentar pegar do localStorage primeiro
const stored = localStorage.getItem('locale')
if (stored && ['pt', 'en', 'es'].includes(stored)) {
return stored as Locale
}
// Detectar do navegador
const lang = navigator.language.toLowerCase()
if (lang.startsWith('en')) return 'en'
if (lang.startsWith('es')) return 'es'
return 'pt' // Padrão
}
/**
* Identifica o código de erro baseado na mensagem
*/
function identifyErrorCode(error: any): string {
const errorMessage = error?.message || error?.error_description || String(error)
const errorCode = error?.code || error?.error || ''
// Autenticação
if (errorMessage.includes('Invalid login credentials') || errorCode === '401') {
return 'AUTH_INVALID_CREDENTIALS'
}
if (errorMessage.includes('Email not confirmed') || errorMessage.includes('User not found')) {
return 'AUTH_EMAIL_NOT_CONFIRMED'
}
if (errorMessage.includes('User already registered') || errorCode === '23505') {
return 'AUTH_USER_EXISTS'
}
if (errorMessage.includes('Signups not allowed') || errorMessage.includes('signup disabled')) {
return 'AUTH_SIGNUP_DISABLED'
}
if (errorMessage.includes('Email rate limit exceeded') || errorMessage.includes('too many requests')) {
return 'RATE_LIMIT_EXCEEDED'
}
if (errorMessage.includes('session_not_found') || errorMessage.includes('not authenticated')) {
return 'SESSION_EXPIRED'
}
// Validação
if (errorMessage.includes('invalid email') || errorMessage.includes('email is not valid')) {
return 'VALIDATION_EMAIL'
}
if (errorMessage.includes('password') && errorMessage.includes('too short')) {
return 'VALIDATION_PASSWORD_LENGTH'
}
if (errorMessage.includes('required') || errorMessage.includes('cannot be null')) {
return 'VALIDATION_REQUIRED'
}
// Arquivo
if (errorMessage.includes('file size') || errorMessage.includes('payload too large')) {
return 'FILE_TOO_LARGE'
}
if (errorMessage.includes('file type') || errorMessage.includes('invalid format')) {
return 'FILE_INVALID_TYPE'
}
if (errorMessage.includes('storage')) {
return 'STORAGE_ERROR'
}
// Rede
if (errorMessage.includes('fetch') || errorMessage.includes('network') || errorMessage.includes('ECONNREFUSED')) {
return 'NETWORK_ERROR'
}
if (errorMessage.includes('timeout')) {
return 'TIMEOUT'
}
// Permissão
if (errorCode === '403' || errorMessage.includes('forbidden') || errorMessage.includes('permission denied')) {
return 'PERMISSION_DENIED'
}
if (errorCode === 'UNAUTHORIZED' || errorMessage.includes('UNAUTHORIZED')) {
return 'UNAUTHORIZED'
}
// Genéricos
if (errorCode === '500' || errorMessage.includes('internal server error')) {
return 'SERVER_ERROR'
}
if (errorCode === '404' || errorMessage.includes('not found')) {
return 'NOT_FOUND'
}
return 'UNKNOWN_ERROR'
}
/**
* Converte erros técnicos em mensagens amigáveis no idioma especificado
*/
export function getFriendlyErrorMessage(error: any, locale?: Locale): FriendlyError {
// Se já é uma string simples, retornar diretamente
if (typeof error === 'string') {
return { message: error }
}
const detectedLocale = locale || detectLocale()
const errorCode = identifyErrorCode(error)
const translation = ERROR_CATALOG[errorCode]?.[detectedLocale] ||
ERROR_CATALOG[errorCode]?.pt ||
ERROR_CATALOG.UNKNOWN_ERROR[detectedLocale]
return {
message: translation.message,
suggestion: translation.suggestion,
code: errorCode
}
}
/**
* Formata o erro para exibição ao usuário
*/
export function formatErrorForDisplay(error: any, locale?: Locale): string {
const friendly = getFriendlyErrorMessage(error, locale)
if (friendly.suggestion) {
return `${friendly.message} ${friendly.suggestion}`
}
return friendly.message
}
/**
* Retorna apenas a mensagem principal sem sugestão
*/
export function getErrorMessage(error: any, locale?: Locale): string {
return getFriendlyErrorMessage(error, locale).message
}
/**
* Retorna apenas a sugestão
*/
export function getErrorSuggestion(error: any, locale?: Locale): string | undefined {
return getFriendlyErrorMessage(error, locale).suggestion
}