import { defineStore } from 'pinia' import { ref, computed } from 'vue' import { invoke } from '@tauri-apps/api/core' import { useSettingsStore } from './settings' export type ChecklistItemKey = | 'create_client' | 'create_project' | 'track_entry' | 'review_entries' | 'create_invoice' | 'explore_reports' export interface ChecklistItem { key: ChecklistItemKey label: string description: string route: string tourId: string completed: boolean } interface ChecklistState { dismissed: boolean items: Record } const DEFAULT_STATE: ChecklistState = { dismissed: false, items: { create_client: { completed: false }, create_project: { completed: false }, track_entry: { completed: false }, review_entries: { completed: false }, create_invoice: { completed: false }, explore_reports: { completed: false }, }, } const ITEM_DEFINITIONS: Omit[] = [ { key: 'create_client', label: 'Create your first client', description: 'Add a client to bill your work to', route: '/clients', tourId: 'clients' }, { key: 'create_project', label: 'Create a project', description: 'Organize your work under a project', route: '/projects', tourId: 'projects' }, { key: 'track_entry', label: 'Track your first time entry', description: 'Start the timer and log some work', route: '/timer', tourId: 'timer' }, { key: 'review_entries', label: 'Review your entries', description: 'See your tracked time in list or timeline view', route: '/entries', tourId: 'entries' }, { key: 'create_invoice', label: 'Create an invoice', description: 'Generate an invoice from tracked time', route: '/invoices', tourId: 'invoices' }, { key: 'explore_reports', label: 'Explore reports', description: 'View hours, profitability, and expense reports', route: '/reports', tourId: 'reports' }, ] export const useOnboardingStore = defineStore('onboarding', () => { const state = ref({ ...DEFAULT_STATE }) const loaded = ref(false) const items = computed(() => ITEM_DEFINITIONS.map(def => ({ ...def, completed: state.value.items[def.key]?.completed || false, })) ) const completedCount = computed(() => items.value.filter(i => i.completed).length) const totalCount = computed(() => items.value.length) const allComplete = computed(() => completedCount.value >= totalCount.value) const isDismissed = computed(() => state.value.dismissed) const isVisible = computed(() => loaded.value && !state.value.dismissed && !allComplete.value) async function load() { const settingsStore = useSettingsStore() const raw = settingsStore.settings.onboarding_checklist if (raw) { try { const parsed = JSON.parse(raw) as ChecklistState state.value = { ...DEFAULT_STATE, ...parsed, items: { ...DEFAULT_STATE.items, ...parsed.items } } } catch { state.value = { ...DEFAULT_STATE } } } // Auto-detect data-based completions await detectCompletions() loaded.value = true } async function detectCompletions() { try { const clients = await invoke('get_clients') if (clients.length > 0) markComplete('create_client') } catch { /* individual failure - continue */ } try { const projects = await invoke('get_projects') if (projects.length > 0) markComplete('create_project') } catch { /* individual failure - continue */ } try { const entries = await invoke('get_time_entries', { startDate: null, endDate: null }) if (entries.length > 0) markComplete('track_entry') } catch { /* individual failure - continue */ } try { const invoices = await invoke('get_invoices') if (invoices.length > 0) markComplete('create_invoice') } catch { /* individual failure - continue */ } } function markComplete(key: ChecklistItemKey) { if (!state.value.items[key].completed) { state.value.items[key].completed = true persist() } } function dismiss() { state.value.dismissed = true persist() } function restore() { state.value.dismissed = false persist() } function reset() { state.value = { dismissed: false, items: { create_client: { completed: false }, create_project: { completed: false }, track_entry: { completed: false }, review_entries: { completed: false }, create_invoice: { completed: false }, explore_reports: { completed: false }, }, } persist() } async function persist() { const settingsStore = useSettingsStore() await settingsStore.updateSetting('onboarding_checklist', JSON.stringify(state.value)) } // Called from router guard when user visits specific pages function onRouteVisit(path: string) { if (path === '/entries') markComplete('review_entries') if (path === '/reports') markComplete('explore_reports') } return { state, loaded, items, completedCount, totalCount, allComplete, isDismissed, isVisible, load, detectCompletions, markComplete, dismiss, restore, reset, onRouteVisit, } })