135 lines
4.2 KiB
TypeScript
135 lines
4.2 KiB
TypeScript
import * as SQLite from 'expo-sqlite';
|
|
import { Contact } from '@/store/useContactStore';
|
|
import { dbToContact } from '@/lib/contactHelpers';
|
|
|
|
let db: SQLite.SQLiteDatabase | null = null;
|
|
|
|
export async function getDatabase(): Promise<SQLite.SQLiteDatabase> {
|
|
if (!db) {
|
|
db = await SQLite.openDatabaseAsync('territorylog.db');
|
|
await initSchema(db);
|
|
}
|
|
return db;
|
|
}
|
|
|
|
async function initSchema(database: SQLite.SQLiteDatabase): Promise<void> {
|
|
await database.execAsync(`
|
|
PRAGMA journal_mode = WAL;
|
|
PRAGMA foreign_keys = ON;
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id TEXT PRIMARY KEY,
|
|
display_name TEXT NOT NULL,
|
|
share_id TEXT UNIQUE NOT NULL,
|
|
is_self INTEGER DEFAULT 1,
|
|
created_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS territories (
|
|
id TEXT PRIMARY KEY,
|
|
territory_code TEXT UNIQUE NOT NULL,
|
|
municipality TEXT,
|
|
barangay TEXT,
|
|
area TEXT,
|
|
block TEXT,
|
|
assigned_to TEXT,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS contacts (
|
|
id TEXT PRIMARY KEY,
|
|
owner_id TEXT NOT NULL,
|
|
full_name TEXT NOT NULL,
|
|
address TEXT,
|
|
household_count INTEGER DEFAULT 1,
|
|
gender TEXT,
|
|
category TEXT NOT NULL,
|
|
status TEXT DEFAULT 'Active',
|
|
tags TEXT DEFAULT '[]',
|
|
notes TEXT,
|
|
territory_code TEXT REFERENCES territories(territory_code),
|
|
latitude REAL,
|
|
longitude REAL,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL,
|
|
deleted_at INTEGER
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS visits (
|
|
id TEXT PRIMARY KEY,
|
|
contact_id TEXT NOT NULL REFERENCES contacts(id),
|
|
visited_by_name TEXT NOT NULL,
|
|
visited_by_id TEXT NOT NULL,
|
|
visit_date INTEGER NOT NULL,
|
|
topic TEXT,
|
|
response TEXT,
|
|
remarks TEXT,
|
|
next_visit_date INTEGER,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS topics (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT UNIQUE NOT NULL,
|
|
is_default INTEGER DEFAULT 0,
|
|
created_at INTEGER NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS sync_log (
|
|
id TEXT PRIMARY KEY,
|
|
partner_id TEXT NOT NULL,
|
|
partner_name TEXT,
|
|
synced_at INTEGER NOT NULL,
|
|
sent_count INTEGER DEFAULT 0,
|
|
received_count INTEGER DEFAULT 0
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_contacts_name ON contacts(full_name);
|
|
CREATE INDEX IF NOT EXISTS idx_contacts_status ON contacts(status);
|
|
CREATE INDEX IF NOT EXISTS idx_contacts_territory ON contacts(territory_code);
|
|
CREATE INDEX IF NOT EXISTS idx_visits_contact ON visits(contact_id);
|
|
CREATE INDEX IF NOT EXISTS idx_visits_date ON visits(visit_date);
|
|
`);
|
|
|
|
// Seed default topics
|
|
const now = Math.floor(Date.now() / 1000);
|
|
const defaultTopics = [
|
|
{ id: 't1', name: 'The Kingdom of God' },
|
|
{ id: 't2', name: 'Paradise Earth' },
|
|
{ id: 't3', name: 'Life After Death' },
|
|
{ id: 't4', name: "The Bible's Reliability" },
|
|
{ id: 't5', name: "God's Name (Jehovah)" },
|
|
{ id: 't6', name: 'Why Bad Things Happen' },
|
|
{ id: 't7', name: 'Jesus Christ' },
|
|
{ id: 't8', name: 'The Resurrection' },
|
|
{ id: 't9', name: 'Family Happiness' },
|
|
];
|
|
|
|
for (const topic of defaultTopics) {
|
|
await database.runAsync(
|
|
'INSERT OR IGNORE INTO topics (id, name, is_default, created_at) VALUES (?, ?, 1, ?)',
|
|
[topic.id, topic.name, now]
|
|
);
|
|
}
|
|
}
|
|
|
|
// ── Map helpers ──────────────────────────────────────────────────────────────
|
|
|
|
export async function getContactsWithGPS(): Promise<Contact[]> {
|
|
const database = await getDatabase();
|
|
const result = await database.getAllAsync<any>(
|
|
`SELECT * FROM contacts WHERE latitude IS NOT NULL AND longitude IS NOT NULL AND deleted_at IS NULL ORDER BY full_name`
|
|
);
|
|
return result.map(dbToContact);
|
|
}
|
|
|
|
export async function getAllContactsForMap(): Promise<Contact[]> {
|
|
const database = await getDatabase();
|
|
const result = await database.getAllAsync<any>(
|
|
`SELECT * FROM contacts WHERE deleted_at IS NULL ORDER BY full_name`
|
|
);
|
|
return result.map(dbToContact);
|
|
}
|