// services/onboardingService.ts // Manages user onboarding state for landlord and tenant roles import { kvStore } from "../modules/KvCacheStore.ts"; import type { User } from "../db/interfaces.ts"; import { getE2EUserById, isE2EEnabled, setE2EUser } from "./e2eFixtures.ts"; export type OnboardingRole = "landlord" | "tenant"; export interface OnboardingStatus { user_id: string; user_type: string | null; onboarding_step: number | null; onboarded_landlord: boolean | null; onboarded_tenant: boolean | null; email_verified: boolean | null; banking_setup_complete: boolean | null; } async function getUser(userId: string): Promise { if (isE2EEnabled()) { return getE2EUserById(userId); } return await kvStore.get(["users", userId]); } async function setUser(user: User): Promise { if (isE2EEnabled()) { setE2EUser(user); return; } await kvStore.set(["users", user.id], user); } export async function startGuestOnboarding( userId: string, role: OnboardingRole, ): Promise<{ nextUrl: string }> { const existing = await getUser(userId); const now = Date.now(); if (!existing) { throw new Error("User not found for onboarding"); } const onboardingStep = role === "landlord" ? (existing.onboarding_step && existing.onboarding_step > 0 ? existing.onboarding_step : 1) : (existing.onboarding_step ?? 0); const updated: User = { ...existing, user_type: role, onboarding_step: onboardingStep, onboarded_landlord: existing.onboarded_landlord ?? false, onboarded_tenant: existing.onboarded_tenant ?? false, email_verified: existing.email_verified ?? false, banking_setup_complete: existing.banking_setup_complete ?? false, updated_on: now, }; await setUser(updated); if (role === "landlord") { return { nextUrl: "/landlord/onboarding/profile" }; } // tenant return { nextUrl: "/tenant/dashboard" }; } export async function getOnboardingStatus( userId: string, ): Promise { const user = await getUser(userId); if (!user) return null; return { user_id: user.id, user_type: user.user_type || "", onboarding_step: user.onboarding_step || 0, onboarded_landlord: user.onboarded_landlord || false, onboarded_tenant: user.onboarded_tenant || false, email_verified: user.email_verified || false, banking_setup_complete: user.banking_setup_complete || false, }; } export async function markRoleOnboarded( userId: string, role: OnboardingRole, ): Promise { const user = await getUser(userId); if (!user) return; const updated: User = { ...user, onboarded_landlord: role === "landlord" ? true : (user.onboarded_landlord ?? false), onboarded_tenant: role === "tenant" ? true : (user.onboarded_tenant ?? false), onboarding_step: role === "landlord" ? 0 : (user.onboarding_step ?? 0), updated_on: Date.now(), }; await setUser(updated); } export async function setOnboardingStep( userId: string, step: number, ): Promise { const user = await getUser(userId); if (!user) return; const updated: User = { ...user, onboarding_step: step, updated_on: Date.now(), }; await setUser(updated); } export async function markEmailVerified(userId: string): Promise { const user = await getUser(userId); if (!user) return; const updated: User = { ...user, email_verified: true, updated_on: Date.now(), }; await setUser(updated); } export async function markBankingSetupComplete( userId: string, ): Promise { const user = await getUser(userId); if (!user) return; const updated: User = { ...user, banking_setup_complete: true, updated_on: Date.now(), }; await setUser(updated); }