diff --git a/src/services/tauri-db.ts b/src/services/tauri-db.ts new file mode 100644 index 0000000..9620692 --- /dev/null +++ b/src/services/tauri-db.ts @@ -0,0 +1,126 @@ +import { invoke } from '@tauri-apps/api/core' + +export interface AlphaUserRecord { + id: number + email: string + first_name: string + last_name: string + role: string | null + seniority: string | null + cell_id: number | null + is_active: boolean + created_at: string | null +} + +export interface CellRecord { + id: number + name: string + description: string | null + created_at: string | null +} + +export interface ProjectMemberRecord { + id: number + user_id: number + initiative_id: number + initiative_name: string | null + role: string | null + assigned_at: string | null +} + +export interface AbsenceRecord { + id: number + user_id: number + start_date: string + end_date: string + type: string + reason: string | null + created_at: string | null +} + +export interface DailyLogRecord { + id: number + user_id: number + initiative_id: number + date: string + work_item_id: number | null + what_worked_on: string | null + progress_pct: number | null + impediments: string | null + plan_for_tomorrow: string | null + hours_spent: number | null + created_at: string | null +} + +export interface PerformanceRecord { + id: number + user_id: number + initiative_id: number | null + period: string + planned_sp: number | null + completed_sp: number | null + planned_hours: number | null + actual_hours: number | null + velocity: number | null + spi: number | null + cpi: number | null + compliance_pct: number | null + impediment_count: number | null + calculated_at: string | null +} + +export const tauriDb = { + // Users + getUsers(): Promise { + return invoke('get_users') + }, + saveUser(user: AlphaUserRecord): Promise { + return invoke('save_user', { user }) + }, + updateUserFields(id: number, role: string | null, seniority: string | null, cell_id: number | null): Promise { + return invoke('update_user_fields', { id, role, seniority, cellId: cell_id }) + }, + + // Cells + getCells(): Promise { + return invoke('get_cells') + }, + saveCell(cell: CellRecord): Promise { + return invoke('save_cell', { cell }) + }, + + // Project Members + getProjectMembers(userId: number): Promise { + return invoke('get_project_members', { userId }) + }, + saveProjectMembers(userId: number, members: ProjectMemberRecord[]): Promise { + return invoke('save_project_members', { userId, members }) + }, + + // Absences + getAbsences(userId: number): Promise { + return invoke('get_absences', { userId }) + }, + saveAbsence(absence: AbsenceRecord): Promise { + return invoke('save_absence', { absence }) + }, + deleteAbsence(id: number): Promise { + return invoke('delete_absence', { id }) + }, + + // Daily Logs + getDailyLogs(userId: number, initiativeId?: number): Promise { + return invoke('get_daily_logs', { userId, initiativeId: initiativeId ?? null }) + }, + saveDailyLog(log: DailyLogRecord): Promise { + return invoke('save_daily_log', { log }) + }, + + // Performance + getPerformance(userId: number, initiativeId?: number): Promise { + return invoke('get_performance', { userId, initiativeId }) + }, + savePerformance(snap: PerformanceRecord): Promise { + return invoke('save_performance', { snap }) + }, +} diff --git a/src/stores/users.ts b/src/stores/users.ts index e10f4d8..c958c55 100644 --- a/src/stores/users.ts +++ b/src/stores/users.ts @@ -1,6 +1,7 @@ import { defineStore } from 'pinia' import { ref, computed } from 'vue' import { kappa } from '@/services/kappa-api' +import { tauriDb, type AlphaUserRecord, type CellRecord } from '@/services/tauri-db' import type { KappaEmployee } from '@/types/kappa' export interface AlphaUser { @@ -11,6 +12,7 @@ export interface AlphaUser { full_name: string is_active: boolean cell?: string + cell_id?: number role?: string seniority?: string projects: string[] @@ -21,6 +23,7 @@ export interface AlphaUser { export const useUsersStore = defineStore('users', () => { const users = ref([]) const employees = ref([]) + const cells = ref([]) const loading = ref(false) const error = ref(null) const totalPages = ref(1) @@ -42,12 +45,15 @@ export const useUsersStore = defineStore('users', () => { loading.value = true error.value = null try { - const [rawUsers, page1] = await Promise.all([ + const [rawUsers, page1, localUsers, localCells] = await Promise.all([ kappa.getUsers(), kappa.getEmployees(1), + tauriDb.getUsers().catch(() => [] as AlphaUserRecord[]), + tauriDb.getCells().catch(() => [] as CellRecord[]), ]) employees.value = page1.results + cells.value = localCells totalPages.value = Math.ceil(page1.count / 25) if (totalPages.value > 1) { @@ -61,7 +67,11 @@ export const useUsersStore = defineStore('users', () => { } } - users.value = buildUsers(rawUsers, employees.value) + const localMap = new Map(localUsers.map(u => [u.id, u])) + users.value = buildUsers(rawUsers, employees.value, localMap) + + // Sync KAPPA users into Turso + syncUsersToTurso(users.value) } catch (e: any) { error.value = e.message } finally { @@ -69,9 +79,13 @@ export const useUsersStore = defineStore('users', () => { } } - function buildUsers(raw: unknown[], emps: KappaEmployee[]): AlphaUser[] { + function buildUsers(raw: unknown[], emps: KappaEmployee[], localMap: Map): AlphaUser[] { + const cellMap = new Map(cells.value.map(c => [c.id, c.name])) + return raw.map((u: any) => { const userEmps = emps.filter(e => e.user === u.id) + const local = localMap.get(u.id) + const cellName = local?.cell_id ? cellMap.get(local.cell_id) : undefined return { id: u.id, @@ -80,6 +94,10 @@ export const useUsersStore = defineStore('users', () => { last_name: u.last_name || '', full_name: u.full_name || `${u.first_name || ''} ${u.last_name || ''}`.trim() || u.email, is_active: u.is_active !== undefined ? u.is_active : true, + cell: cellName, + cell_id: local?.cell_id ?? undefined, + role: local?.role ?? undefined, + seniority: local?.seniority ?? undefined, projects: userEmps .filter(e => e.initiative_name) .map(e => e.initiative_name!), @@ -89,6 +107,37 @@ export const useUsersStore = defineStore('users', () => { }) } + async function syncUsersToTurso(userList: AlphaUser[]) { + for (const u of userList) { + await tauriDb.saveUser({ + id: u.id, + email: u.email, + first_name: u.first_name, + last_name: u.last_name, + role: u.role ?? null, + seniority: u.seniority ?? null, + cell_id: u.cell_id ?? null, + is_active: u.is_active, + created_at: null, + }).catch(() => {}) + } + } + + async function updateUserFields(id: number, role: string | null, seniority: string | null, cellId: number | null) { + await tauriDb.updateUserFields(id, role, seniority, cellId) + const idx = users.value.findIndex(u => u.id === id) + if (idx !== -1) { + const cellName = cellId ? cells.value.find(c => c.id === cellId)?.name : undefined + users.value[idx] = { + ...users.value[idx], + role: role ?? undefined, + seniority: seniority ?? undefined, + cell: cellName, + cell_id: cellId ?? undefined, + } + } + } + function updateLocal(id: number, data: Partial) { const idx = users.value.findIndex(u => u.id === id) if (idx !== -1) { @@ -96,9 +145,23 @@ export const useUsersStore = defineStore('users', () => { } } + async function createCell(name: string, description?: string): Promise { + const cell: CellRecord = { + id: 0, + name, + description: description ?? null, + created_at: null, + } + const id = await tauriDb.saveCell(cell) + const created = { ...cell, id } + cells.value.push(created) + return created + } + return { users, employees, + cells, loading, error, totalPages, @@ -107,5 +170,7 @@ export const useUsersStore = defineStore('users', () => { devsByProject, fetchAll, updateLocal, + updateUserFields, + createCell, } })