feat(frontend): API layer + stores Pinia
Ajoute le client Axios, les modules API (gardens, varieties, plantings, tasks) et les stores Pinia correspondants. Corrige tsconfig.json pour inclure vite/client et DOM.Iterable. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
5
frontend/src/api/client.ts
Normal file
5
frontend/src/api/client.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import axios from 'axios'
|
||||
|
||||
export default axios.create({
|
||||
baseURL: import.meta.env.VITE_API_URL ?? '',
|
||||
})
|
||||
49
frontend/src/api/gardens.ts
Normal file
49
frontend/src/api/gardens.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import client from './client'
|
||||
|
||||
export interface Garden {
|
||||
id?: number
|
||||
nom: string
|
||||
description?: string
|
||||
type: string
|
||||
latitude?: number
|
||||
longitude?: number
|
||||
adresse?: string
|
||||
exposition?: string
|
||||
ombre?: string
|
||||
sol_type?: string
|
||||
grille_largeur: number
|
||||
grille_hauteur: number
|
||||
}
|
||||
|
||||
export interface GardenCell {
|
||||
id?: number
|
||||
garden_id?: number
|
||||
col: number
|
||||
row: number
|
||||
libelle?: string
|
||||
etat: string
|
||||
notes?: string
|
||||
}
|
||||
|
||||
export interface Measurement {
|
||||
id?: number
|
||||
garden_id?: number
|
||||
temp_air?: number
|
||||
temp_sol?: number
|
||||
humidite_air?: number
|
||||
humidite_sol?: number
|
||||
source?: string
|
||||
ts?: string
|
||||
}
|
||||
|
||||
export const gardensApi = {
|
||||
list: () => client.get<Garden[]>('/api/gardens').then(r => r.data),
|
||||
get: (id: number) => client.get<Garden>(`/api/gardens/${id}`).then(r => r.data),
|
||||
create: (g: Partial<Garden>) => client.post<Garden>('/api/gardens', g).then(r => r.data),
|
||||
update: (id: number, g: Partial<Garden>) => client.put<Garden>(`/api/gardens/${id}`, g).then(r => r.data),
|
||||
delete: (id: number) => client.delete(`/api/gardens/${id}`),
|
||||
cells: (id: number) => client.get<GardenCell[]>(`/api/gardens/${id}/cells`).then(r => r.data),
|
||||
measurements: (id: number) => client.get<Measurement[]>(`/api/gardens/${id}/measurements`).then(r => r.data),
|
||||
addMeasurement: (id: number, m: Partial<Measurement>) =>
|
||||
client.post<Measurement>(`/api/gardens/${id}/measurements`, m).then(r => r.data),
|
||||
}
|
||||
31
frontend/src/api/plantings.ts
Normal file
31
frontend/src/api/plantings.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import client from './client'
|
||||
|
||||
export interface Planting {
|
||||
id?: number
|
||||
garden_id: number
|
||||
variety_id: number
|
||||
cell_id?: number
|
||||
date_plantation?: string
|
||||
quantite: number
|
||||
statut: string
|
||||
notes?: string
|
||||
}
|
||||
|
||||
export interface PlantingEvent {
|
||||
id?: number
|
||||
planting_id?: number
|
||||
type: string
|
||||
note?: string
|
||||
ts?: string
|
||||
}
|
||||
|
||||
export const plantingsApi = {
|
||||
list: () => client.get<Planting[]>('/api/plantings').then(r => r.data),
|
||||
get: (id: number) => client.get<Planting>(`/api/plantings/${id}`).then(r => r.data),
|
||||
create: (p: Partial<Planting>) => client.post<Planting>('/api/plantings', p).then(r => r.data),
|
||||
update: (id: number, p: Partial<Planting>) => client.put<Planting>(`/api/plantings/${id}`, p).then(r => r.data),
|
||||
delete: (id: number) => client.delete(`/api/plantings/${id}`),
|
||||
events: (id: number) => client.get<PlantingEvent[]>(`/api/plantings/${id}/events`).then(r => r.data),
|
||||
addEvent: (id: number, e: Partial<PlantingEvent>) =>
|
||||
client.post<PlantingEvent>(`/api/plantings/${id}/events`, e).then(r => r.data),
|
||||
}
|
||||
20
frontend/src/api/tasks.ts
Normal file
20
frontend/src/api/tasks.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import client from './client'
|
||||
|
||||
export interface Task {
|
||||
id?: number
|
||||
titre: string
|
||||
description?: string
|
||||
garden_id?: number
|
||||
priorite: string
|
||||
echeance?: string
|
||||
statut: string
|
||||
}
|
||||
|
||||
export const tasksApi = {
|
||||
list: (params?: { statut?: string; garden_id?: number }) =>
|
||||
client.get<Task[]>('/api/tasks', { params }).then(r => r.data),
|
||||
get: (id: number) => client.get<Task>(`/api/tasks/${id}`).then(r => r.data),
|
||||
create: (t: Partial<Task>) => client.post<Task>('/api/tasks', t).then(r => r.data),
|
||||
update: (id: number, t: Partial<Task>) => client.put<Task>(`/api/tasks/${id}`, t).then(r => r.data),
|
||||
delete: (id: number) => client.delete(`/api/tasks/${id}`),
|
||||
}
|
||||
23
frontend/src/api/varieties.ts
Normal file
23
frontend/src/api/varieties.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import client from './client'
|
||||
|
||||
export interface PlantVariety {
|
||||
id?: number
|
||||
nom_commun: string
|
||||
nom_botanique?: string
|
||||
variete?: string
|
||||
famille?: string
|
||||
type_plante?: string
|
||||
besoin_eau?: string
|
||||
espacement_cm?: number
|
||||
plantation_mois?: string
|
||||
recolte_mois?: string
|
||||
notes?: string
|
||||
}
|
||||
|
||||
export const varietiesApi = {
|
||||
list: () => client.get<PlantVariety[]>('/api/varieties').then(r => r.data),
|
||||
get: (id: number) => client.get<PlantVariety>(`/api/varieties/${id}`).then(r => r.data),
|
||||
create: (v: Partial<PlantVariety>) => client.post<PlantVariety>('/api/varieties', v).then(r => r.data),
|
||||
update: (id: number, v: Partial<PlantVariety>) => client.put<PlantVariety>(`/api/varieties/${id}`, v).then(r => r.data),
|
||||
delete: (id: number) => client.delete(`/api/varieties/${id}`),
|
||||
}
|
||||
27
frontend/src/stores/gardens.ts
Normal file
27
frontend/src/stores/gardens.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { gardensApi, type Garden } from '@/api/gardens'
|
||||
|
||||
export const useGardensStore = defineStore('gardens', () => {
|
||||
const gardens = ref<Garden[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
async function fetchAll() {
|
||||
loading.value = true
|
||||
gardens.value = await gardensApi.list()
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
async function create(g: Partial<Garden>) {
|
||||
const created = await gardensApi.create(g)
|
||||
gardens.value.push(created)
|
||||
return created
|
||||
}
|
||||
|
||||
async function remove(id: number) {
|
||||
await gardensApi.delete(id)
|
||||
gardens.value = gardens.value.filter(g => g.id !== id)
|
||||
}
|
||||
|
||||
return { gardens, loading, fetchAll, create, remove }
|
||||
})
|
||||
27
frontend/src/stores/plantings.ts
Normal file
27
frontend/src/stores/plantings.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { plantingsApi, type Planting } from '@/api/plantings'
|
||||
|
||||
export const usePlantingsStore = defineStore('plantings', () => {
|
||||
const plantings = ref<Planting[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
async function fetchAll() {
|
||||
loading.value = true
|
||||
plantings.value = await plantingsApi.list()
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
async function create(p: Partial<Planting>) {
|
||||
const created = await plantingsApi.create(p)
|
||||
plantings.value.push(created)
|
||||
return created
|
||||
}
|
||||
|
||||
async function remove(id: number) {
|
||||
await plantingsApi.delete(id)
|
||||
plantings.value = plantings.value.filter(p => p.id !== id)
|
||||
}
|
||||
|
||||
return { plantings, loading, fetchAll, create, remove }
|
||||
})
|
||||
34
frontend/src/stores/tasks.ts
Normal file
34
frontend/src/stores/tasks.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { tasksApi, type Task } from '@/api/tasks'
|
||||
|
||||
export const useTasksStore = defineStore('tasks', () => {
|
||||
const tasks = ref<Task[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
async function fetchAll(params?: { statut?: string; garden_id?: number }) {
|
||||
loading.value = true
|
||||
tasks.value = await tasksApi.list(params)
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
async function create(t: Partial<Task>) {
|
||||
const created = await tasksApi.create(t)
|
||||
tasks.value.push(created)
|
||||
return created
|
||||
}
|
||||
|
||||
async function updateStatut(id: number, statut: string) {
|
||||
const t = tasks.value.find(t => t.id === id)
|
||||
if (!t) return
|
||||
const updated = await tasksApi.update(id, { ...t, statut })
|
||||
Object.assign(t, updated)
|
||||
}
|
||||
|
||||
async function remove(id: number) {
|
||||
await tasksApi.delete(id)
|
||||
tasks.value = tasks.value.filter(t => t.id !== id)
|
||||
}
|
||||
|
||||
return { tasks, loading, fetchAll, create, updateStatut, remove }
|
||||
})
|
||||
27
frontend/src/stores/varieties.ts
Normal file
27
frontend/src/stores/varieties.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { varietiesApi, type PlantVariety } from '@/api/varieties'
|
||||
|
||||
export const useVarietiesStore = defineStore('varieties', () => {
|
||||
const varieties = ref<PlantVariety[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
async function fetchAll() {
|
||||
loading.value = true
|
||||
varieties.value = await varietiesApi.list()
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
async function create(v: Partial<PlantVariety>) {
|
||||
const created = await varietiesApi.create(v)
|
||||
varieties.value.push(created)
|
||||
return created
|
||||
}
|
||||
|
||||
async function remove(id: number) {
|
||||
await varietiesApi.delete(id)
|
||||
varieties.value = varieties.value.filter(v => v.id !== id)
|
||||
}
|
||||
|
||||
return { varieties, loading, fetchAll, create, remove }
|
||||
})
|
||||
@@ -5,7 +5,8 @@
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"lib": ["ES2020", "DOM"],
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"types": ["vite/client"],
|
||||
"skipLibCheck": true,
|
||||
"paths": { "@/*": ["./src/*"] }
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user