@acvl/mobile-components 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/README.md +14 -0
  2. package/lib/module/camara/CampoDeFotos.js +4 -2
  3. package/lib/module/camara/CampoDeFotos.js.map +1 -1
  4. package/lib/module/camara/elegir.js +4 -3
  5. package/lib/module/camara/elegir.js.map +1 -1
  6. package/lib/module/componentes/AccionesDelEncabezado.js +3 -1
  7. package/lib/module/componentes/AccionesDelEncabezado.js.map +1 -1
  8. package/lib/module/componentes/BotonDeAvatar.js +24 -20
  9. package/lib/module/componentes/BotonDeAvatar.js.map +1 -1
  10. package/lib/module/componentes/CabeceraEmpujada.js +3 -1
  11. package/lib/module/componentes/CabeceraEmpujada.js.map +1 -1
  12. package/lib/module/componentes/PantallaDeError.js +6 -4
  13. package/lib/module/componentes/PantallaDeError.js.map +1 -1
  14. package/lib/module/componentes/TiraDeFotos.js +4 -2
  15. package/lib/module/componentes/TiraDeFotos.js.map +1 -1
  16. package/lib/module/componentes/VisorDeFoto.js +6 -4
  17. package/lib/module/componentes/VisorDeFoto.js.map +1 -1
  18. package/lib/module/dialogos/HostDeDialogos.js +3 -1
  19. package/lib/module/dialogos/HostDeDialogos.js.map +1 -1
  20. package/lib/module/dialogos/dialogos.js +6 -4
  21. package/lib/module/dialogos/dialogos.js.map +1 -1
  22. package/lib/module/formularios/SelectorDeOpcion.js +13 -7
  23. package/lib/module/formularios/SelectorDeOpcion.js.map +1 -1
  24. package/lib/module/formularios/campos.js +9 -4
  25. package/lib/module/formularios/campos.js.map +1 -1
  26. package/lib/module/formularios/guardado.js +4 -2
  27. package/lib/module/formularios/guardado.js.map +1 -1
  28. package/lib/module/fotos/elegir.js +10 -8
  29. package/lib/module/fotos/elegir.js.map +1 -1
  30. package/lib/module/hoja/HojaDeLista.js +5 -3
  31. package/lib/module/hoja/HojaDeLista.js.map +1 -1
  32. package/lib/module/hoja/useMasDeLaFicha.js +3 -1
  33. package/lib/module/hoja/useMasDeLaFicha.js.map +1 -1
  34. package/lib/module/idioma/ProveedorDeIdioma.js +54 -0
  35. package/lib/module/idioma/ProveedorDeIdioma.js.map +1 -0
  36. package/lib/module/idioma/index.js +4 -0
  37. package/lib/module/idioma/index.js.map +1 -0
  38. package/lib/module/idioma/textos.js +237 -0
  39. package/lib/module/idioma/textos.js.map +1 -0
  40. package/lib/module/index.js +4 -0
  41. package/lib/module/index.js.map +1 -1
  42. package/lib/module/listas/HojaDeFiltros.js +11 -8
  43. package/lib/module/listas/HojaDeFiltros.js.map +1 -1
  44. package/lib/module/listas/ListaPaginada.js +6 -4
  45. package/lib/module/listas/ListaPaginada.js.map +1 -1
  46. package/lib/module/listas/piezas.js +13 -7
  47. package/lib/module/listas/piezas.js.map +1 -1
  48. package/lib/module/pantallas/PantallaDeAcceso.js +6 -4
  49. package/lib/module/pantallas/PantallaDeAcceso.js.map +1 -1
  50. package/lib/module/pantallas/PantallaDeEdicion.js +9 -6
  51. package/lib/module/pantallas/PantallaDeEdicion.js.map +1 -1
  52. package/lib/module/pantallas/PantallaDeFicha.js +7 -5
  53. package/lib/module/pantallas/PantallaDeFicha.js.map +1 -1
  54. package/lib/module/pantallas/PantallaDeHistorial.js +18 -14
  55. package/lib/module/pantallas/PantallaDeHistorial.js.map +1 -1
  56. package/lib/module/pantallas/PantallaDePerfil.js +12 -10
  57. package/lib/module/pantallas/PantallaDePerfil.js.map +1 -1
  58. package/lib/typescript/src/camara/CampoDeFotos.d.ts.map +1 -1
  59. package/lib/typescript/src/camara/elegir.d.ts.map +1 -1
  60. package/lib/typescript/src/componentes/AccionesDelEncabezado.d.ts.map +1 -1
  61. package/lib/typescript/src/componentes/BotonDeAvatar.d.ts.map +1 -1
  62. package/lib/typescript/src/componentes/CabeceraEmpujada.d.ts.map +1 -1
  63. package/lib/typescript/src/componentes/PantallaDeError.d.ts.map +1 -1
  64. package/lib/typescript/src/componentes/TiraDeFotos.d.ts.map +1 -1
  65. package/lib/typescript/src/componentes/VisorDeFoto.d.ts.map +1 -1
  66. package/lib/typescript/src/dialogos/HostDeDialogos.d.ts.map +1 -1
  67. package/lib/typescript/src/dialogos/dialogos.d.ts.map +1 -1
  68. package/lib/typescript/src/formularios/SelectorDeOpcion.d.ts.map +1 -1
  69. package/lib/typescript/src/formularios/campos.d.ts.map +1 -1
  70. package/lib/typescript/src/formularios/guardado.d.ts.map +1 -1
  71. package/lib/typescript/src/fotos/elegir.d.ts.map +1 -1
  72. package/lib/typescript/src/hoja/HojaDeLista.d.ts.map +1 -1
  73. package/lib/typescript/src/hoja/useMasDeLaFicha.d.ts.map +1 -1
  74. package/lib/typescript/src/idioma/ProveedorDeIdioma.d.ts +16 -0
  75. package/lib/typescript/src/idioma/ProveedorDeIdioma.d.ts.map +1 -0
  76. package/lib/typescript/src/idioma/index.d.ts +3 -0
  77. package/lib/typescript/src/idioma/index.d.ts.map +1 -0
  78. package/lib/typescript/src/idioma/textos.d.ts +124 -0
  79. package/lib/typescript/src/idioma/textos.d.ts.map +1 -0
  80. package/lib/typescript/src/index.d.ts +1 -0
  81. package/lib/typescript/src/index.d.ts.map +1 -1
  82. package/lib/typescript/src/listas/HojaDeFiltros.d.ts.map +1 -1
  83. package/lib/typescript/src/listas/ListaPaginada.d.ts.map +1 -1
  84. package/lib/typescript/src/listas/piezas.d.ts.map +1 -1
  85. package/lib/typescript/src/pantallas/PantallaDeAcceso.d.ts.map +1 -1
  86. package/lib/typescript/src/pantallas/PantallaDeEdicion.d.ts.map +1 -1
  87. package/lib/typescript/src/pantallas/PantallaDeFicha.d.ts.map +1 -1
  88. package/lib/typescript/src/pantallas/PantallaDeHistorial.d.ts.map +1 -1
  89. package/lib/typescript/src/pantallas/PantallaDePerfil.d.ts.map +1 -1
  90. package/package.json +1 -1
  91. package/src/camara/CampoDeFotos.tsx +4 -2
  92. package/src/camara/elegir.ts +4 -3
  93. package/src/componentes/AccionesDelEncabezado.tsx +3 -1
  94. package/src/componentes/BotonDeAvatar.tsx +22 -18
  95. package/src/componentes/CabeceraEmpujada.tsx +3 -1
  96. package/src/componentes/PantallaDeError.tsx +6 -4
  97. package/src/componentes/TiraDeFotos.tsx +4 -2
  98. package/src/componentes/VisorDeFoto.tsx +7 -7
  99. package/src/dialogos/HostDeDialogos.tsx +3 -1
  100. package/src/dialogos/dialogos.ts +15 -4
  101. package/src/formularios/SelectorDeOpcion.tsx +22 -8
  102. package/src/formularios/campos.tsx +9 -4
  103. package/src/formularios/guardado.ts +4 -2
  104. package/src/fotos/elegir.ts +14 -10
  105. package/src/hoja/HojaDeLista.tsx +5 -5
  106. package/src/hoja/useMasDeLaFicha.tsx +3 -1
  107. package/src/idioma/ProveedorDeIdioma.tsx +51 -0
  108. package/src/idioma/index.ts +7 -0
  109. package/src/idioma/textos.ts +246 -0
  110. package/src/index.ts +11 -0
  111. package/src/listas/HojaDeFiltros.tsx +10 -9
  112. package/src/listas/ListaPaginada.tsx +6 -6
  113. package/src/listas/piezas.tsx +17 -10
  114. package/src/pantallas/PantallaDeAcceso.tsx +6 -4
  115. package/src/pantallas/PantallaDeEdicion.tsx +13 -6
  116. package/src/pantallas/PantallaDeFicha.tsx +7 -5
  117. package/src/pantallas/PantallaDeHistorial.tsx +22 -16
  118. package/src/pantallas/PantallaDePerfil.tsx +12 -10
@@ -8,6 +8,7 @@ import EstadoVacio from "../componentes/EstadoVacio";
8
8
  import Nota from "../componentes/Nota";
9
9
  import { mensajeDeError } from "../formularios/errores";
10
10
  import { crearEstilos, usePaleta } from "../tema";
11
+ import { useTextos } from "../idioma";
11
12
 
12
13
  /**
13
14
  * El armazón de una pantalla que edita algo (un viaje, un tracto, una caja, un operador). Dos
@@ -43,19 +44,24 @@ export function EsperaDeEdicion({
43
44
  }) {
44
45
  const c = usePaleta();
45
46
  const styles = useStyles();
47
+ const t = useTextos();
46
48
  return (
47
49
  <View style={styles.root}>
48
50
  <CabeceraEmpujada eyebrow={eyebrow} titulo="…" />
49
51
  {!puede ? (
50
- <EstadoVacio icono="lock-outline" titulo="No tienes permiso" texto={sinPermiso} />
52
+ <EstadoVacio
53
+ icono="lock-outline"
54
+ titulo={t.edicion.sinPermiso}
55
+ texto={sinPermiso}
56
+ />
51
57
  ) : consulta.isError ? (
52
58
  <EstadoVacio
53
59
  icono="cloud-alert"
54
- titulo={`No se pudo cargar ${queEs}`}
55
- texto={mensajeDeError(consulta.error, "Revisa la señal e intenta de nuevo.")}
60
+ titulo={t.edicion.noSePudoCargar(queEs)}
61
+ texto={mensajeDeError(consulta.error, t.comun.revisaLaSenal)}
56
62
  >
57
63
  <BotonGrande icono="refresh" modo="contorno" onPress={consulta.refetch}>
58
- Reintentar
64
+ {t.comun.reintentar}
59
65
  </BotonGrande>
60
66
  </EstadoVacio>
61
67
  ) : (
@@ -71,7 +77,7 @@ export function FormularioDeEdicion({
71
77
  error,
72
78
  guardando,
73
79
  onGuardar,
74
- textoDeGuardar = "Guardar",
80
+ textoDeGuardar,
75
81
  children,
76
82
  }: {
77
83
  eyebrow: string;
@@ -86,6 +92,7 @@ export function FormularioDeEdicion({
86
92
  }) {
87
93
  const styles = useStyles();
88
94
  const insets = useSafeAreaInsets();
95
+ const t = useTextos();
89
96
  return (
90
97
  <View style={styles.root}>
91
98
  <CabeceraEmpujada eyebrow={eyebrow} titulo={titulo} />
@@ -99,7 +106,7 @@ export function FormularioDeEdicion({
99
106
  </ScrollView>
100
107
  <View style={[styles.pie, { paddingBottom: insets.bottom + 16 }]}>
101
108
  <BotonGrande icono="check" onPress={onGuardar} cargando={guardando}>
102
- {guardando ? "Guardando…" : textoDeGuardar}
109
+ {guardando ? t.edicion.guardando : (textoDeGuardar ?? t.edicion.guardar)}
103
110
  </BotonGrande>
104
111
  </View>
105
112
  </KeyboardAvoidingView>
@@ -6,6 +6,7 @@ import BotonGrande from "../componentes/BotonGrande";
6
6
  import CabeceraEmpujada from "../componentes/CabeceraEmpujada";
7
7
  import EstadoVacio from "../componentes/EstadoVacio";
8
8
  import { crearEstilos, usePaleta } from "../tema";
9
+ import { useTextos } from "../idioma";
9
10
 
10
11
  /** Lo que la ficha lee de un `use…Query` de RTK Query. */
