ca-grow-ops-manager/frontend/src/lib/layoutApi.ts
fullsizemalt 2acef3c63c
Some checks are pending
Test / backend-test (push) Waiting to run
Test / frontend-test (push) Waiting to run
fix(frontend): Update LayoutCanvas and layoutApi types
2026-01-01 16:39:49 -08:00

337 lines
8.9 KiB
TypeScript

import api from './api';
export interface LayoutProperty {
id: string;
name: string;
address?: string;
licenseNum?: string;
buildings: LayoutBuilding[];
createdAt?: string;
}
export interface LayoutBuilding {
id: string;
propertyId: string;
name: string;
code: string;
type: string;
floors: LayoutFloor[];
}
export interface LayoutFloor {
id: string;
buildingId: string;
name: string;
number: number;
width: number;
height: number;
ceilingHeight?: number;
defaultTiers?: number;
rooms: LayoutRoom[];
}
export interface LayoutRoom {
id: string;
floorId: string;
name: string;
code: string;
type: 'VEG' | 'FLOWER' | 'DRY' | 'CURE' | 'MOTHER' | 'CLONE' | 'FACILITY';
posX: number;
posY: number;
width: number;
height: number;
rotation: number;
color?: string;
sections?: LayoutSection[];
}
export interface LayoutPosition {
id: string;
sectionId: string;
row: number;
column: number;
tier: number;
slot: number;
status: string;
plantId?: string;
plant?: any;
}
export interface LayoutSection {
id: string;
roomId: string;
name: string;
code: string;
type: string;
posX: number;
posY: number;
width: number;
height: number;
rows: number;
columns: number;
tiers: number;
spacing?: number;
positions?: LayoutPosition[];
}
// 3D Visualization Types
export interface Position3D {
id: string;
row: number;
column: number;
tier: number;
status: string;
plant: {
id: string;
tagNumber: string;
status: string;
batchId: string | null;
batchName: string | null;
plantTypeId: string | null;
strain: string | null;
stage: string | null;
} | null;
}
export interface Section3D {
id: string;
name: string;
code: string;
type: string;
posX: number;
posY: number;
width: number;
height: number;
rows: number;
columns: number;
positions: Position3D[];
}
export interface Room3D {
id: string;
name: string;
code: string;
type: string;
posX: number;
posY: number;
width: number;
height: number;
color: string | null;
sections: Section3D[];
}
export interface Floor3DData {
floor: {
id: string;
name: string;
number: number;
width: number;
height: number;
building: string;
property: string;
};
rooms: Room3D[];
stats: {
totalRooms: number;
totalSections: number;
totalPositions: number;
occupiedPositions: number;
};
}
// ========================================
// API Functions
// ========================================
export const layoutApi = {
// Properties
async getProperties(): Promise<LayoutProperty[]> {
const response = await api.get('/layout/properties');
return response.data;
},
async createProperty(data: { name: string; address?: string; licenseNum?: string }): Promise<LayoutProperty> {
const response = await api.post('/layout/properties', data);
return response.data;
},
// Buildings
async createBuilding(data: { propertyId: string; name: string; code: string; type: string }): Promise<LayoutBuilding> {
const response = await api.post('/layout/buildings', data);
return response.data;
},
// Floors
async getFloor(id: string): Promise<LayoutFloor & { building: LayoutBuilding }> {
const response = await api.get(`/layout/floors/${id}`);
return response.data;
},
async createFloor(data: {
buildingId: string;
name: string;
number: number;
width?: number;
height?: number;
ceilingHeight?: number;
defaultTiers?: number;
}): Promise<LayoutFloor> {
const response = await api.post('/layout/floors', data);
return response.data;
},
// 3D Visualization
async getFloor3D(id: string): Promise<Floor3DData> {
const response = await api.get(`/layout/floors/${id}/3d`);
return response.data;
},
async saveFloorLayout(floorId: string, rooms: LayoutRoom[]): Promise<LayoutFloor> {
const roomsForApi = rooms.map(r => ({
id: r.id,
name: r.name,
code: r.code,
type: r.type,
posX: r.posX,
posY: r.posY,
width: r.width,
height: r.height,
color: r.color,
rotation: r.rotation,
sections: r.sections // Include sections in save
}));
const response = await api.post(`/layout/floors/${floorId}/layout`, { rooms: roomsForApi });
return response.data;
},
async generateRoom(data: {
floorId: string;
name: string;
code: string;
type: string;
setupType: string;
tiers: number;
racksCount: number;
rowsPerRack: number;
colsPerRack: number;
}): Promise<LayoutRoom> {
const response = await api.post('/layout/rooms/generate', data);
return response.data;
},
// Rooms
async createRoom(data: Partial<LayoutRoom>): Promise<LayoutRoom> {
const response = await api.post('/layout/rooms', data);
return response.data;
},
async updateRoom(id: string, data: Partial<LayoutRoom>): Promise<LayoutRoom> {
const response = await api.put(`/layout/rooms/${id}`, data);
return response.data;
},
async deleteRoom(id: string): Promise<void> {
await api.delete(`/layout/rooms/${id}`);
},
// Sections
async createSection(data: Partial<LayoutSection> & { rows: number; columns: number }): Promise<LayoutSection> {
const response = await api.post('/layout/sections', data);
return response.data;
},
async getRoomSections(roomId: string): Promise<LayoutSection[]> {
const response = await api.get(`/layout/rooms/${roomId}/sections`);
return response.data;
},
async occupyPosition(positionId: string, data: { batchId?: string; plantTypeId?: string }): Promise<void> {
await api.post(`/layout/positions/${positionId}/occupy`, data);
},
async fillSection(sectionId: string, batchId: string, maxCount?: number): Promise<{ plantsCreated: number; message: string }> {
const response = await api.post(`/layout/sections/${sectionId}/fill`, { batchId, maxCount });
return response.data;
},
async movePlant(plantId: string, targetPositionId: string, reason?: string): Promise<{ newAddress: string; message: string }> {
const response = await api.post(`/layout/plants/${plantId}/move`, { targetPositionId, reason });
return response.data;
},
async getSection(id: string): Promise<LayoutSection> {
const response = await api.get(`/layout/sections/${id}`);
return response.data;
},
async updateSection(id: string, updates: {
name?: string;
code?: string;
type?: string;
rows?: number;
columns?: number;
}): Promise<any> {
const response = await api.patch(`/layout/sections/${id}`, updates);
return response.data;
},
// ========================================
// Plant Type Library (Rackula-inspired)
// ========================================
async getPlantTypes(): Promise<LayoutPlantType[]> {
const response = await api.get('/layout/plant-types');
return response.data;
},
async getPlantType(slug: string): Promise<LayoutPlantType> {
const response = await api.get(`/layout/plant-types/${slug}`);
return response.data;
},
async createPlantType(data: CreatePlantTypeData): Promise<LayoutPlantType> {
const response = await api.post('/layout/plant-types', data);
return response.data;
},
async updatePlantType(slug: string, data: Partial<CreatePlantTypeData>): Promise<LayoutPlantType> {
const response = await api.put(`/layout/plant-types/${slug}`, data);
return response.data;
},
async deletePlantType(slug: string): Promise<void> {
await api.delete(`/layout/plant-types/${slug}`);
}
};
// Plant Type Library Types
export interface LayoutPlantType {
id: string;
slug: string;
name: string;
strain?: string;
category: 'VEG' | 'FLOWER' | 'MOTHER' | 'CLONE' | 'SEEDLING';
colour: string;
growthDays?: number;
yieldGrams?: number;
notes?: string;
tags?: string[];
customFields?: Record<string, unknown>;
createdAt?: string;
updatedAt?: string;
}
export interface CreatePlantTypeData {
name: string;
strain?: string;
category: 'VEG' | 'FLOWER' | 'MOTHER' | 'CLONE' | 'SEEDLING';
colour: string;
growthDays?: number;
yieldGrams?: number;
notes?: string;
tags?: string[];
customFields?: Record<string, unknown>;
}