From d9a98e9eb2cfdb5e92ba82a95536fb5a4360e84b Mon Sep 17 00:00:00 2001 From: Eli Ribble Date: Sun, 22 Mar 2026 02:37:10 +0000 Subject: [PATCH] Begin ripping apart the communications page into components Essential to get the logic under control --- ts/store/communication.ts | 32 ++++---- ts/store/user.ts | 64 ++++++++++------ ts/view/Communication.vue | 150 ++++---------------------------------- 3 files changed, 73 insertions(+), 173 deletions(-) diff --git a/ts/store/communication.ts b/ts/store/communication.ts index 487bac3a..27573abb 100644 --- a/ts/store/communication.ts +++ b/ts/store/communication.ts @@ -1,43 +1,45 @@ import { defineStore } from "pinia"; import { ref, computed } from "vue"; +import { useUserStore } from "./user"; export const useCommunicationStore = defineStore("communication", () => { // State - const communications = ref(null); + const all = ref(null); const loading = ref(false); const error = ref(null); // Actions - async function fetchCommunications() { + async function fetchAll() { + const userStore = useUserStore(); + if (userStore.urls == null) { + throw new Error("can't fetch without user URL data"); + } + loading.value = true; error.value = null; try { const params = new URLSearchParams(); params.append("sort", "-created"); - if (typeFilter.value) params.append("type", typeFilter.value); + //if (typeFilter.value) params.append("type", typeFilter.value); const response = await fetch( - `$${apiBase.value}/communication?$${params}`, + `${userStore.urls.api.communication}?${params}`, ); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); - communications.value = data.communications; - - // if we already had something selected, reset it using the new data - if (selectedCommunication.value) { - const matching = communications.value.filter((report) => { - return report.id === selectedCommunication.value.id; - }); - if (matching.length > 0) { - selectedCommunication.value = matching[0]; - } - } + all.value = data.communications; } catch (err) { console.error("Error loading communications:", err); throw err; } } + return { + // State + all, + // Actions + fetch, + }; }); diff --git a/ts/store/user.ts b/ts/store/user.ts index f9895e75..1bc2d883 100644 --- a/ts/store/user.ts +++ b/ts/store/user.ts @@ -1,22 +1,48 @@ import { defineStore } from "pinia"; import { ref, computed } from "vue"; +// Define interfaces matching your Go structs +interface URLsAPI { + communication: string; +} + +interface URLs { + api: URLsAPI; + tegola: string; +} + +interface User { + display_name: string; + initials: string; + notification_counts: NotificationCounts; + notifications: any[]; // Replace with proper type + organization: string; // Replace with proper type + role: string; + username: string; +} + +interface UserResponse { + self: User; + urls: URLs; +} + +interface NotificationCounts { + // Add the actual structure based on your API + [key: string]: number; +} + export const useUserStore = defineStore("user", () => { // State - const display_name = ref(null); - const error = ref(null); - const initials = ref(null); + const display_name = ref(null); + const error = ref(null); + const initials = ref(null); const loading = ref(false); - const notification_counts = ref(null); - const notifications = ref(null); - const organization = ref(null); - const role = ref(null); - const urls = ref(null); - const username = ref(null); - - // Getters - const isAuthenticated = computed(() => user.value !== null); - const userName = computed(() => user.value?.name ?? ""); + const notification_counts = ref(null); + const notifications = ref(null); + const organization = ref(null); + const role = ref(null); + const urls = ref(null); + const username = ref(null); // Actions async function fetchUser() { @@ -27,7 +53,7 @@ export const useUserStore = defineStore("user", () => { const response = await fetch("/api/user/self"); if (!response.ok) throw new Error("Failed to fetch user"); - const data = await response.json(); + const data: UserResponse = await response.json(); display_name.value = data.self.display_name; initials.value = data.self.initials; notification_counts.value = data.self.notification_counts; @@ -38,17 +64,13 @@ export const useUserStore = defineStore("user", () => { username.value = data.self.username; console.log("loaded user data", data); } catch (e) { - error.value = e.message; + error.value = e instanceof Error ? e.message : "an error ocurred"; console.error("Error fetching user:", e); } finally { loading.value = false; } } - function clearUser() { - user.value = null; - } - return { // State display_name, @@ -61,11 +83,7 @@ export const useUserStore = defineStore("user", () => { role, urls, username, - // Getters - isAuthenticated, - userName, // Actions fetchUser, - clearUser, }; }); diff --git a/ts/view/Communication.vue b/ts/view/Communication.vue index e59d0ea2..40c6503c 100644 --- a/ts/view/Communication.vue +++ b/ts/view/Communication.vue @@ -3,128 +3,7 @@
-
-
-
- - -
-
- - - -
-
- -
-
- -
-
- - - - - {{ - comm.type === "publicreport.nuisance" - ? "Nuisance" - : "Standing Water" - }} - -
- - - -
- - -
-
- - {{ - comm.public_report.address.postal_code - }} -
- {{ formatAddress(comm.public_report.address) }} -
- - - {{ comm.public_report.images.length }} photo(s) - -
-
-
-
- -
- -

No reports found

-
-
+
@@ -781,16 +660,15 @@ import { useUserStore } from "../store/user"; import MapMultipoint from "../components/MapMultipoint.vue"; import TimeRelative from "../components/TimeRelative.vue"; -const communicationStore = useCommunicationStore(); +const communication = useCommunicationStore(); const user = useUserStore(); onMounted(() => { - communicationStore.fetchCommunications(); + communication.fetch(); }); // Refs const apiBase = ref("/api"); const selectedCommunication = ref(null); -const searchFilter = ref(""); const typeFilter = ref("all"); const messageText = ref(""); const showPhotoModal = ref(false); @@ -798,20 +676,10 @@ const currentPhotoIndex = ref(0); const showToast = ref(false); const toastTitle = ref(""); const toastMessage = ref(""); -const communications = ref([]); const loading = ref(false); const error = ref(null); const mapRef = ref(null); -// Computed properties -const filteredCommunications = computed(() => { - return communications.value.filter((report) => { - const matchesType = - typeFilter.value === "all" || report.type === typeFilter.value; - return matchesType && filterMatches(searchFilter.value, report); - }); -}); - const nuisance = computed(() => { return selectedCommunication.value?.public_report?.nuisance || null; }); @@ -820,6 +688,18 @@ const water = computed(() => { return selectedCommunication.value?.public_report?.water || null; }); +async function fetchCommunications() { + await communication.fetchAll(); + // if we already had something selected, reset it using the new data + if (selectedCommunication.value) { + const matching = communication.all.filter((c) => { + return c.id === selectedCommunication.value.id; + }); + if (matching.length > 0) { + selectedCommunication.value = matching[0]; + } + } +} // Methods function filterMatches(filter, comm) { // Implement your filter logic here