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
|
|
|
|
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>
|