homemanager-fe/src/views/HousePlanner.vue

177 lines
4.7 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-20 16:43:32 +00:00
<PlannerBuildingSelect
:buildings="buildings"
:floors="floors"
:status="status"
:selected-building-id="selectedBuildingId"
:selected-floor-id="selectedFloorId"
@update:selected-building-id="(newValue) => buildingSelected(newValue)"
@update:selected-floor-id="(newValue) => (selectedFloorId = newValue)"
/>
2023-01-18 21:20:06 +00:00
<HousePlanner
v-if="selectedFloorId"
2023-01-19 15:07:57 +00:00
editable
2023-05-22 18:01:41 +00:00
class="h-full"
2023-01-19 15:07:57 +00:00
ref="plannerRef"
:key="`planner-${selectedFloorId}`"
2023-01-18 21:20:06 +00:00
:floor-document="floorPlan"
2023-01-20 16:43:32 +00:00
@update="
(layers, rooms, boundingBox) =>
updateDocument(layers, rooms, boundingBox)
"
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';
2023-01-24 19:04:01 +00:00
import { computed, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
2023-01-18 21:20:06 +00:00
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-20 16:43:32 +00:00
import PlannerBuildingSelect from '../components/house-planner/PlannerBuildingSelect.vue';
2023-01-19 15:07:57 +00:00
import { UpsertRoomItem } from '../interfaces/room.interfaces';
2023-01-20 16:43:32 +00:00
import { Line, Vec2Box } 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-24 19:04:01 +00:00
2023-01-18 21:20:06 +00:00
const building = useBuildingStore();
2023-01-24 19:04:01 +00:00
const route = useRoute();
2023-01-18 21:20:06 +00:00
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,
})
);
2023-01-20 16:43:32 +00:00
const buildingSelected = async (id: number) => {
if (id == null) return;
2023-01-19 15:07:57 +00:00
selectedFloorId.value = undefined;
2023-01-20 16:43:32 +00:00
selectedBuildingId.value = id;
await building.getFloors(id);
2023-01-18 21:20:06 +00:00
};
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;
};
2023-01-20 16:43:32 +00:00
const updateDocument = async (
data: FloorDocument,
rooms: Line[],
boundingBox?: Vec2Box
) => {
2023-01-19 15:07:57 +00:00
if (
!selectedBuildingId.value ||
!selectedFloorId.value ||
2023-01-20 16:43:32 +00:00
selectedFloorId.value !== data.id ||
2023-01-19 15:07:57 +00:00
!currentFloor.value ||
status.value === 'Saving...'
)
return;
status.value = 'Saving...';
try {
data = await updateRooms(data, rooms);
// Prevent useless requests
2023-01-20 16:43:32 +00:00
const floorPlan = JSON.stringify({ ...data, boundingBox });
2023-01-19 15:07:57 +00:00
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
};
2023-01-24 19:04:01 +00:00
const initialize = async () => {
await building.getBuildings();
if (route.query.buildingId) {
await buildingSelected(Number(route.query.buildingId));
if (route.query.floorId) {
selectedFloorId.value = Number(route.query.floorId);
}
}
};
2023-01-18 21:20:06 +00:00
onMounted(() => {
floors.value = [];
2023-01-24 19:04:01 +00:00
initialize();
2023-01-18 21:20:06 +00:00
});
</script>