Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7278c1363d | ||
|
|
3ed07cae3c |
+35
-1
@@ -390,6 +390,20 @@ export async function getTemplates(): Promise<Template[]> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persiste el catálogo global de plantillas (GET /templates) para tenerlas
|
||||||
|
* SIEMPRE en local y poder inspeccionar offline, aunque el proyecto concreto
|
||||||
|
* aún no se haya abierto. Upsert por id: no borra las que ya hubiera.
|
||||||
|
*/
|
||||||
|
export async function saveTemplates(templates: Template[]): Promise<void> {
|
||||||
|
const db = await getDb();
|
||||||
|
await db.withTransactionAsync(async () => {
|
||||||
|
for (const t of templates) {
|
||||||
|
await upsertById(db, 'templates', pickTemplate(t));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function getFeatureTypes(): Promise<FeatureType[]> {
|
export async function getFeatureTypes(): Promise<FeatureType[]> {
|
||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
return db.getAllAsync<FeatureType>('SELECT * FROM feature_types ORDER BY name');
|
return db.getAllAsync<FeatureType>('SELECT * FROM feature_types ORDER BY name');
|
||||||
@@ -409,6 +423,22 @@ export async function getMediaFor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proyecta el valor crudo del servidor (un `Model::toArray()`) a SOLO las
|
||||||
|
* columnas que existen en la tabla local, reutilizando los mismos `pick*` del
|
||||||
|
* PULL. Imprescindible: el `toArray()` trae columnas inexistentes en local
|
||||||
|
* (uuid, created_at, deleted_at, client_updated_at, properties…) y, en features,
|
||||||
|
* `geometry` como array —que SQLite no puede bindear—. Sin esto, un conflicto
|
||||||
|
* lanzaría "no such column"/error de bind y abortaría el ciclo de sync entero.
|
||||||
|
*/
|
||||||
|
const CONFLICT_PROJECTOR: Record<string, (v: never) => Record<string, unknown>> = {
|
||||||
|
features: (v) => pickFeature(v as Feature),
|
||||||
|
issues: (v) => pickIssue(v as Issue),
|
||||||
|
issue_tasks: (v) => pickIssueTask(v as IssueTask),
|
||||||
|
inspections: (v) => pickInspection(v as Inspection),
|
||||||
|
issue_comments: (v) => pickIssueComment(v as IssueComment),
|
||||||
|
};
|
||||||
|
|
||||||
/** Aplica el valor del servidor (recibido en un conflicto) a la fila local. */
|
/** Aplica el valor del servidor (recibido en un conflicto) a la fila local. */
|
||||||
export async function applyServerValue(
|
export async function applyServerValue(
|
||||||
table: string,
|
table: string,
|
||||||
@@ -416,7 +446,11 @@ export async function applyServerValue(
|
|||||||
serverValue: Record<string, unknown>,
|
serverValue: Record<string, unknown>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
await upsertById(db, table, { id, ...serverValue });
|
const project = CONFLICT_PROJECTOR[table];
|
||||||
|
// Si no hay proyector conocido, cae a un id-only (no-op seguro) en vez de
|
||||||
|
// volcar columnas crudas que podrían no existir en la tabla local.
|
||||||
|
const row = project ? project(serverValue as never) : { id };
|
||||||
|
await upsertById(db, table, { ...row, id });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- creaciones offline (optimista + reconciliación) ----------
|
// ---------- creaciones offline (optimista + reconciliación) ----------
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
import * as api from '../api/endpoints';
|
import * as api from '../api/endpoints';
|
||||||
import { Project } from '../api/types';
|
import { Project } from '../api/types';
|
||||||
import { useSession } from '../auth/session';
|
import { useSession } from '../auth/session';
|
||||||
import { getProjects, saveProjectList, setActiveProjectId } from '../db/repositories';
|
import { getProjects, saveProjectList, saveTemplates, setActiveProjectId } from '../db/repositories';
|
||||||
import { isOnline } from '../net/connectivity';
|
import { isOnline } from '../net/connectivity';
|
||||||
import { runSync } from '../sync/engine';
|
import { runSync } from '../sync/engine';
|
||||||
import { RootStackParamList } from '../navigation/types';
|
import { RootStackParamList } from '../navigation/types';
|
||||||
@@ -38,6 +38,15 @@ export function ProjectsScreen({ navigation }: Props) {
|
|||||||
if (await isOnline()) {
|
if (await isOnline()) {
|
||||||
const list = normalize(await api.listProjects());
|
const list = normalize(await api.listProjects());
|
||||||
await saveProjectList(list);
|
await saveProjectList(list);
|
||||||
|
// Prefetch del catálogo global de plantillas: así quedan SIEMPRE en
|
||||||
|
// local y se puede inspeccionar offline aunque el proyecto no se haya
|
||||||
|
// abierto todavía. No bloquea la lista si /templates falla.
|
||||||
|
try {
|
||||||
|
const { templates } = await api.getTemplates();
|
||||||
|
await saveTemplates(templates);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('No se pudieron prefetchar las plantillas:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setProjects(await getProjects());
|
setProjects(await getProjects());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user