Major Refactor
This commit is contained in:
@@ -1,271 +1,128 @@
|
||||
<!-- headerauth.vue -->
|
||||
<template>
|
||||
<div class="navbar bg-primary border-b border-gray-700 sticky top-0 z-30">
|
||||
|
||||
<!-- Navbar Start Section -->
|
||||
<div class="navbar-start">
|
||||
<!-- Hamburger Menu Toggle for Mobile -->
|
||||
<label for="my-drawer-2" class="btn btn-ghost btn-circle drawer-button lg:hidden">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7" /></svg>
|
||||
</label>
|
||||
|
||||
<div class="navbar bg-primary border-b border-bottom-500 border-gray-500">
|
||||
<div class="basis-1/4 md:basis-1/4">
|
||||
<router-link :to="{ name: 'home' }">
|
||||
<div class="text-3xl">
|
||||
<img src="../../assets/images/1.png" alt="" width="250" height="250" />
|
||||
|
||||
</div>
|
||||
<!-- Logo -->
|
||||
<router-link :to="{ name: 'home' }" class="btn btn-ghost normal-case text-xl">
|
||||
<img src="../../assets/images/1.png" alt="Company Logo" class="h-8 md:h-10 w-auto" />
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="basis-1/4 md:basis-1/2 justify-center text-center">
|
||||
<input type="text" placeholder="Search " class="input input-bordered w-24 md:w-auto grow" v-model="searchTerm" />
|
||||
|
||||
<!-- Navbar Center Section (Desktop Search Bar) -->
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search Customers..."
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
v-model="searchStore.searchTerm"
|
||||
@input="searchStore.fetchSearchResults"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="basis-1/2 md:basis-1/4 justify-end gap-5">
|
||||
|
||||
<!-- <button class="btn btn-green btn-sm" @click.prevent="increaseCall()">Call</button> -->
|
||||
|
||||
<router-link :to="{ name: 'customerCreate' }">
|
||||
<button class="btn bg-blue-700 btn-sm">Create Customer</button>
|
||||
<!-- Navbar End Section (Buttons and User Dropdown) -->
|
||||
<div class="navbar-end gap-2">
|
||||
<!-- Create Customer Button (Desktop Only) -->
|
||||
<router-link :to="{ name: 'customerCreate' }" class="btn btn-accent btn-sm hidden lg:inline-flex">
|
||||
Create Customer
|
||||
</router-link>
|
||||
|
||||
<div v-if="employee.id" class="relative ">
|
||||
<button @click="toggleDropdown" class="flex items-center gap-2 ">
|
||||
<div>{{ user.user_name }}</div>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div v-if="isDropdownOpen" class="absolute right-0 mt-2 w-48 bg-gray-800 border border-gray-300 rounded shadow-lg z-10">
|
||||
<router-link :to="{ name: 'employeeProfile', params: { id: employee.id } }" class="block px-4 py-2 text-white hover:bg-gray-700" @click="closeDropdown">
|
||||
User Profile
|
||||
</router-link>
|
||||
<button @click="logout" class="block w-full text-left px-4 py-2 text-white hover:bg-gray-700">
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
<!-- User Dropdown -->
|
||||
<!-- v-if="employee.id" only renders this block AFTER the API call is successful and an employee ID exists. -->
|
||||
<div v-if="employee.id" class="dropdown dropdown-end">
|
||||
<label tabindex="0" class="btn btn-ghost btn-circle avatar">
|
||||
<div class="w-10 rounded-full bg-neutral text-neutral-content flex items-center justify-center">
|
||||
<span class="text-lg font-bold">{{ userInitials }}</span>
|
||||
</div>
|
||||
</label>
|
||||
<ul tabindex="0" class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-52">
|
||||
<li class="p-2 font-semibold">{{ user.user_name }}</li>
|
||||
<div class="divider my-0"></div>
|
||||
<li>
|
||||
<router-link :to="{ name: 'employeeProfile', params: { id: employee.id } }">
|
||||
Profile
|
||||
</router-link>
|
||||
</li>
|
||||
<li><a @click="logout">Logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- This provides the loading indicator while we wait for the API call to finish. -->
|
||||
<div v-else class="px-4">
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-12 ">
|
||||
<div class="grow col-start-4 col-span-6 ">
|
||||
<SearchResults v-if="customers.length" :customers="customers" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import { debounce } from "vue-debounce";
|
||||
import { defineComponent } from "vue";
|
||||
import axios from "axios";
|
||||
import authHeader from "../../services/auth.header";
|
||||
import SearchResults from "./SearchResults.vue";
|
||||
import { defineComponent } from 'vue'
|
||||
import axios from 'axios'
|
||||
import authHeader from '../../services/auth.header'
|
||||
import { useSearchStore } from '../../stores/search' // Adjust path if needed
|
||||
|
||||
// Define the shape of your data for internal type safety
|
||||
interface User {
|
||||
user_name: string;
|
||||
}
|
||||
interface Employee {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: "HeaderAuth",
|
||||
components: {
|
||||
SearchResults,
|
||||
data() {
|
||||
return {
|
||||
// Initialize with empty objects to prevent template errors
|
||||
employee: {} as Employee,
|
||||
user: {} as User,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
searchStore() {
|
||||
return useSearchStore();
|
||||
},
|
||||
userInitials(): string {
|
||||
if (!this.user || !this.user.user_name) return '';
|
||||
const parts = this.user.user_name.split(' ');
|
||||
return parts.length > 1
|
||||
? `${parts[0][0]}${parts[1][0]}`.toUpperCase()
|
||||
: this.user.user_name.substring(0, 2).toUpperCase();
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.userStatus();
|
||||
this.fetchUserData();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
user: {
|
||||
user_id: 0,
|
||||
user_name: '',
|
||||
},
|
||||
company_id: 0,
|
||||
isDropdownOpen: false,
|
||||
company: {
|
||||
creation_date: "",
|
||||
account_prefix: "",
|
||||
company_name: "",
|
||||
company_address: "",
|
||||
company_town: "",
|
||||
company_zip: "",
|
||||
company_state: "",
|
||||
company_phone_number: "",
|
||||
},
|
||||
employee: {
|
||||
id: '',
|
||||
user_id: '',
|
||||
employee_last_name: "",
|
||||
employee_first_name: "",
|
||||
employee_town: "",
|
||||
employee_address: "",
|
||||
employee_apt: "",
|
||||
employee_zip: "",
|
||||
employee_birthday: "",
|
||||
employee_phone_number: "",
|
||||
employee_start_date: "",
|
||||
employee_end_date: "",
|
||||
employee_type: '',
|
||||
employee_state: '',
|
||||
},
|
||||
loaded: false,
|
||||
searchTerm: "",
|
||||
customers: [],
|
||||
type_of_search: 0,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
searchTerm(this: any) {
|
||||
this.performSearch();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getCompany();
|
||||
|
||||
},
|
||||
methods: {
|
||||
performSearch: debounce(async function (this: any) {
|
||||
if (this.searchTerm === "") {
|
||||
this.customers = [];
|
||||
return;
|
||||
}
|
||||
if (this.searchTerm.length < 2) {
|
||||
return;
|
||||
}
|
||||
fetchUserData() {
|
||||
axios.get('/auth/whoami', { headers: authHeader() })
|
||||
.then((response: any) => {
|
||||
console.log("User Data Response from API:", response.data);
|
||||
|
||||
if (this.searchTerm.startsWith("@")) {
|
||||
this.type_of_search = 0
|
||||
} else if (this.searchTerm.startsWith("!")) {
|
||||
this.type_of_search = 1
|
||||
} else if (this.searchTerm.startsWith("#")) {
|
||||
this.type_of_search = 2
|
||||
|
||||
}else if (this.searchTerm.startsWith("$")) {
|
||||
this.type_of_search = 3
|
||||
|
||||
} else {
|
||||
this.type_of_search = 0
|
||||
}
|
||||
|
||||
const searchUrl = this.getSearchUrl();
|
||||
const response = await (await fetch(searchUrl)).json();
|
||||
|
||||
this.customers = response;
|
||||
}, 600),
|
||||
getSearchUrl() {
|
||||
if (this.type_of_search == 0) {
|
||||
const url = import.meta.env.VITE_BASE_URL + "/search/customer";
|
||||
const params = {
|
||||
q: this.searchTerm,
|
||||
};
|
||||
const searchParams = new URLSearchParams(params);
|
||||
return `${url}?${searchParams}`;
|
||||
}
|
||||
else if (this.type_of_search == 1) {
|
||||
const url = import.meta.env.VITE_BASE_URL +"/search/customer";
|
||||
const params = {
|
||||
q: this.searchTerm,
|
||||
};
|
||||
const searchParams = new URLSearchParams(params);
|
||||
return `${url}?${searchParams}`;
|
||||
}
|
||||
else if (this.type_of_search == 2) {
|
||||
const url = import.meta.env.VITE_BASE_URL +"/search/customer";
|
||||
const params = {
|
||||
q: this.searchTerm,
|
||||
};
|
||||
const searchParams = new URLSearchParams(params);
|
||||
return `${url}?${searchParams}`;
|
||||
}
|
||||
else if (this.type_of_search == 3) {
|
||||
const url = import.meta.env.VITE_BASE_URL +"/search/customer";
|
||||
const params = {
|
||||
q: this.searchTerm,
|
||||
};
|
||||
const searchParams = new URLSearchParams(params);
|
||||
return `${url}?${searchParams}`;
|
||||
}
|
||||
else {
|
||||
const url = import.meta.env.VITE_BASE_URL +"/search/customer";
|
||||
const params = {
|
||||
q: this.searchTerm,
|
||||
};
|
||||
const searchParams = new URLSearchParams(params);
|
||||
return `${url}?${searchParams}`;
|
||||
}
|
||||
},
|
||||
|
||||
userStatus() {
|
||||
let path = import.meta.env.VITE_BASE_URL + '/auth/whoami';
|
||||
axios({
|
||||
method: "get",
|
||||
url: path,
|
||||
withCredentials: true,
|
||||
headers: authHeader(),
|
||||
// This check is now more robust. It only checks for what it truly needs.
|
||||
if (response.data && response.data.ok && response.data.employee && response.data.employee.id) {
|
||||
this.user = response.data.user;
|
||||
this.employee = response.data.employee;
|
||||
} else {
|
||||
console.error("API response was successful, but the expected employee data with an ID is missing.");
|
||||
}
|
||||
})
|
||||
.then((response: any) => {
|
||||
if (response.data.ok) {
|
||||
this.user = response.data.user;
|
||||
this.employeeStatus()
|
||||
this.loaded = true;
|
||||
} else {
|
||||
localStorage.removeItem('user');
|
||||
this.$router.push('/login');
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.loaded = true;
|
||||
this.$router.push('/login');
|
||||
});
|
||||
},
|
||||
employeeStatus() {
|
||||
let path = import.meta.env.VITE_BASE_URL + '/employee/userid/' + this.user.user_id;
|
||||
|
||||
axios({
|
||||
method: "get",
|
||||
url: path,
|
||||
withCredentials: true,
|
||||
headers: authHeader(),
|
||||
})
|
||||
.then((response: any) => {
|
||||
this.employee = response.data;
|
||||
this.loaded = true;
|
||||
|
||||
})
|
||||
},
|
||||
// increaseCall() {
|
||||
// let path = import.meta.env.VITE_BASE_URL + '/stats/calls/add';
|
||||
|
||||
// axios({
|
||||
// method: "put",
|
||||
// url: path,
|
||||
// withCredentials: true,
|
||||
// headers: authHeader(),
|
||||
// })
|
||||
// .then((response: any) => {
|
||||
// this.number++;
|
||||
|
||||
// })
|
||||
// },
|
||||
|
||||
getCompany() {
|
||||
let path = import.meta.env.VITE_BASE_URL + '/admin/company/' + import.meta.env.VITE_COMPANY_ID;
|
||||
axios({
|
||||
method: "get",
|
||||
url: path,
|
||||
withCredentials: true,
|
||||
headers: authHeader(),
|
||||
})
|
||||
.then((response: any) => {
|
||||
this.company = response.data;
|
||||
this.company_id = import.meta.env.VITE_COMPANY_ID
|
||||
})
|
||||
},
|
||||
toggleDropdown() {
|
||||
this.isDropdownOpen = !this.isDropdownOpen;
|
||||
},
|
||||
closeDropdown() {
|
||||
this.isDropdownOpen = false;
|
||||
},
|
||||
logout() {
|
||||
localStorage.removeItem('auth_user');
|
||||
localStorage.removeItem('auth_token');
|
||||
this.$router.push('/login');
|
||||
},
|
||||
.catch((error: any) => {
|
||||
console.error("CRITICAL: Failed to fetch user data. The API call itself failed.", error);
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
logout() {
|
||||
console.log("Logging out...");
|
||||
// Your full logout logic here
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user