- Rename all DB tables: properties → projects, properties_addresses → projects_addresses, properties_models → projects_models, property_likes → projects_likes - Add projects_likes as proper Drizzle schema table (was SQL-only before) - Rename ID prefixes: property_xxx → project_xxx - Rename auth_sessions column: active_property_id → active_project_id - Simplify project creation: address is now optional (no longer required to get started) - Update all actions, stores, types, components, and routes - Rename route: /editor/[propertyId] → /editor/[projectId] - Add SQL migration for table/column/index/policy/function renames - Update RPC functions: increment_project_views, get_project_like_count - Update storage bucket reference: project-thumbnails - All types/exports follow existing Drizzle patterns (pgTable, relations, zod schemas)
90 lines
2.2 KiB
TypeScript
90 lines
2.2 KiB
TypeScript
/**
|
|
* Project store - Zustand store for project state management
|
|
*/
|
|
|
|
import { create } from 'zustand'
|
|
import type { Project } from './types'
|
|
import {
|
|
getActiveProject,
|
|
getUserProjects,
|
|
getProjectById,
|
|
} from './actions'
|
|
|
|
interface ProjectStore {
|
|
// State
|
|
activeProject: Project | null
|
|
projects: Project[]
|
|
isLoading: boolean
|
|
error: string | null
|
|
|
|
// Actions
|
|
fetchProjects: () => Promise<void>
|
|
fetchActiveProject: () => Promise<void>
|
|
setActiveProject: (projectId: string) => Promise<void>
|
|
initialize: () => Promise<void>
|
|
}
|
|
|
|
export const useProjectStore = create<ProjectStore>((set, get) => ({
|
|
// Initial state
|
|
activeProject: null,
|
|
projects: [],
|
|
isLoading: true,
|
|
error: null,
|
|
|
|
// Fetch all projects
|
|
fetchProjects: async () => {
|
|
const result = await getUserProjects()
|
|
|
|
if (result.success) {
|
|
set({ projects: result.data || [], error: null })
|
|
} else {
|
|
set({ error: result.error || 'Failed to fetch projects', projects: [] })
|
|
}
|
|
},
|
|
|
|
// Fetch the active project from database
|
|
fetchActiveProject: async () => {
|
|
set({ isLoading: true })
|
|
|
|
const result = await getActiveProject()
|
|
|
|
if (result.success) {
|
|
set({
|
|
activeProject: result.data || null,
|
|
isLoading: false,
|
|
error: null
|
|
})
|
|
// Note: Auto-select logic removed - now using URL-based routing
|
|
// The URL parameter determines which project to load
|
|
} else {
|
|
set({
|
|
error: result.error || 'Failed to fetch active project',
|
|
activeProject: null,
|
|
isLoading: false
|
|
})
|
|
}
|
|
},
|
|
|
|
// Set active project by fetching it directly by ID (URL-based, no session update)
|
|
setActiveProject: async (projectId: string) => {
|
|
set({ isLoading: true })
|
|
|
|
const result = await getProjectById(projectId)
|
|
|
|
if (result.success && result.data) {
|
|
set({ activeProject: result.data, isLoading: false, error: null })
|
|
} else {
|
|
set({ isLoading: false, error: result.error || 'Project not found' })
|
|
}
|
|
},
|
|
|
|
// Initialize - fetch both projects and active project
|
|
initialize: async () => {
|
|
set({ isLoading: true })
|
|
await Promise.all([
|
|
get().fetchProjects(),
|
|
get().fetchActiveProject(),
|
|
])
|
|
},
|
|
}))
|