feat: Sprint 0 — project scaffold, DB schema, Zustand stores, base UI components
This commit is contained in:
114
lib/database.ts
Normal file
114
lib/database.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import * as SQLite from 'expo-sqlite';
|
||||
|
||||
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]
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user