Onboarding
This commit is contained in:
@@ -69,6 +69,9 @@ export const initDatabase = (): void => {
|
||||
experience_level TEXT,
|
||||
lexicon_explored INTEGER NOT NULL DEFAULT 0,
|
||||
customization_done INTEGER NOT NULL DEFAULT 0,
|
||||
scan_done INTEGER NOT NULL DEFAULT 0,
|
||||
reminder_done INTEGER NOT NULL DEFAULT 0,
|
||||
collection_done INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
@@ -116,6 +119,17 @@ export const initDatabase = (): void => {
|
||||
db.runSync("ALTER TABLE plants ADD COLUMN health_checks TEXT NOT NULL DEFAULT '[]'");
|
||||
} catch (_) { /* column already exists */ }
|
||||
|
||||
// Migration: add persistent onboarding checklist columns to existing databases
|
||||
try {
|
||||
db.runSync('ALTER TABLE user_onboarding_profile ADD COLUMN scan_done INTEGER NOT NULL DEFAULT 0');
|
||||
} catch (_) { /* column already exists */ }
|
||||
try {
|
||||
db.runSync('ALTER TABLE user_onboarding_profile ADD COLUMN reminder_done INTEGER NOT NULL DEFAULT 0');
|
||||
} catch (_) { /* column already exists */ }
|
||||
try {
|
||||
db.runSync('ALTER TABLE user_onboarding_profile ADD COLUMN collection_done INTEGER NOT NULL DEFAULT 0');
|
||||
} catch (_) { /* column already exists */ }
|
||||
|
||||
repairForeignKeyState(db);
|
||||
|
||||
_isDatabaseInitialized = true;
|
||||
@@ -252,6 +266,9 @@ export const OnboardingProfileDb = {
|
||||
experience_level: string | null;
|
||||
lexicon_explored: number;
|
||||
customization_done: number;
|
||||
scan_done: number;
|
||||
reminder_done: number;
|
||||
collection_done: number;
|
||||
}>('SELECT * FROM user_onboarding_profile WHERE user_id = ?', [userId])!;
|
||||
},
|
||||
|
||||
@@ -314,6 +331,42 @@ export const OnboardingProfileDb = {
|
||||
[userId, done ? 1 : 0],
|
||||
);
|
||||
},
|
||||
|
||||
setScanDone(userId: number, done: boolean) {
|
||||
const db = getDb();
|
||||
db.runSync(
|
||||
`INSERT INTO user_onboarding_profile (user_id, scan_done, updated_at)
|
||||
VALUES (?, ?, datetime('now'))
|
||||
ON CONFLICT(user_id) DO UPDATE SET
|
||||
scan_done = excluded.scan_done,
|
||||
updated_at = datetime('now')`,
|
||||
[userId, done ? 1 : 0],
|
||||
);
|
||||
},
|
||||
|
||||
setReminderDone(userId: number, done: boolean) {
|
||||
const db = getDb();
|
||||
db.runSync(
|
||||
`INSERT INTO user_onboarding_profile (user_id, reminder_done, updated_at)
|
||||
VALUES (?, ?, datetime('now'))
|
||||
ON CONFLICT(user_id) DO UPDATE SET
|
||||
reminder_done = excluded.reminder_done,
|
||||
updated_at = datetime('now')`,
|
||||
[userId, done ? 1 : 0],
|
||||
);
|
||||
},
|
||||
|
||||
setCollectionDone(userId: number, done: boolean) {
|
||||
const db = getDb();
|
||||
db.runSync(
|
||||
`INSERT INTO user_onboarding_profile (user_id, collection_done, updated_at)
|
||||
VALUES (?, ?, datetime('now'))
|
||||
ON CONFLICT(user_id) DO UPDATE SET
|
||||
collection_done = excluded.collection_done,
|
||||
updated_at = datetime('now')`,
|
||||
[userId, done ? 1 : 0],
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
const DEFAULT_CARE_INFO: CareInfo = {
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
import { OnboardingProfileDb } from './database';
|
||||
|
||||
export type PersistentOnboardingStep = 'lexicon' | 'customize';
|
||||
export type PersistentOnboardingStep = 'lexicon' | 'customize' | 'scan' | 'reminder' | 'collection';
|
||||
|
||||
const STEP_COLUMN: Record<PersistentOnboardingStep, 'lexicon_explored' | 'customization_done' | 'scan_done' | 'reminder_done' | 'collection_done'> = {
|
||||
lexicon: 'lexicon_explored',
|
||||
customize: 'customization_done',
|
||||
scan: 'scan_done',
|
||||
reminder: 'reminder_done',
|
||||
collection: 'collection_done',
|
||||
};
|
||||
|
||||
const STEP_SETTER: Record<PersistentOnboardingStep, (userId: number, done: boolean) => void> = {
|
||||
lexicon: OnboardingProfileDb.setLexiconExplored,
|
||||
customize: OnboardingProfileDb.setCustomizationDone,
|
||||
scan: OnboardingProfileDb.setScanDone,
|
||||
reminder: OnboardingProfileDb.setReminderDone,
|
||||
collection: OnboardingProfileDb.setCollectionDone,
|
||||
};
|
||||
|
||||
export const OnboardingProgressService = {
|
||||
isStepCompleted(userId: number, step: PersistentOnboardingStep): boolean {
|
||||
const profile = OnboardingProfileDb.get(userId);
|
||||
return step === 'lexicon'
|
||||
? profile.lexicon_explored === 1
|
||||
: profile.customization_done === 1;
|
||||
return profile[STEP_COLUMN[step]] === 1;
|
||||
},
|
||||
|
||||
completeStep(userId: number, step: PersistentOnboardingStep): void {
|
||||
if (step === 'lexicon') {
|
||||
OnboardingProfileDb.setLexiconExplored(userId, true);
|
||||
return;
|
||||
}
|
||||
OnboardingProfileDb.setCustomizationDone(userId, true);
|
||||
STEP_SETTER[step](userId, true);
|
||||
},
|
||||
|
||||
getSignals(userId: number) {
|
||||
@@ -23,6 +33,9 @@ export const OnboardingProgressService = {
|
||||
return {
|
||||
lexiconExplored: profile.lexicon_explored === 1,
|
||||
customizationDone: profile.customization_done === 1,
|
||||
scanDone: profile.scan_done === 1,
|
||||
reminderDone: profile.reminder_done === 1,
|
||||
collectionDone: profile.collection_done === 1,
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user