Add district header on root page

This commit is contained in:
Eli Ribble 2026-04-03 18:28:41 +00:00
parent bfecae7d61
commit 5842b6251d
No known key found for this signature in database
10 changed files with 124 additions and 157 deletions

View file

@ -187,117 +187,4 @@ document.addEventListener('DOMContentLoaded', onLoad);
{{ else }}
{{ template "rmo/component/header-district.html" .District }}
{{ end }}
<div class="container my-4">
<!-- Search Box -->
<div class="card search-box mb-4">
<div class="card-body">
<form class="row g-3 align-items-center" action="#" id="lookup-form">
<div class="col-md-9">
<address-or-report-input
name="address-or-report"
placeholder="Enter a report ID, address, neighborhood, or zip code"
></address-or-report-input>
</div>
<div class="col-md-3">
<span
data-bs-toggle="tooltip"
id="lookup-tooltip"
title="You can look up a report once you type in the full report ID. Start typing and I'll suggest complete IDs"
>
<button
type="submit"
class="btn btn-primary btn-lg w-100 disabled"
disabled
id="lookup"
>
Lookup Report by ID
</button>
</span>
</div>
<div class="col-12">
<div class="form-check custom-circle-checkbox">
<input
class="form-check-input"
type="checkbox"
id="checkboxNuisance"
data-color="danger"
checked
/>
<label class="form-check-label" for="checkboxNuisance"
>Mosquito Nuisance</label
>
</div>
<div class="form-check custom-circle-checkbox">
<input
class="form-check-input"
type="checkbox"
id="checkboxWater"
data-color="success"
checked
/>
<label class="form-check-label" for="checkboxWater"
>Standing Water</label
>
</div>
</div>
</form>
</div>
</div>
<!-- Map Section -->
<div class="card mb-4">
<div class="card-header bg-info text-white">
<h5 class="mb-0"><i class="bi bi-pin-map-fill me-2"></i>Reports Map</h5>
</div>
<div class="card-body p-0">
<div class="map-container">
<map-multipoint
id="map"
xmax="-118.0"
ymax="37.0"
xmin="-119.0"
ymin="36.0"
tegola="{{ .URL.Tegola }}"
zoom="9"
></map-multipoint>
</div>
</div>
</div>
<!-- Results Section -->
<div class="card">
<div
class="card-header bg-primary text-white d-flex justify-content-between align-items-center"
>
<h5 class="mb-0">
<i class="bi bi-geo-fill me-2"></i>Reports Near You
</h5>
<span class="badge bg-light text-dark" id="report-count"
>- Reports Found</span
>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table-report />
</div>
</div>
<!--
<div class="card-footer">
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center mb-0">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">Previous</a>
</li>
<li class="page-item active"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#">Next</a>
</li>
</ul>
</nav>
</div>
--></div>
</div>
{{ end }}

View file

@ -14,6 +14,7 @@ type districtR struct {
type district struct {
Name string `json:"name"`
Slug string `json:"slug"`
URLLogo string `json:"url_logo"`
}
@ -40,6 +41,7 @@ func (res *districtR) List(ctx context.Context, r *http.Request, query QueryPara
}
districts = append(districts, &district{
Name: org.Name(),
Slug: slug,
URLLogo: logo,
})
}

View file

@ -5,10 +5,13 @@
</template>
<script setup lang="ts">
import { ref, computed } from "vue";
import { onMounted, ref } from "vue";
import { useHead } from "@vueuse/head";
import { router } from "@/rmo/router";
import { useDistrictStore } from "@/rmo/store/district";
import type { District } from "@/rmo/type";
const district = useDistrictStore();
const count = ref<number>(0);
const message = ref<string>("hey");
@ -16,6 +19,16 @@ const increment = (): void => {
count.value++;
};
onMounted(() => {
district
.get()
.then((districts: District[]) => {
console.log("got districts");
})
.catch((e) => {
console.error("Failed to get districts", e);
});
});
// Reactive head management
/*
useHead({

View file

@ -71,12 +71,4 @@
</main>
</template>
<script setup lang="ts">
import { ref } from "vue";
interface District {
name: string;
url_logo: string;
}
const district = ref<District | null>(null);
</script>
<script setup lang="ts"></script>

View file

@ -1,18 +1,38 @@
import { createRouter, createWebHistory } from "vue-router";
import type { RouteRecordRaw } from "vue-router";
import Home from "@/rmo/view/Home.vue";
import Nuisance from "@/rmo/view/Nuisance.vue";
import HomeBase from "@/rmo/view/Home.vue";
import HomeDistrict from "@/rmo/view/district/Home.vue";
import NuisanceBase from "@/rmo/view/Nuisance.vue";
//import * as NuisanceDistrict from "@/rmo/view/district/Nuisance.vue";
import Status from "@/rmo/view/Status.vue";
import Water from "@/rmo/view/Water.vue";
const routes: RouteRecordRaw[] = [
{
path: "/",
name: "Home",
component: Home,
name: "HomeBase",
component: HomeBase,
},
{
path: "/nuisance",
name: "Nuisance",
component: Nuisance,
name: "NuisanceBase",
component: NuisanceBase,
},
{
path: "/district/:slug",
name: "HomeDistrict",
component: HomeDistrict,
props: true,
},
/*{
path: "/district/{slug}/nuisance",
name: "NuisanceDistrict",
component: NuisanceDistrict,
props: true,
},*/
{
path: "/status",
name: "Status",
component: Status,
},
{
path: "/water",

48
ts/rmo/store/district.ts Normal file
View file

@ -0,0 +1,48 @@
import { ref } from "vue";
import { defineStore } from "pinia";
import { District } from "@/rmo/type";
export const useDistrictStore = defineStore("district", () => {
const districts = ref<District[] | null>(null);
const error = ref<string | null>(null);
const loading = ref<boolean>(false);
const ongoingFetch = ref<Promise<District[]> | null>(null);
async function fetchDistricts(): Promise<District[]> {
loading.value = true;
error.value = null;
try {
const response = await fetch("/api/district");
if (!response.ok) throw new Error("Failed to fetch districts");
const data: District[] = await response.json();
districts.value = data;
return data;
} catch (e) {
error.value = e instanceof Error ? e.message : "an error ocurred";
console.error("Error fetching districts:", e);
throw new Error(error.value);
} finally {
loading.value = false;
}
}
async function get(): Promise<District[]> {
if (districts.value != null) {
return districts.value;
}
if (ongoingFetch.value !== null) {
return ongoingFetch.value;
}
const s = await fetchDistricts();
districts.value = s;
ongoingFetch.value = null;
return s;
}
return {
error,
get,
};
});

5
ts/rmo/type.ts Normal file
View file

@ -0,0 +1,5 @@
export interface District {
name: string;
slug: string;
url_logo: string;
}

View file

@ -1,3 +1,12 @@
<style scoped>
.district-logo {
display: block;
margin-left: auto;
margin-right: auto;
max-height: 88px;
width: auto;
}
</style>
<template>
<Home>
<template #header>
@ -20,14 +29,14 @@
For this area, mosquito control services are provided by
</p>
<h3 class="text-center">{{ district.name }}</h3>
<img class="district-logo" src="{{ district.url_logo }}" />
<img class="district-logo" :src="district.url_logo" />
</div>
</div>
</div>
</section>
</template>
<template v-else>
<p>loading</p>
<p>loading district...</p>
</template>
</template>
</Home>
@ -35,11 +44,21 @@
<script setup lang="ts">
import { ref } from "vue";
import { computedAsync } from "@vueuse/core";
import Home from "@/rmo/content/Home.vue";
import type { District } from "@/rmo/type";
import { useDistrictStore } from "@/rmo/store/district";
interface District {
name: string;
url_logo: string;
interface Props {
slug: string;
}
const district = ref<District | null>(null);
const props = defineProps<Props>();
const districtStore = useDistrictStore();
const district = computedAsync(async (): Promise<District | null> => {
const districts = await districtStore.get();
return (
districts.find((district: District) => district.slug == props.slug) || null
);
});
</script>

View file

@ -1,5 +1,6 @@
import { createApp } from "vue";
import { createHead } from "@vueuse/head";
import { createPinia } from "pinia";
import "@/gen/custom-icons.scss";
import "@/style/rmo.scss";
import router from "@/rmo/router";
@ -7,7 +8,9 @@ import App from "@/rmo/App.vue";
const app = createApp(App);
const head = createHead();
const pinia = createPinia();
app.use(head);
app.use(pinia);
app.use(router);
app.mount("#app");

View file

@ -24,28 +24,6 @@ document.addEventListener("DOMContentLoaded", () => {
}
});
});
document.addEventListener("init", () => {
const user = {
display_name: "",
initials: "",
notifications: [],
notification_counts: {
communication: 0,
home: 0,
review: 0,
},
organization: {
name: "",
},
role: "",
username: "",
};
});
interface GreetingComponent {
message: string;
name: string;
updateMessage(): void;
}
const pinia = createPinia();
const app = createApp(App);