Big update
This commit is contained in:
parent
124b8775fb
commit
b400be3f1a
29 changed files with 31703 additions and 2443 deletions
|
|
@ -1,31 +1,79 @@
|
|||
<template>
|
||||
<div class="client-page">
|
||||
<!-- Client Header -->
|
||||
<TopBar :selectedAddressIdx="selectedAddressIdx" :client="client" :nextVisitDate="nextVisitDate" v-if="client.customerName" @update:selectedAddressIdx="selectedAddressIdx = $event" />
|
||||
<GeneralClientInfo
|
||||
v-if="client.customerName"
|
||||
:client-data="client"
|
||||
/>
|
||||
<AdditionalInfoBar :address="client.addresses[selectedAddressIdx]" v-if="client.customerName" />
|
||||
|
||||
<Tabs value="0">
|
||||
<!-- Address Selector (only shows if multiple addresses) -->
|
||||
<AddressSelector
|
||||
v-if="!isNew && client.addresses && client.addresses.length > 1"
|
||||
:addresses="client.addresses"
|
||||
:selected-address-idx="selectedAddressIdx"
|
||||
:contacts="client.contacts"
|
||||
@update:selected-address-idx="handleAddressChange"
|
||||
/>
|
||||
|
||||
<!-- Main Content Tabs -->
|
||||
<Tabs value="0" class="overview-tabs">
|
||||
<TabList>
|
||||
<Tab value="0">Overview</Tab>
|
||||
<Tab value="1">Projects <span class="tab-info-alert">1</span></Tab>
|
||||
<Tab value="1">Projects</Tab>
|
||||
<Tab value="2">Financials</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<!-- Overview Tab -->
|
||||
<TabPanel value="0">
|
||||
<Overview
|
||||
:client-data="client"
|
||||
:selected-address="selectedAddress"
|
||||
:selected-address="selectedAddressData"
|
||||
:all-contacts="client.contacts"
|
||||
:edit-mode="editMode"
|
||||
:is-new="isNew"
|
||||
:full-address="fullAddress"
|
||||
:client="client"
|
||||
@edit-mode-enabled="enableEditMode"
|
||||
@update:address-contacts="handleAddressContactsUpdate"
|
||||
@update:primary-contact="handlePrimaryContactUpdate"
|
||||
@update:client="handleClientUpdate"
|
||||
/>
|
||||
</TabPanel>
|
||||
|
||||
<!-- Projects Tab -->
|
||||
<TabPanel value="1">
|
||||
<div id="projects-tab"><h3>Project Status</h3></div>
|
||||
<div class="coming-soon-section">
|
||||
<i class="pi pi-wrench"></i>
|
||||
<h3>Projects</h3>
|
||||
<p>Section coming soon</p>
|
||||
</div>
|
||||
</TabPanel>
|
||||
|
||||
<!-- Financials Tab -->
|
||||
<TabPanel value="2">
|
||||
<div id="financials-tab"><h3>Accounting</h3></div>
|
||||
<div class="coming-soon-section">
|
||||
<i class="pi pi-dollar"></i>
|
||||
<h3>Financials</h3>
|
||||
<p>Section coming soon</p>
|
||||
</div>
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
|
||||
<!-- Form Actions (for edit mode or new client) -->
|
||||
<div class="form-actions" v-if="editMode || isNew">
|
||||
<Button
|
||||
@click="handleCancel"
|
||||
label="Cancel"
|
||||
severity="secondary"
|
||||
:disabled="isSubmitting"
|
||||
/>
|
||||
<Button
|
||||
@click="handleSubmit"
|
||||
:label="isNew ? 'Create Client' : 'Save Changes'"
|
||||
:loading="isSubmitting"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
|
|
@ -35,19 +83,23 @@ import TabList from "primevue/tablist";
|
|||
import Tab from "primevue/tab";
|
||||
import TabPanels from "primevue/tabpanels";
|
||||
import TabPanel from "primevue/tabpanel";
|
||||
import Button from "primevue/button";
|
||||
import Api from "../../api";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useLoadingStore } from "../../stores/loading";
|
||||
import { useNotificationStore } from "../../stores/notifications-primevue";
|
||||
import { useCompanyStore } from "../../stores/company";
|
||||
import DataUtils from "../../utils";
|
||||
import Overview from "../clientSubPages/Overview.vue";
|
||||
import ProjectStatus from "../clientSubPages/ProjectStatus.vue";
|
||||
import TopBar from "../clientView/TopBar.vue";
|
||||
import AddressSelector from "../clientView/AddressSelector.vue";
|
||||
import GeneralClientInfo from "../clientView/GeneralClientInfo.vue";
|
||||
import AdditionalInfoBar from "../clientView/AdditionalInfoBar.vue";
|
||||
import Overview from "../clientView/Overview.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const loadingStore = useLoadingStore();
|
||||
const notificationStore = useNotificationStore();
|
||||
const companyStore = useCompanyStore();
|
||||
|
||||
const address = route.query.address || null;
|
||||
const clientName = route.query.client || null;
|
||||
|
|
@ -73,6 +125,10 @@ const addresses = computed(() => {
|
|||
|
||||
const nextVisitDate = ref(null); // Placeholder, update as needed
|
||||
|
||||
// Tab and edit state
|
||||
const editMode = ref(false);
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
const selectedAddressIdx = computed({
|
||||
get: () => addresses.value.indexOf(selectedAddress.value),
|
||||
set: (idx) => {
|
||||
|
|
@ -82,6 +138,22 @@ const selectedAddressIdx = computed({
|
|||
}
|
||||
});
|
||||
|
||||
// Find the address data object that matches the selected address string
|
||||
const selectedAddressData = computed(() => {
|
||||
if (!client.value?.addresses || !selectedAddress.value) {
|
||||
return null;
|
||||
}
|
||||
return client.value.addresses.find(
|
||||
(addr) => DataUtils.calculateFullAddress(addr) === selectedAddress.value
|
||||
);
|
||||
});
|
||||
|
||||
// Calculate full address for display
|
||||
const fullAddress = computed(() => {
|
||||
if (!selectedAddressData.value) return "N/A";
|
||||
return DataUtils.calculateFullAddress(selectedAddressData.value);
|
||||
});
|
||||
|
||||
const getClientNames = async (type) => {
|
||||
loadingStore.setLoading(true);
|
||||
try {
|
||||
|
|
@ -173,6 +245,88 @@ watch(
|
|||
}
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => companyStore.currentCompany,
|
||||
(newCompany) => {
|
||||
console.log("############# Company changed to:", newCompany);
|
||||
let companyIsPresent = false
|
||||
for (company of selectedAddressData.value.companies || []) {
|
||||
console.log("Checking address company:", company);
|
||||
if (company.company === newCompany) {
|
||||
companyIsPresent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!companyIsPresent) {
|
||||
notificationStore.addWarning(
|
||||
`The selected company is not linked to this address.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Handle address change
|
||||
const handleAddressChange = (newIdx) => {
|
||||
selectedAddressIdx.value = newIdx;
|
||||
// TODO: Update route query with new address
|
||||
};
|
||||
|
||||
// Enable edit mode
|
||||
const enableEditMode = () => {
|
||||
editMode.value = true;
|
||||
};
|
||||
|
||||
// Handle cancel edit or new
|
||||
const handleCancel = () => {
|
||||
if (isNew.value) {
|
||||
// For new client, clear the form data
|
||||
client.value = {};
|
||||
} else {
|
||||
editMode.value = false;
|
||||
// Restore original data if editing
|
||||
}
|
||||
};
|
||||
|
||||
// Handle save edit or create new
|
||||
const handleSubmit = async () => {
|
||||
isSubmitting.value = true;
|
||||
try {
|
||||
if (isNew.value) {
|
||||
const createdClient = await Api.createClient(client.value);
|
||||
console.log("Created client:", createdClient);
|
||||
notificationStore.addSuccess("Client created successfully!");
|
||||
// Navigate to the created client
|
||||
window.location.hash = '#/client?client=' + encodeURIComponent(createdClient.name || createdClient.customerName);
|
||||
} else {
|
||||
// TODO: Implement save logic
|
||||
notificationStore.addSuccess("Changes saved successfully!");
|
||||
editMode.value = false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error submitting:", error);
|
||||
notificationStore.addError(isNew.value ? "Failed to create client" : "Failed to save changes");
|
||||
} finally {
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Handle address contacts update
|
||||
const handleAddressContactsUpdate = (contactNames) => {
|
||||
console.log("Address contacts updated:", contactNames);
|
||||
// TODO: Store this for saving
|
||||
};
|
||||
|
||||
// Handle primary contact update
|
||||
const handlePrimaryContactUpdate = (contactName) => {
|
||||
console.log("Primary contact updated:", contactName);
|
||||
// TODO: Store this for saving
|
||||
};
|
||||
|
||||
// Handle client update from forms
|
||||
const handleClientUpdate = (newClientData) => {
|
||||
client.value = { ...client.value, ...newClientData };
|
||||
};
|
||||
</script>
|
||||
<style lang="css">
|
||||
.tab-info-alert {
|
||||
|
|
@ -184,4 +338,63 @@ watch(
|
|||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.overview-tabs {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.coming-soon-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
padding: 4rem 2rem;
|
||||
text-align: center;
|
||||
background: var(--surface-card);
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--surface-border);
|
||||
}
|
||||
|
||||
.coming-soon-section i {
|
||||
font-size: 4rem;
|
||||
color: var(--text-color-secondary);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.coming-soon-section h3 {
|
||||
margin: 0;
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.coming-soon-section p {
|
||||
margin: 0;
|
||||
font-size: 1.1rem;
|
||||
color: var(--text-color-secondary);
|
||||
}
|
||||
|
||||
.client-page {
|
||||
padding-bottom: 5rem; /* Add padding to prevent content from being hidden behind fixed buttons */
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 1rem;
|
||||
padding: 1.5rem;
|
||||
background: var(--surface-card);
|
||||
border-radius: 0;
|
||||
border: 1px solid var(--surface-border);
|
||||
border-bottom: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue