trips) adding transportation, checklist, and experience planning

This commit is contained in:
2026-02-20 19:47:51 -05:00
parent cf2fd658f1
commit a348fb034d
34 changed files with 6499 additions and 2040 deletions

View File

@@ -211,6 +211,100 @@ export function runMigrations(db: Database): void {
)
`);
// Private vehicle transportation details - links to a transport plan
db.run(`
CREATE TABLE IF NOT EXISTS private_vehicles (
id TEXT PRIMARY KEY,
plan_id TEXT NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
start_address TEXT NOT NULL,
end_address TEXT NOT NULL,
departure_date TEXT,
departure_time TEXT,
departure_timezone TEXT,
arrival_date TEXT,
arrival_time TEXT,
arrival_timezone TEXT,
start_plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
end_plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
for (const col of [
'departure_date TEXT',
'departure_time TEXT',
'departure_timezone TEXT',
'arrival_date TEXT',
'arrival_time TEXT',
'arrival_timezone TEXT'
]) {
try {
db.run(`ALTER TABLE private_vehicles ADD COLUMN ${col}`);
} catch {
/* already exists */
}
}
// Other transportation details - links to a transport plan
db.run(`
CREATE TABLE IF NOT EXISTS other_transports (
id TEXT PRIMARY KEY,
plan_id TEXT NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
start_date TEXT,
start_time TEXT,
start_timezone TEXT,
end_date TEXT,
end_time TEXT,
end_timezone TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
// Activity / restaurant details - links to a plan
db.run(`
CREATE TABLE IF NOT EXISTS experience_plans (
id TEXT PRIMARY KEY,
plan_id TEXT NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
booking_id TEXT,
total_cost REAL,
description TEXT,
website TEXT,
address TEXT,
contact_number TEXT,
start_date TEXT,
start_time TEXT,
start_timezone TEXT,
end_date TEXT,
end_time TEXT,
end_timezone TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
// Checklist master table (packing/todo details come from linked plan.type)
db.run(`
CREATE TABLE IF NOT EXISTS checklists (
id TEXT PRIMARY KEY,
plan_id TEXT NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
db.run(`
CREATE TABLE IF NOT EXISTS checklist_items (
id TEXT PRIMARY KEY,
checklist_id TEXT NOT NULL REFERENCES checklists(id) ON DELETE CASCADE,
content TEXT NOT NULL,
is_checked INTEGER NOT NULL DEFAULT 0,
position INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
// Lodgings table - links to a plan
db.run(`
CREATE TABLE IF NOT EXISTS lodgings (
@@ -330,12 +424,12 @@ export function runMigrations(db: Database): void {
)
`);
// Template plans (transport/lodging) attached to operator tour days
// Template plans attached to operator tour days
db.run(`
CREATE TABLE IF NOT EXISTS operator_tour_day_plans (
id INTEGER PRIMARY KEY AUTOINCREMENT,
operator_tour_day_id INTEGER NOT NULL REFERENCES operator_tour_days(id) ON DELETE CASCADE,
type TEXT NOT NULL CHECK (type IN ('transport', 'lodging')),
type TEXT NOT NULL CHECK (type IN ('transport', 'lodging', 'activity', 'restaurant', 'packing', 'todo')),
title TEXT NOT NULL,
notes TEXT,
position INTEGER NOT NULL DEFAULT 0,
@@ -344,6 +438,65 @@ export function runMigrations(db: Database): void {
)
`);
// Migration: expand operator_tour_day_plans `type` CHECK constraint if it still only supports transport/lodging.
try {
const schema = db.get<{ sql: string }>(
`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'operator_tour_day_plans'`
);
const sql = schema?.sql?.toLowerCase() ?? '';
if (sql && !sql.includes("'activity'")) {
db.run(`
CREATE TABLE operator_tour_day_plans__new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
operator_tour_day_id INTEGER NOT NULL REFERENCES operator_tour_days(id) ON DELETE CASCADE,
type TEXT NOT NULL CHECK (type IN ('transport', 'lodging', 'activity', 'restaurant', 'packing', 'todo')),
title TEXT NOT NULL,
notes TEXT,
position INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
chain TEXT,
address_line1 TEXT,
address_line2 TEXT,
city_name TEXT,
country TEXT,
country_code TEXT,
postal_code TEXT,
transport_kind TEXT,
start_date TEXT,
start_time TEXT,
start_timezone TEXT,
end_date TEXT,
end_time TEXT,
end_timezone TEXT,
booking_id TEXT,
total_cost REAL,
description TEXT,
website TEXT,
address TEXT,
contact_number TEXT,
items_json TEXT
)
`);
db.run(`
INSERT INTO operator_tour_day_plans__new (
id, operator_tour_day_id, type, title, notes, position, created_at, updated_at,
chain, address_line1, address_line2, city_name, country, country_code, postal_code,
transport_kind, start_date, start_time, start_timezone, end_date, end_time, end_timezone
)
SELECT
id, operator_tour_day_id, type, title, notes, position, created_at, updated_at,
chain, address_line1, address_line2, city_name, country, country_code, postal_code,
transport_kind, start_date, start_time, start_timezone, end_date, end_time, end_timezone
FROM operator_tour_day_plans
`);
db.run('DROP TABLE operator_tour_day_plans');
db.run('ALTER TABLE operator_tour_day_plans__new RENAME TO operator_tour_day_plans');
}
} catch {
/* best-effort migration */
}
// Lodging-specific fields for operator_tour_day_plans (type=lodging) — same shape as trip lodgings
for (const col of [
'chain TEXT',
@@ -352,7 +505,21 @@ export function runMigrations(db: Database): void {
'city_name TEXT',
'country TEXT',
'country_code TEXT',
'postal_code TEXT'
'postal_code TEXT',
'transport_kind TEXT',
'start_date TEXT',
'start_time TEXT',
'start_timezone TEXT',
'end_date TEXT',
'end_time TEXT',
'end_timezone TEXT',
'booking_id TEXT',
'total_cost REAL',
'description TEXT',
'website TEXT',
'address TEXT',
'contact_number TEXT',
'items_json TEXT'
]) {
try {
db.run(`ALTER TABLE operator_tour_day_plans ADD COLUMN ${col}`);
@@ -360,6 +527,15 @@ export function runMigrations(db: Database): void {
/* already exists */
}
}
try {
db.run(
`UPDATE operator_tour_day_plans
SET transport_kind = 'other'
WHERE type = 'transport' AND (transport_kind IS NULL OR TRIM(transport_kind) = '')`
);
} catch {
/* best-effort migration */
}
// Countries table — editable list for admin (used by country selector)
db.run(`