11
12
  interface ConsultaDeFicha {
@@ -54,6 +55,7 @@ export default function PantallaDeFicha({
54
55
  const c = usePaleta();
55
56
  const styles = useStyles();
56
57
  const insets = useSafeAreaInsets();
58
+ const t = useTextos();
57
59
 
58
60
  let cuerpo: React.ReactNode;
59
61
  if (consulta.isLoading) {
@@ -62,17 +64,17 @@ export default function PantallaDeFicha({
62
64
  cuerpo = esNoEncontrado(consulta.error) ? (
63
65
  <EstadoVacio
64
66
  icono="file-hidden"
65
- titulo="No existe"
66
- texto="Puede que lo hayan borrado, o que no tengas permiso de verlo."
67
+ titulo={t.ficha.noExiste}
68
+ texto={t.ficha.noExisteTexto}
67
69
  />
68
70
  ) : (
69
71
  <EstadoVacio
70
72
  icono="cloud-off-outline"
71
- titulo="No se pudo cargar"
72
- texto="Revisa tu señal e intenta de nuevo."
73
+ titulo={t.comun.noSePudoCargar}
74
+ texto={t.comun.revisaLaSenal}
73
75
  >
74
76
  <BotonGrande icono="refresh" onPress={() => consulta.refetch()}>
75
- Reintentar
77
+ {t.comun.reintentar}
76
78
  </BotonGrande>
77
79
  </EstadoVacio>
78
80
  );
@@ -8,6 +8,7 @@ import EstadoVacio from "../componentes/EstadoVacio";
8
8
  import Tarjeta from "../componentes/Tarjeta";
9
9
  import { crearEstilos, renglon, tipografia, usePaleta, type Paleta } from "../tema";
10
10
  import { Text } from "../texto";
11
+ import { type Idioma, type Textos, useIdiomaDeLaLibreria, useTextos } from "../idioma";
11
12
 
12
13
  /**
13
14
  * Un movimiento de la bitácora de un registro, como lo responde cualquier endpoint `historial/`
@@ -64,20 +65,20 @@ const partirTipo = (tipo: string) => {
64
65
  };
65
66
 
66
67
  /** El valor de un campo tal como viene de la bitácora, listo para pintarse. */
67
- const formatear = (valor: unknown): string => {
68
+ const formatear = (valor: unknown, t: Textos): string => {
68
69
  if (valor === null || valor === undefined || valor === "") return "—";
69
- if (typeof valor === "boolean") return valor ? "Sí" : "No";
70
+ if (typeof valor === "boolean") return valor ? t.comun.si : t.comun.no;
70
71
  if (Array.isArray(valor)) return valor.length ? valor.join(", ") : "—";
71
72
  if (typeof valor === "object") return JSON.stringify(valor);
72
73
  return String(valor);
73
74
  };
74
75
 
75
76
  /** La fecha y hora del movimiento, en la hora del teléfono. */
76
- const fechaHora = (iso: string) => {
77
+ const fechaHora = (iso: string, idioma: Idioma) => {
77
78
  const fecha = new Date(iso);
78
79
  return Number.isNaN(fecha.getTime())
79
80
  ? "—"
80
- : fecha.toLocaleString("es-MX", {
81
+ : fecha.toLocaleString(idioma === "en" ? "en-US" : "es-MX", {
81
82
  day: "2-digit",
82
83
  month: "short",
83
84
  year: "numeric",
@@ -102,6 +103,8 @@ export function TarjetaDeEvento({
102
103
  }) {
103
104
  const c = usePaleta();
104
105
  const styles = useStyles();
106
+ const t = useTextos();
107
+ const idioma = useIdiomaDeLaLibreria();
105
108
  const [abierto, setAbierto] = React.useState(false);
106
109
 
107
110
  const { accion, modelo } = partirTipo(evento.history_type);
@@ -121,16 +124,18 @@ export function TarjetaDeEvento({
121
124
  <View style={styles.flex}>
122
125
  <Text style={styles.titulo}>{modelo}</Text>
123
126
  <Text style={styles.linea}>
124
- {[accion, evento.history_user || "Sistema"].filter(Boolean).join(" · ")}
127
+ {[accion, evento.history_user || t.historial.sistema]
128
+ .filter(Boolean)
129
+ .join(" · ")}
125
130
  </Text>
126
- <Text style={styles.linea}>{fechaHora(evento.history_date)}</Text>
131
+ <Text style={styles.linea}>{fechaHora(evento.history_date, idioma)}</Text>
127
132
  </View>
128
133
  </View>
129
134
 
130
135
  {/* Un arreglo vacío es «se guardó sin mover nada»; nulo es la creación, que no lista
131
136
  cambios. */}
132
137
  {!abierto && cambiados?.length === 0 ? (
133
- <Text style={styles.sinCambios}>Sin cambios en los campos.</Text>
138
+ <Text style={styles.sinCambios}>{t.historial.sinCambios}</Text>
134
139
  ) : null}
135
140
 
136
141
  {visibles.map((campo) => {
@@ -140,7 +145,7 @@ export function TarjetaDeEvento({
140
145
  <Text style={[styles.etiqueta, cambiado && styles.etiquetaCambiada]}>
141
146
  {labels[campo]}
142
147
  </Text>
143
- <Text style={styles.valor}>{formatear(evento[campo])}</Text>
148
+ <Text style={styles.valor}>{formatear(evento[campo], t)}</Text>
144
149
  </View>
145
150
  );
146
151
  })}
@@ -154,10 +159,10 @@ export function TarjetaDeEvento({
154
159
  >
155
160
  <Text style={styles.alternarTexto}>
156
161
  {abierto
157
- ? "Ocultar campos"
162
+ ? t.historial.ocultarCampos
158
163
  : cambiados?.length
159
- ? "Ver todos los campos"
160
- : "Ver los campos"}
164
+ ? t.historial.verTodos
165
+ : t.historial.verCampos}
161
166
  </Text>
162
167
  <MaterialCommunityIcons
163
168
  name={abierto ? "chevron-up" : "chevron-down"}
@@ -205,20 +210,21 @@ export default function PantallaDeHistorial({
205
210
  const insets = useSafeAreaInsets();
206
211
  const { data, isLoading, isFetching, isError, refetch } = consulta;
207
212
  const eventos = data?.history ?? [];
213
+ const t = useTextos();
208
214
 
209
215
  return (
210
216
  <View style={styles.root}>
211
- <CabeceraEmpujada eyebrow={eyebrow} titulo="Historial" />
217
+ <CabeceraEmpujada eyebrow={eyebrow} titulo={t.historial.titulo} />
212
218
  {/* El error sólo se queda con la pantalla cuando no hay nada que enseñar: un refresco
213
219
  que falla no debe borrar el historial que ya se estaba leyendo. */}
214
220
  {isError && !data ? (
215
221
  <EstadoVacio
216
222
  icono="cloud-off-outline"
217
- titulo="No se pudo cargar el historial"
218
- texto="Revisa tu señal e intenta de nuevo."
223
+ titulo={t.historial.noCargo}
224
+ texto={t.comun.revisaLaSenal}
219
225
  >
220
226
  <BotonGrande icono="refresh" modo="contorno" onPress={() => refetch()}>
221
- Reintentar
227
+ {t.comun.reintentar}
222
228
  </BotonGrande>
223
229
  </EstadoVacio>
224
230
  ) : isLoading ? (
@@ -240,7 +246,7 @@ export default function PantallaDeHistorial({
240
246
  }
241
247
  >
242
248
  {eventos.length === 0 ? (
243
- <EstadoVacio icono="history" titulo="Sin movimientos registrados" />
249
+ <EstadoVacio icono="history" titulo={t.historial.sinMovimientos} />
244
250
  ) : (
245
251
  eventos.map((evento, indice) => (
246
252
  // El backend no da una llave por evento (mezcla modelos con ids que se
@@ -13,16 +13,17 @@ import {
13
13
  type PreferenciaDeTema,
14
14
  } from "../tema";
15
15
  import { Text } from "../texto";
16
+ import { type Textos, useTextos } from "../idioma";
16
17
 
17
18
  /**
18
19
  * La apariencia: **igual que el teléfono** por omisión, o fija. Tres opciones y no un interruptor de
19
20
  * «modo oscuro», como el del portal: con un interruptor, quien lo toca una vez ya no vuelve a seguir
20
21
  * al teléfono.
21
22
  */
22
- const APARIENCIAS: Pestana<PreferenciaDeTema>[] = [
23
- { key: "sistema", label: "Teléfono", icono: "cellphone" },
24
- { key: "claro", label: "Claro", icono: "white-balance-sunny" },
25
- { key: "oscuro", label: "Oscuro", icono: "weather-night" },
23
+ const aparienciasDe = (t: Textos): Pestana<PreferenciaDeTema>[] => [
24
+ { key: "sistema", label: t.perfil.telefono, icono: "cellphone" },
25
+ { key: "claro", label: t.perfil.claro, icono: "white-balance-sunny" },
26
+ { key: "oscuro", label: t.perfil.oscuro, icono: "weather-night" },
26
27
  ];
27
28
 
28
29
  /**
@@ -52,10 +53,11 @@ export default function PantallaDePerfil({
52
53
  const styles = useStyles();
53
54
  const [tema, setTema] = usePreferenciaDeTema();
54
55
  const insets = useSafeAreaInsets();
56
+ const t = useTextos();
55
57
 
56
58
  return (
57
59
  <View style={styles.root}>
58
- <CabeceraEmpujada eyebrow={rotulo} titulo="Perfil" />
60
+ <CabeceraEmpujada eyebrow={rotulo} titulo={t.perfil.titulo} />
59
61
 
60
62
  <ContenidoDePantalla paddingBottom={insets.bottom + 20}>
61
63
  <ScrollView
@@ -66,13 +68,13 @@ export default function PantallaDePerfil({
66
68
  {/* Paper recorta título y subtítulo a un renglón por omisión: un nombre
67
69
  largo con la letra al 180% se perdía. */}
68
70
  <Card.Title
69
- title={nombre || "N/A"}
71
+ title={nombre || t.comun.noDisponible}
70
72
  titleVariant={"titleLarge"}
71
73
  titleStyle={{ fontWeight: "bold" }}
72
74
  titleNumberOfLines={0}
73
75
  subtitleNumberOfLines={0}
74
76
  subtitleStyle={renglon(tipografia.secundario)}
75
- subtitle={subtitulo || "N/A"}
77
+ subtitle={subtitulo || t.comun.noDisponible}
76
78
  subtitleVariant={"bodySmall"}
77
79
  left={(props) => (
78
80
  <Avatar.Text
@@ -85,8 +87,8 @@ export default function PantallaDePerfil({
85
87
  </Card>
86
88
 
87
89
  <View style={styles.apariencia}>
88
- <Text style={styles.rotulo}>Apariencia</Text>
89
- <Pestanas pestanas={APARIENCIAS} activa={tema} onSelect={setTema} />
90
+ <Text style={styles.rotulo}>{t.perfil.apariencia}</Text>
91
+ <Pestanas pestanas={aparienciasDe(t)} activa={tema} onSelect={setTema} />
90
92
  </View>
91
93
 
92
94
  {/* El tope de ancho vive en este View y no en el Button: el Surface de
@@ -100,7 +102,7 @@ export default function PantallaDePerfil({
100
102
  loading={saliendo}
101
103
  disabled={saliendo}
102
104
  >
103
- Cerrar sesión
105
+ {t.perfil.cerrarSesion}
104
106
  </Button>
105
107
  </View>
106
108
  {children}