337 lines
8.9 KiB
TypeScript
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>;
|
|
}
|
|
|