Get review detail UI to show without crashing
It doesn't fully work yet though.
This commit is contained in:
parent
9921618c12
commit
9a9371301c
5 changed files with 100 additions and 107 deletions
|
|
@ -97,8 +97,7 @@ const initializeMap = () => {
|
|||
type: "raster",
|
||||
});
|
||||
|
||||
emit("load", { map: getCurrentInstance() });
|
||||
|
||||
/*
|
||||
map.value.on("click", (e) => {
|
||||
emit("map-click", {
|
||||
lng: e.lngLat.lng,
|
||||
|
|
@ -107,6 +106,7 @@ const initializeMap = () => {
|
|||
point: e.point,
|
||||
});
|
||||
});
|
||||
*/
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("hey dummy", e);
|
||||
|
|
@ -150,21 +150,6 @@ const setMarkers = (newMarkers) => {
|
|||
}
|
||||
};
|
||||
|
||||
const getCurrentInstance = () => {
|
||||
// Return an object with the public methods
|
||||
return {
|
||||
addLayer,
|
||||
addSource,
|
||||
jumpTo,
|
||||
on,
|
||||
once,
|
||||
queryRenderedFeatures,
|
||||
fitBounds,
|
||||
setLayoutProperty,
|
||||
setMarkers,
|
||||
};
|
||||
};
|
||||
|
||||
// Expose methods to parent components
|
||||
defineExpose({
|
||||
addLayer,
|
||||
|
|
@ -188,10 +173,3 @@ onBeforeUnmount(() => {
|
|||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.map-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -34,9 +34,11 @@
|
|||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
v-model="form.longitude"
|
||||
v-model="selectedTaskChanges.location.longitude"
|
||||
:class="{
|
||||
'border-warning': form.longitude !== originalValues.longitude,
|
||||
'border-warning':
|
||||
selectedTaskChanges.location.longitude !==
|
||||
selectedTask.location.longitude,
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -48,9 +50,11 @@
|
|||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
v-model="form.latitude"
|
||||
v-model="selectedTaskChanges.location.latitude"
|
||||
:class="{
|
||||
'border-warning': form.latitude !== originalValues.latitude,
|
||||
'border-warning':
|
||||
selectedTaskChanges.location?.latitude !==
|
||||
selectedTask.location?.latitude,
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -61,9 +65,11 @@
|
|||
<div class="col-sm-9">
|
||||
<select
|
||||
class="form-select"
|
||||
v-model="form.condition"
|
||||
v-model="selectedTaskChanges.pool.condition"
|
||||
:class="{
|
||||
'border-warning': form.condition !== originalValues.condition,
|
||||
'border-warning':
|
||||
selectedTaskChanges.pool.condition !==
|
||||
selectedTask.pool.condition,
|
||||
}"
|
||||
>
|
||||
<option value="">-- Select --</option>
|
||||
|
|
@ -77,22 +83,23 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="form.ownerContact" class="row mb-3">
|
||||
<div v-if="selectedTaskChanges.pool.ownerContact" class="row mb-3">
|
||||
<label class="col-sm-3 col-form-label fw-bold">Owner Contact:</label>
|
||||
<div class="col-sm-9">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
v-model="form.ownerContact"
|
||||
v-model="selectedTaskChanges.pool.owner_contact"
|
||||
:class="{
|
||||
'border-warning':
|
||||
form.ownerContact !== originalValues.ownerContact,
|
||||
selectedTaskChanges.pool.owner_contact !==
|
||||
selectedTask.pool.owner_contact,
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="form.residentContact" class="row mb-4">
|
||||
<div v-if="selectedTaskChanges.pool.resident_contact" class="row mb-4">
|
||||
<label class="col-sm-3 col-form-label fw-bold">
|
||||
Resident Contact:
|
||||
</label>
|
||||
|
|
@ -100,10 +107,11 @@
|
|||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
v-model="form.residentContact"
|
||||
v-model="selectedTaskChanges.pool.resident_contact"
|
||||
:class="{
|
||||
'border-warning':
|
||||
form.residentContact !== originalValues.residentContact,
|
||||
selectedTaskChanges.pool.resident_contact !==
|
||||
selectedTask.pool.resident_contact,
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -116,12 +124,14 @@
|
|||
<MapMultipoint
|
||||
ref="mapMultipoint"
|
||||
id="map"
|
||||
:organization-id="organizationId"
|
||||
:tegola="tegolaUrl"
|
||||
:xmin="serviceArea.xmin"
|
||||
:ymin="serviceArea.ymin"
|
||||
:xmax="serviceArea.xmax"
|
||||
:ymax="serviceArea.ymax"
|
||||
:bounds="mapBounds"
|
||||
:markers="mapMarkers"
|
||||
:organizationId="user.organization.id"
|
||||
:tegola="user.urls.tegola"
|
||||
:xmin="user.organization.service_area?.min.x ?? 0"
|
||||
:ymin="user.organization.service_area?.min.y ?? 0"
|
||||
:xmax="user.organization.service_area?.max.x ?? 0"
|
||||
:ymax="user.organization.service_area?.max.y ?? 0"
|
||||
></MapMultipoint>
|
||||
</div>
|
||||
|
||||
|
|
@ -129,12 +139,11 @@
|
|||
<MapProxiedArcgisTile
|
||||
ref="mapTile"
|
||||
class="map"
|
||||
:organization-id="organizationId"
|
||||
:tegola="tegolaUrl"
|
||||
:tiles-url="tilesUrl"
|
||||
:latitude="selectedTask.location.latitude"
|
||||
:longitude="selectedTask.location.longitude"
|
||||
@map-click="updatePoolLocation"
|
||||
:location="selectedTask.location"
|
||||
:organization-id="user.organization.id"
|
||||
:tegola="user.urls.tegola"
|
||||
:urlTiles="user.urls.tile"
|
||||
@map-click="doPoolLocation"
|
||||
></MapProxiedArcgisTile>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -142,10 +151,19 @@
|
|||
<script setup lang="ts">
|
||||
import MapMultipoint from "@/components/MapMultipoint.vue";
|
||||
import MapProxiedArcgisTile from "@/components/MapProxiedArcgisTile.vue";
|
||||
import { formatAddress } from "@/format";
|
||||
import ReviewTask from "@/types";
|
||||
|
||||
interface Props {
|
||||
loading: boolean;
|
||||
mapBounds?: Bounds;
|
||||
mapMarkers: Marker[];
|
||||
selectedTaskChanges: ReviewTask;
|
||||
selectedTask?: ReviewTask;
|
||||
user: User | null;
|
||||
}
|
||||
const props = defineProps<Props>();
|
||||
function doPoolLocation(lat, lng) {
|
||||
console.log("pool location", lat, lng);
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,20 @@
|
|||
<style scoped lang="scss">
|
||||
.entry-item {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.entry-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.entry-item.active {
|
||||
background-color: #e7f3ff;
|
||||
border-left: 4px solid #0d6efd;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<!-- Error Alert -->
|
||||
<div v-if="error" class="mt-3 alert alert-danger alert-dismissible">
|
||||
|
|
@ -28,7 +45,7 @@
|
|||
:key="task.id"
|
||||
class="entry-item"
|
||||
:class="{ active: selectedTaskID === task.id }"
|
||||
@click="selectTask(task)"
|
||||
@click="emit('doSelectTask', task.id)"
|
||||
>
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<div>
|
||||
|
|
@ -45,11 +62,15 @@
|
|||
<script setup lang="ts">
|
||||
import { formatAddress } from "@/format";
|
||||
|
||||
interface Emits {
|
||||
(e: "doSelectTask", id: int): void;
|
||||
}
|
||||
interface Props {
|
||||
error: string | null;
|
||||
selectedTaskID: int | null;
|
||||
tasks: ReviewTask[];
|
||||
total: int;
|
||||
}
|
||||
const emit = defineEmits<Emits>();
|
||||
const props = defineProps<Props>();
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -77,9 +77,9 @@ onMounted(() => {
|
|||
});
|
||||
|
||||
// Refs
|
||||
const currentPhotoIndex = ref(0);
|
||||
const error = ref(null);
|
||||
const loading = ref(true);
|
||||
const currentPhotoIndex = ref<int>(0);
|
||||
const error = ref<string | null>(null);
|
||||
const loading = ref<boolean>(true);
|
||||
const mapBounds = ref<Bounds | null>(null);
|
||||
const mapMarkers = ref<Marker[]>([]);
|
||||
const selectedId = ref<string | null>(null);
|
||||
|
|
|
|||
|
|
@ -24,23 +24,6 @@ body {
|
|||
border-left: 1px solid #dee2e6;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.entry-item {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.entry-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.entry-item.active {
|
||||
background-color: #e7f3ff;
|
||||
border-left: 4px solid #0d6efd;
|
||||
}
|
||||
|
||||
.placeholder-box {
|
||||
background-color: #e9ecef;
|
||||
border: 2px dashed #adb5bd;
|
||||
|
|
@ -80,6 +63,7 @@ body {
|
|||
<template #left>
|
||||
<ReviewPoolColumnList
|
||||
v-if="reviewTask.all"
|
||||
@doSelectTask="selectTask"
|
||||
:error="error"
|
||||
:selectedTaskID="selectedTaskID"
|
||||
:tasks="reviewTask.all"
|
||||
|
|
@ -90,7 +74,14 @@ body {
|
|||
</div>
|
||||
</template>
|
||||
<template #center>
|
||||
<ReviewPoolColumnDetail :selectedTask="selectedTask" />
|
||||
<ReviewPoolColumnDetail
|
||||
:loading="loading"
|
||||
:mapBounds="mapBounds || undefined"
|
||||
:mapMarkers="mapMarkers"
|
||||
:selectedTaskChanges="selectedTaskChanges"
|
||||
:selectedTask="selectedTask"
|
||||
:user="user"
|
||||
/>
|
||||
</template>
|
||||
<template #right>
|
||||
<ReviewPoolColumnAction :submitting="submitting" />
|
||||
|
|
@ -184,12 +175,17 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
});
|
||||
|
||||
// State
|
||||
const totalPending = ref<number>(0);
|
||||
const selectedTaskID = ref<int | null>(null);
|
||||
const originalValues = ref<Partial<FormData>>({});
|
||||
const loading = ref<boolean>(true);
|
||||
const submitting = ref<boolean>(false);
|
||||
const selectedTaskChanges = ref<ReviewTask>({
|
||||
location: {},
|
||||
pool: {},
|
||||
});
|
||||
const error = ref<string | null>(null);
|
||||
const loading = ref<boolean>(true);
|
||||
const mapBounds = ref<Bounds | null>(null);
|
||||
const mapMarkers = ref<Marker[]>([]);
|
||||
const selectedTaskID = ref<int | null>(null);
|
||||
const submitting = ref<boolean>(false);
|
||||
const totalPending = ref<number>(0);
|
||||
|
||||
const reviewTask = useReviewTaskStore();
|
||||
const user = useUserStore();
|
||||
|
|
@ -215,7 +211,7 @@ const changes = computed<Changes>(() => {
|
|||
];
|
||||
|
||||
fields.forEach((field) => {
|
||||
if (form[field.key] !== originalValues.value[field.key]) {
|
||||
if (selectedTaskChanges[field.key] !== selectedTask.value[field.key]) {
|
||||
updated.push(field.label);
|
||||
} else {
|
||||
unchanged.push(field.label);
|
||||
|
|
@ -236,22 +232,17 @@ async function fetchTasks() {
|
|||
}
|
||||
// Helper Functions
|
||||
// Task Selection
|
||||
function selectTask(task: Task): void {
|
||||
console.log("Selected task", task);
|
||||
selectedTask.value = task;
|
||||
function selectTask(id: int): void {
|
||||
console.log("Selected task", id);
|
||||
selectedTaskID.value = id;
|
||||
|
||||
// Populate form with task values
|
||||
form.latitude = task.location.latitude;
|
||||
form.longitude = task.location.longitude;
|
||||
form.condition = task.condition || "";
|
||||
form.ownerContact = task.ownerContact || "";
|
||||
form.residentContact = task.residentContact || "";
|
||||
form.poolShape = task.poolShape || "";
|
||||
|
||||
// Store original values for change tracking
|
||||
originalValues.value = { ...form };
|
||||
selectedTaskChanges.value = {
|
||||
location: {},
|
||||
pool: {},
|
||||
};
|
||||
|
||||
// Update map
|
||||
const task = reviewTask.byID(id);
|
||||
updateMap(task);
|
||||
}
|
||||
|
||||
|
|
@ -299,8 +290,8 @@ function updatePoolLocation(event: MapClickEvent): void {
|
|||
}).setLngLat([event.detail.lng, event.detail.lat]),
|
||||
]);
|
||||
|
||||
form.latitude = event.detail.lat;
|
||||
form.longitude = event.detail.lng;
|
||||
selectedTaskChanges.latitude = event.detail.lat;
|
||||
selectedTaskChanges.longitude = event.detail.lng;
|
||||
}
|
||||
|
||||
// Submit Review
|
||||
|
|
@ -314,18 +305,9 @@ async function submitReview(action: "committed" | "discarded"): Promise<void> {
|
|||
const payload: any = {
|
||||
task_id: selectedTask.value.id,
|
||||
status: action,
|
||||
updates: {},
|
||||
updates: selectedTaskChanges,
|
||||
};
|
||||
|
||||
// Include changed fields in the payload
|
||||
if (action === "committed") {
|
||||
(Object.keys(form) as Array<keyof FormData>).forEach((key) => {
|
||||
if (form[key] !== originalValues.value[key]) {
|
||||
payload.updates[key] = form[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const response = await fetch("/api/review/pool", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -353,12 +335,6 @@ async function submitReview(action: "committed" | "discarded"): Promise<void> {
|
|||
selectTask(reviewTask.all[nextIndex]);
|
||||
} else {
|
||||
selectedTask.value = null;
|
||||
form.condition = "";
|
||||
form.ownerContact = "";
|
||||
form.residentContact = "";
|
||||
form.poolShape = "";
|
||||
form.latitude = 0;
|
||||
form.longitude = 0;
|
||||
originalValues.value = {};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue