homemanager-fe/src/views/HousePlanner.vue

178 lines
5.0 KiB
Vue
Raw Normal View History

2023-01-18 21:20:06 +00:00
<template>
2023-01-19 15:07:57 +00:00
<div class="relative h-full bg-gray-100">
2023-01-18 21:20:06 +00:00
<div
class="absolute top-0 left-0 z-10 rounded-br-md border-b-2 border-r-2 border-gray-200 bg-white px-2 py-2 shadow-lg"
>
<div class="flex flex-row items-center space-x-4 px-4">
<div class="flex flex-row items-center space-x-4">
<label for="building">Building:</label>
<select
id="building"
class="rounded-sm border-gray-300 py-1 focus:ring-2 focus:ring-blue-200"
v-model="selectedBuildingId"
@change="buildingSelected()"
>
<option v-for="building of buildings" :value="building.id">
{{ building.displayName }}
</option>
</select>
</div>
<div
class="flex flex-row items-center space-x-4"
v-if="selectedBuildingId"
>
<label for="floor">Floor:</label>
<select
id="floor"
class="rounded-sm border-gray-300 py-1 focus:ring-2 focus:ring-blue-200"
v-model="selectedFloorId"
>
<option v-for="floor of floors" :value="floor.id">
{{ floor.displayName }} ({{ floor.number }})
</option>
</select>
</div>
<div v-if="selectedFloorId">{{ status }}</div>
</div>
</div>
<HousePlanner
v-if="selectedFloorId"
2023-01-19 15:07:57 +00:00
editable
ref="plannerRef"
:key="`planner-${selectedFloorId}`"
2023-01-18 21:20:06 +00:00
:floor-document="floorPlan"
2023-01-19 15:07:57 +00:00
@update="(layers, rooms) => updateDocument(layers, rooms)"
2023-01-18 21:20:06 +00:00
@edited="status = 'Modified'"
/>
2023-01-19 15:07:57 +00:00
<div
class="flex h-full w-full select-none items-center justify-center text-lg"
v-else
>
<span class="font-bold uppercase text-gray-300"
>Choose a floor to edit from the top left</span
>
</div>
2023-01-18 21:20:06 +00:00
</div>
</template>
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { computed, onMounted, ref } from 'vue';
import { defaultRoomData } from '../components/house-planner/helpers/default-room';
import HousePlanner from '../components/house-planner/HousePlanner.vue';
import { FloorDocument } from '../components/house-planner/interfaces/floor-document.interface';
2023-01-19 15:07:57 +00:00
import { UpsertRoomItem } from '../interfaces/room.interfaces';
import { Line } from '../modules/house-planner/interfaces';
2023-01-18 21:20:06 +00:00
import { useBuildingStore } from '../store/building.store';
2023-01-19 15:07:57 +00:00
import extractLinePoints from '../utils/extract-line-points';
2023-01-18 21:20:06 +00:00
const building = useBuildingStore();
const { buildings, floors } = storeToRefs(building);
const selectedBuildingId = ref<number>();
const selectedFloorId = ref<number>();
const status = ref('No changes');
2023-01-19 15:07:57 +00:00
const plannerRef = ref<InstanceType<typeof HousePlanner>>();
2023-01-18 21:20:06 +00:00
const currentFloor = computed(
() =>
selectedFloorId.value &&
floors.value.find((floor) => floor.id === selectedFloorId.value)
);
const floorPlan = computed(
() =>
currentFloor.value &&
Object.assign({
...defaultRoomData,
2023-01-19 15:07:57 +00:00
...JSON.parse(currentFloor.value.plan || '{}'),
2023-01-18 21:20:06 +00:00
id: selectedFloorId.value,
})
);
const buildingSelected = async () => {
if (selectedBuildingId.value == null) return;
2023-01-19 15:07:57 +00:00
selectedFloorId.value = undefined;
2023-01-18 21:20:06 +00:00
await building.getFloors(selectedBuildingId.value);
};
2023-01-19 15:07:57 +00:00
const updateRooms = async (data: FloorDocument, rooms: Line[]) => {
2023-01-18 21:20:06 +00:00
if (
!selectedBuildingId.value ||
!selectedFloorId.value ||
!currentFloor.value
)
2023-01-19 15:07:57 +00:00
return data;
2023-01-18 21:20:06 +00:00
2023-01-19 15:07:57 +00:00
const extractedRooms: UpsertRoomItem[] = rooms.map((room) => ({
id: room.databaseId,
canvasObjectId: room.id,
displayName: room.name,
plan: JSON.stringify({ polygon: extractLinePoints(room) }),
}));
if (!extractedRooms.length) {
return data;
}
const createdRooms = await building.upsertFloorRooms(
2023-01-18 21:20:06 +00:00
selectedBuildingId.value,
currentFloor.value.number,
2023-01-19 15:07:57 +00:00
extractedRooms
2023-01-18 21:20:06 +00:00
);
2023-01-19 15:07:57 +00:00
if (createdRooms?.length) {
createdRooms.forEach((room) => {
if (!room.canvasObjectId || !room.id) return;
rooms.forEach((existing) => {
if (existing.id !== room.canvasObjectId) return;
existing.databaseId = room.id;
});
});
if (plannerRef.value) {
data = plannerRef.value.updateLocalDocument();
}
}
return data;
};
const updateDocument = async (data: FloorDocument, rooms: Line[]) => {
if (
!selectedBuildingId.value ||
!selectedFloorId.value ||
!currentFloor.value ||
status.value === 'Saving...'
)
return;
status.value = 'Saving...';
try {
data = await updateRooms(data, rooms);
// Prevent useless requests
const floorPlan = JSON.stringify(data);
if (currentFloor.value.plan === floorPlan) {
status.value = 'Saved!';
return;
}
await building.saveFloor(
selectedBuildingId.value,
currentFloor.value.number,
{
plan: floorPlan,
}
);
status.value = 'Saved!';
} catch (e) {
console.error(`Failed to save floor document: ${(e as Error).stack}`);
status.value = 'Failed to save!';
}
2023-01-18 21:20:06 +00:00
};
onMounted(() => {
floors.value = [];
building.getBuildings();
});
</script>