Get review detail UI to show without crashing

It doesn't fully work yet though.
This commit is contained in:
Eli Ribble 2026-03-28 12:35:12 -07:00
parent 9921618c12
commit 9a9371301c
No known key found for this signature in database
5 changed files with 100 additions and 107 deletions

View file

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

View file

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

View file

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

View file

@ -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);

View file

@ -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 = {};
}