Working log in/route guard
This commit is contained in:
@@ -1,53 +1,100 @@
|
||||
<!-- SearchResults.vue -->
|
||||
<!-- components/SearchResults.vue -->
|
||||
<template>
|
||||
|
||||
<div class="fixed top-16 left-1/2 -translate-x-1/2 w-full max-w-2xl px-4">
|
||||
<div class="overflow-x-auto bg-base-100 rounded-lg shadow-2xl border border-gray-700">
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Address</th>
|
||||
<th>Phone</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- It now reads `searchResults` directly from the store -->
|
||||
<tr v-for="user in searchStore.searchResults" :key="user.id" class="hover cursor-pointer" @click="viewProfile(user.id)">
|
||||
<td>
|
||||
<div class="font-bold">{{ user.customer_first_name }} {{ user.customer_last_name }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>{{ user.customer_address }}</div>
|
||||
<div class="text-sm opacity-70">{{ user.customer_town }}, {{ user.customer_state }}</div>
|
||||
</td>
|
||||
<td>{{ user.customer_phone_number }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div
|
||||
ref="searchContainer"
|
||||
class="absolute top-16 left-1/2 -translate-x-1/2 z-50 w-96 max-w-[90vw] max-h-[70vh] bg-base-100 rounded-lg shadow-xl border border-base-300 flex flex-col"
|
||||
>
|
||||
<!-- Header of the search results box -->
|
||||
<div class="p-4 border-b border-base-300 flex-shrink-0">
|
||||
<h3 class="font-bold">Search Results</h3>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
THE FIX IS HERE:
|
||||
- Removed the `menu` class from the `<ul>`.
|
||||
- Added `flex flex-col` to explicitly force a single vertical column.
|
||||
- Added `space-y-1` to add a small gap between each list item.
|
||||
-->
|
||||
<ul class="flex flex-col space-y-1 p-2 flex-grow overflow-y-auto">
|
||||
<li v-if="isLoading" class="p-4 text-center">
|
||||
<span class="loading loading-spinner"></span>
|
||||
</li>
|
||||
<li v-else-if="searchResults.length === 0 && searchTerm.length > 1" class="px-4 py-2 text-sm text-gray-500">
|
||||
No results found for "{{ searchTerm }}"
|
||||
</li>
|
||||
|
||||
<!-- The v-for now loops through simple <li> elements -->
|
||||
<li v-for="result in searchResults" :key="result.id">
|
||||
<!--
|
||||
We add styling directly to the router-link to make it look like a clickable list item.
|
||||
- `block`: Makes the entire area clickable, not just the text.
|
||||
-->
|
||||
<router-link
|
||||
:to="{ name: 'customerProfile', params: { id: result.id } }"
|
||||
@click="clearSearch"
|
||||
class="block p-2 rounded-lg hover:bg-base-200 focus:bg-primary focus:text-primary-content"
|
||||
>
|
||||
<div>
|
||||
<div class="font-bold">{{ result.customer_first_name }} {{ result.customer_last_name }}</div>
|
||||
<div class="text-sm opacity-70">
|
||||
{{ result.customer_address }}
|
||||
</div>
|
||||
<div class="text-sm opacity-70">
|
||||
{{ result.customer_town }}, {{ getStateName(result.customer_state) }}
|
||||
</div>
|
||||
<div class="text-xs opacity-60 mt-1">
|
||||
{{ result.customer_phone_number }}
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
// 1. Import the store
|
||||
import { defineComponent } from 'vue';
|
||||
import { mapState, mapActions } from 'pinia';
|
||||
import { useSearchStore } from '../stores/search'; // Adjust path if needed
|
||||
|
||||
export default defineComponent({
|
||||
name: "SearchResults",
|
||||
setup() {
|
||||
// 2. Make the store available
|
||||
const searchStore = useSearchStore();
|
||||
return { searchStore };
|
||||
name: 'SearchResults',
|
||||
|
||||
data() {
|
||||
return {
|
||||
stateMap: {
|
||||
0: 'MA', 1: 'RI', 2: 'NH', 3: 'ME', 4: 'VT', 5: 'CT', 6: 'NY',
|
||||
} as Record<number, string>,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(useSearchStore, ['searchTerm', 'searchResults', 'isLoading']),
|
||||
},
|
||||
|
||||
methods: {
|
||||
viewProfile(customerId: number) {
|
||||
// When a user is clicked, navigate to their profile...
|
||||
this.$router.push({ name: 'customerProfile', params: { id: customerId } });
|
||||
// ...and clear the search so the overlay disappears.
|
||||
this.searchStore.clearSearch();
|
||||
}
|
||||
}
|
||||
...mapActions(useSearchStore, ['clearSearch']),
|
||||
|
||||
getStateName(stateValue: number | string): string {
|
||||
const stateNumber = Number(stateValue);
|
||||
return this.stateMap[stateNumber] || 'N/A';
|
||||
},
|
||||
|
||||
handleClickOutside(event: MouseEvent) {
|
||||
const searchContainer = this.$refs.searchContainer as HTMLElement;
|
||||
const searchInput = document.getElementById('customer-search-input');
|
||||
|
||||
if (searchContainer && !searchContainer.contains(event.target as Node) && searchInput && !searchInput.contains(event.target as Node)) {
|
||||
this.clearSearch();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
document.addEventListener('mousedown', this.handleClickOutside);
|
||||
},
|
||||
beforeUnmount() {
|
||||
document.removeEventListener('mousedown', this.handleClickOutside);
|
||||
},
|
||||
});
|
||||
</script>c
|
||||
</script>
|
||||
Reference in New Issue
Block a user