Add district header on root page
This commit is contained in:
parent
bfecae7d61
commit
5842b6251d
10 changed files with 124 additions and 157 deletions
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
48
ts/rmo/store/district.ts
Normal 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
5
ts/rmo/type.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export interface District {
|
||||
name: string;
|
||||
slug: string;
|
||||
url_logo: string;
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue