Add ability to select items and display in detail view
This commit is contained in:
parent
e0a586b311
commit
fb853a2bd3
5 changed files with 65 additions and 44 deletions
|
|
@ -18,7 +18,7 @@
|
|||
<div class="text-muted small mb-2">Signal → Lead</div>
|
||||
<button
|
||||
class="btn btn-outline-primary tool-button"
|
||||
:disabled="selectedSignals.length === 0 || creating"
|
||||
:disabled="selectedSignalIDs.size === 0 || creating"
|
||||
@click="createLead()"
|
||||
>
|
||||
<span v-if="!creating">Create New Lead from Selection</span>
|
||||
|
|
@ -29,13 +29,13 @@
|
|||
</button>
|
||||
<button
|
||||
class="btn btn-outline-secondary tool-button"
|
||||
:disabled="selectedSignals.length === 0"
|
||||
:disabled="selectedSignalIDs.size === 0"
|
||||
>
|
||||
Add Signals to Existing Lead
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-outline-secondary tool-button"
|
||||
:disabled="selectedSignals.length === 0"
|
||||
:disabled="selectedSignalIDs.size === 0"
|
||||
@click="markAsAddressed()"
|
||||
>
|
||||
Mark Signal as Addressed
|
||||
|
|
@ -75,7 +75,7 @@
|
|||
<script setup lang="ts">
|
||||
interface Props {
|
||||
creating: boolean;
|
||||
selectedSignals: Set<int>;
|
||||
selectedSignalIDs: Set<int>;
|
||||
}
|
||||
const props = defineProps<Props>();
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -48,28 +48,7 @@
|
|||
>
|
||||
<tbody>
|
||||
<tr v-for="signal in selectedSignals" :key="signal.id">
|
||||
<td>
|
||||
<button
|
||||
@click="toggleSignal(signal)"
|
||||
class="btn btn-sm btn-link text-danger p-0 ms-1"
|
||||
style="font-size: 0.7rem"
|
||||
>
|
||||
<i class="bi bi-x"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="signal.type === 'flyover pool'">Pool</span>
|
||||
<span v-else-if="signal.type === 'publicreport nuisance'"
|
||||
>Nuisance</span
|
||||
>
|
||||
<span v-else-if="signal.type === 'publicreport water'"
|
||||
>Water</span
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<TimeRelative :time="signal.created"></TimeRelative>
|
||||
</td>
|
||||
<td>{{ shortAddress(signal.address) }}</td>
|
||||
<PlanningColumnDetailEntry :signal="signal"/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -107,11 +86,12 @@ import MapMultipoint from "./MapMultipoint.vue";
|
|||
import MapProxiedArcgisTile from "./MapProxiedArcgisTile.vue";
|
||||
import { shortAddress } from "../format";
|
||||
import TimeRelative from "./TimeRelative.vue";
|
||||
import PlanningColumnDetailEntry from "./PlanningColumnDetailEntry.vue";
|
||||
import { useUserStore } from "../store/user";
|
||||
|
||||
interface Props {
|
||||
markers: Marker[];
|
||||
selectedSignals: Set<int>;
|
||||
selectedSignals: Array<Signal>;
|
||||
}
|
||||
const props = defineProps<Props>();
|
||||
const user = useUserStore();
|
||||
|
|
|
|||
33
ts/components/PlanningColumnDetailEntry.vue
Normal file
33
ts/components/PlanningColumnDetailEntry.vue
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<td>
|
||||
<button
|
||||
@click="toggleSignal(signal)"
|
||||
class="btn btn-sm btn-link text-danger p-0 ms-1"
|
||||
style="font-size: 0.7rem"
|
||||
>
|
||||
<i class="bi bi-x"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="signal.type === 'flyover pool'">Pool</span>
|
||||
<span v-else-if="signal.type === 'publicreport nuisance'"
|
||||
>Nuisance</span
|
||||
>
|
||||
<span v-else-if="signal.type === 'publicreport water'"
|
||||
>Water</span
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<TimeRelative :time="signal.created"></TimeRelative>
|
||||
</td>
|
||||
<td>{{ shortAddress(signal.address) }}</td>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { shortAddress } from "../format";
|
||||
import TimeRelative from "@/components/TimeRelative.vue";
|
||||
interface Props {
|
||||
signal: Signal;
|
||||
}
|
||||
const props = defineProps<Props>();
|
||||
</script>
|
||||
|
|
@ -118,13 +118,13 @@
|
|||
<div class="mb-3">
|
||||
<div class="fw-semibold mb-2">
|
||||
Signals
|
||||
<span class="badge bg-primary" v-show="selectedSignals.size > 0">
|
||||
{{ selectedSignals.size }}
|
||||
<span class="badge bg-primary" v-show="selectedSignalIDs.size > 0">
|
||||
{{ selectedSignalIDs.size }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="signals != null && signals.length === 0"
|
||||
v-if="signals != null && signals.length == 0"
|
||||
class="text-muted small fst-italic"
|
||||
>
|
||||
No signals found
|
||||
|
|
@ -209,7 +209,7 @@ interface Props {
|
|||
leads: Lead[] | null;
|
||||
loading: boolean;
|
||||
planFollowups: Followup[] | null;
|
||||
selectedSignals: Set<int>;
|
||||
selectedSignalIDs: Set<int>;
|
||||
signals: Signal[] | null;
|
||||
}
|
||||
const emit = defineEmits<Emits>();
|
||||
|
|
@ -220,10 +220,10 @@ const filters = ref({
|
|||
sort: "newest",
|
||||
});
|
||||
const isSelected = (id) => {
|
||||
return props.selectedSignals.values().some((s) => s.id === id);
|
||||
return props.selectedSignalIDs.values().some((s) => s.id === id);
|
||||
};
|
||||
const toggleSignal = (signal: int) => {
|
||||
if (props.selectedSignals.has(signal)) {
|
||||
if (props.selectedSignalIDs.has(signal)) {
|
||||
emit("signalDeselect", signal);
|
||||
} else {
|
||||
emit("signalSelect", signal);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
:loading="loading"
|
||||
:planFollowups="planFollowups"
|
||||
@refresh="refresh"
|
||||
:selectedSignals="selectedSignals"
|
||||
:selectedSignalIDs="selectedSignalIDs"
|
||||
@signalDeselect="signalDeselect"
|
||||
@signalSelect="signalSelect"
|
||||
:signals="signal.all"
|
||||
|
|
@ -35,12 +35,13 @@
|
|||
<PlanningColumnDetail
|
||||
:markers="markers"
|
||||
:selectedSignals="selectedSignals"
|
||||
:signals="signal.all"
|
||||
/>
|
||||
</template>
|
||||
<template #right>
|
||||
<PlanningColumnAction
|
||||
:creating="creating"
|
||||
:selectedSignals="selectedSignals"
|
||||
:selectedSignalIDs="selectedSignalIDs"
|
||||
/>
|
||||
</template>
|
||||
</ThreeColumn>
|
||||
|
|
@ -70,7 +71,7 @@ const leads = ref([]);
|
|||
const loading = ref(false);
|
||||
const planFollowups = ref([]);
|
||||
const poolLocations = ref({});
|
||||
const selectedSignals = ref(new Set([]));
|
||||
const selectedSignalIDs = ref(new Set<int>([]));
|
||||
const signal = useSignalStore();
|
||||
const user = useUserStore();
|
||||
|
||||
|
|
@ -100,6 +101,13 @@ const getBoundingBox = (points) => {
|
|||
const markers = computed(() => {
|
||||
return [];
|
||||
});
|
||||
const selectedSignals = computed(() => {
|
||||
if (selectedSignalIDs.value.size == 0 || signal.all == null) {
|
||||
return [];
|
||||
}
|
||||
const result = signal.all.filter((s) => selectedSignalIDs.value.has(s));
|
||||
return result;
|
||||
});
|
||||
const updateMap = (signals) => {
|
||||
const locations = signals.map((s) => s.location);
|
||||
const markers = locations.map((l) =>
|
||||
|
|
@ -151,11 +159,11 @@ const loadPlanFollowups = async () => {
|
|||
};
|
||||
|
||||
const clearSelection = () => {
|
||||
selectedSignals.value.clear();
|
||||
selectedSignalIDs.value.clear();
|
||||
};
|
||||
|
||||
const createLead = async () => {
|
||||
if (selectedSignals.value.size === 0) return;
|
||||
if (selectedSignalIDs.value.size === 0) return;
|
||||
|
||||
creating.value = true;
|
||||
|
||||
|
|
@ -167,7 +175,7 @@ const createLead = async () => {
|
|||
},
|
||||
body: JSON.stringify({
|
||||
pool_locations: poolLocations.value,
|
||||
signal_ids: selectedSignals.value.map((s) => s.id),
|
||||
signal_ids: selectedSignalIDs,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -191,7 +199,7 @@ const createLead = async () => {
|
|||
};
|
||||
|
||||
const markAsAddressed = async () => {
|
||||
if (selectedSignals.value.size === 0) return;
|
||||
if (selectedSignalIDs.value.size === 0) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${apiBase.value}/signal/mark-addressed`, {
|
||||
|
|
@ -200,7 +208,7 @@ const markAsAddressed = async () => {
|
|||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
signal_ids: selectedSignals.value.map((s) => s.id),
|
||||
signal_ids: selectedSignalIDs,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -209,7 +217,7 @@ const markAsAddressed = async () => {
|
|||
}
|
||||
|
||||
signals.value = signals.value.filter(
|
||||
(signal) => !selectedSignals.value.some((s) => s.id === signal.id),
|
||||
(signal) => !selectedSignalIDs.value.has(s.id),
|
||||
);
|
||||
|
||||
clearSelection();
|
||||
|
|
@ -223,10 +231,10 @@ const refresh = () => {
|
|||
loadData();
|
||||
};
|
||||
const signalDeselect = (id: int) => {
|
||||
selectedSignals.value.delete(id);
|
||||
selectedSignalIDs.value.delete(id);
|
||||
};
|
||||
const signalSelect = (id: int) => {
|
||||
selectedSignals.value.add(id);
|
||||
selectedSignalIDs.value.add(id);
|
||||
};
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue