build out client page, edit functionality, create functionality, data massager
This commit is contained in:
parent
f510645a31
commit
34f2c110d6
15 changed files with 1571 additions and 1681 deletions
|
|
@ -1,44 +1,89 @@
|
|||
<template>
|
||||
<!-- Client Header -->
|
||||
<div class="client-header" v-if="client.customerName">
|
||||
<div class="client-info">
|
||||
<h2 class="client-name">{{ client.customerName }}</h2>
|
||||
<div class="address-section" v-if="addresses.length > 0">
|
||||
<label class="address-label">Address:</label>
|
||||
<Select
|
||||
v-if="addresses.length > 1"
|
||||
v-model="selectedAddress"
|
||||
:options="addresses"
|
||||
class="address-dropdown"
|
||||
placeholder="Select an address"
|
||||
/>
|
||||
<span v-else class="single-address">{{ addresses[0] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Tabs value="0">
|
||||
<TabList>
|
||||
<Tab value="0">Overview</Tab>
|
||||
<Tab value="1">Projects <span class=tab-info-alert>1</span></Tab>
|
||||
<Tab value="1">Projects <span class="tab-info-alert">1</span></Tab>
|
||||
<Tab value="2">Financials</Tab>
|
||||
<Tab value="3">History</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel value="0">
|
||||
<div id=overview-tab><h3>Overview</h3></div>
|
||||
<Overview
|
||||
:client-data="client"
|
||||
:selected-address="selectedAddress"
|
||||
:is-new="isNew"
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel value="1">
|
||||
<div id=projects-tab><h3>Project Status</h3></div>
|
||||
<div id="projects-tab"><h3>Project Status</h3></div>
|
||||
</TabPanel>
|
||||
<TabPanel value="2">
|
||||
<div id=financials-tab><h3>Accounting</h3></div>
|
||||
<div id="financials-tab"><h3>Accounting</h3></div>
|
||||
</TabPanel>
|
||||
<TabPanel value="3">
|
||||
<div id=history-tab><h3>History</h3></div>
|
||||
<div id="history-tab"><h3>History</h3></div>
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { computed, onMounted, ref, watch } from "vue";
|
||||
import Tabs from "primevue/tabs";
|
||||
import TabList from "primevue/tablist";
|
||||
import Tab from "primevue/tab";
|
||||
import TabPanels from "primevue/tabpanels";
|
||||
import TabPanel from "primevue/tabpanel";
|
||||
import Select from "primevue/select";
|
||||
import Api from "../../api";
|
||||
import ApiWithToast from "../../api-toast";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useLoadingStore } from "../../stores/loading";
|
||||
import { useNotificationStore } from "../../stores/notifications-primevue";
|
||||
import DataUtils from "../../utils";
|
||||
import Overview from "../clientSubPages/Overview.vue";
|
||||
import ProjectStatus from "../clientSubPages/ProjectStatus.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const loadingStore = useLoadingStore();
|
||||
const notificationStore = useNotificationStore();
|
||||
|
||||
const address = route.query.address || null;
|
||||
const clientName = route.query.client || null;
|
||||
const isNew = computed(() => route.query.new === "true" || false);
|
||||
|
||||
const clientNames = ref([]);
|
||||
const client = ref({});
|
||||
const { clientName } = defineProps({
|
||||
clientName: { type: String, required: true },
|
||||
const geocode = ref({});
|
||||
|
||||
const selectedAddress = ref(address);
|
||||
|
||||
const selectedAddressObject = computed(() =>
|
||||
client.value.addresses?.find(
|
||||
(addr) => DataUtils.calculateFullAddress(addr) === selectedAddress.value,
|
||||
),
|
||||
);
|
||||
const addresses = computed(() => {
|
||||
if (client.value && client.value.addresses) {
|
||||
return client.value.addresses.map((addr) => DataUtils.calculateFullAddress(addr));
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const getClientNames = async (type) => {
|
||||
|
|
@ -58,6 +103,30 @@ const getClient = async (name) => {
|
|||
try {
|
||||
const clientData = await Api.getClient(name);
|
||||
client.value = clientData || {};
|
||||
// Set initial selected address if provided in route or use first address
|
||||
if (address && client.value.addresses) {
|
||||
const fullAddresses = client.value.addresses.map((addr) =>
|
||||
DataUtils.calculateFullAddress(addr),
|
||||
);
|
||||
if (fullAddresses.includes(address)) {
|
||||
selectedAddress.value = address;
|
||||
} else if (fullAddresses.length > 0) {
|
||||
selectedAddress.value = fullAddresses[0];
|
||||
}
|
||||
} else if (client.value.addresses && client.value.addresses.length > 0) {
|
||||
selectedAddress.value = DataUtils.calculateFullAddress(client.value.addresses[0]);
|
||||
}
|
||||
if (
|
||||
selectedAddressObject.value?.customLongitude &&
|
||||
selectedAddressObject.value?.customLatitude
|
||||
) {
|
||||
geocode.value = {
|
||||
longitude: selectedAddressObject.value.customLongitude,
|
||||
latitude: selectedAddressObject.value.customLatitude,
|
||||
};
|
||||
} else if (selectedAddress.value) {
|
||||
geocode.value = await Api.getGeocode(selectedAddress.value);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching client data in Client.vue: ", error.message || error);
|
||||
} finally {
|
||||
|
|
@ -66,18 +135,99 @@ const getClient = async (name) => {
|
|||
};
|
||||
|
||||
onMounted(async () => {
|
||||
if (clientName === "new") {
|
||||
// Logic for creating a new client
|
||||
console.log("Creating a new client");
|
||||
} else {
|
||||
// Logic for fetching and displaying existing client data
|
||||
if (clientName) {
|
||||
await getClient(clientName);
|
||||
console.log("Displaying existing client data");
|
||||
}
|
||||
console.debug(
|
||||
"DEBUG: Client.vue mounted with clientName:",
|
||||
clientName,
|
||||
"isNew:",
|
||||
isNew.value,
|
||||
"address:",
|
||||
address,
|
||||
"addresses:",
|
||||
addresses.value,
|
||||
"selectedAddress:",
|
||||
selectedAddress.value,
|
||||
"Does selected address match an address in addresses?:",
|
||||
selectedAddress.value && addresses.value.includes(selectedAddress.value),
|
||||
"geocode:",
|
||||
geocode.value,
|
||||
);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => route.query,
|
||||
async (newQuery, oldQuery) => {
|
||||
const clientName = newQuery.client || null;
|
||||
const isNewClient = newQuery.new === "true" || false;
|
||||
const address = newQuery.address || null;
|
||||
|
||||
// Clear client data if switching to new client mode
|
||||
if (isNewClient) {
|
||||
client.value = {};
|
||||
selectedAddress.value = null;
|
||||
geocode.value = {};
|
||||
console.log("Switched to new client mode - cleared client data");
|
||||
} else if (clientName && clientName !== oldQuery.client) {
|
||||
// Load client data if switching to existing client
|
||||
await getClient(clientName);
|
||||
console.log("Route query changed - displaying existing client data");
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<style lang="css">
|
||||
.client-header {
|
||||
background: var(--surface-card);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
border: 1px solid var(--surface-border);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.client-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.client-name {
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.address-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.address-label {
|
||||
font-weight: 500;
|
||||
color: var(--text-color-secondary);
|
||||
min-width: 70px;
|
||||
}
|
||||
|
||||
.address-dropdown {
|
||||
min-width: 300px;
|
||||
flex: 1;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.single-address {
|
||||
color: var(--text-color);
|
||||
font-size: 0.95rem;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.tab-info-alert {
|
||||
background-color: a95e46;
|
||||
background-color: #a95e46;
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
padding-left: 5px;
|
||||
|
|
@ -85,4 +235,25 @@ onMounted(async () => {
|
|||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.client-info {
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.client-name {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.address-section {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.address-dropdown {
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue