updated calendar to be tabular, moved bid schedule there, started client view refactoring
This commit is contained in:
parent
c5c5ffb0fb
commit
440381265c
18 changed files with 2283 additions and 2159 deletions
29
frontend/src/components/clientView/AdditionalInfoBar.vue
Normal file
29
frontend/src/components/clientView/AdditionalInfoBar.vue
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div class="additional-info-bar">
|
||||
<span>additional address information. coming soon</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
address: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.additional-info-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.25rem 1rem;
|
||||
background: linear-gradient(135deg, #f0f9f0 0%, #e8f5e8 100%);
|
||||
color: #2d5a47;
|
||||
border-bottom: 1px solid #c8e6c9;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
min-height: 30px;
|
||||
}
|
||||
</style>
|
||||
180
frontend/src/components/clientView/TopBar.vue
Normal file
180
frontend/src/components/clientView/TopBar.vue
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
<template>
|
||||
<div class="top-bar">
|
||||
<div class="address-section">
|
||||
<label class="section-label">Address:</label>
|
||||
<Dropdown
|
||||
v-model="selectedAddressIdx"
|
||||
:options="addressOptions"
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
placeholder="Select Address"
|
||||
class="address-dropdown"
|
||||
/>
|
||||
</div>
|
||||
<div class="contact-section">
|
||||
<div class="contact-info">
|
||||
<div class="contact-item">
|
||||
<strong>{{ primaryContact.name }}</strong>
|
||||
</div>
|
||||
<div class="contact-item">
|
||||
<i class="pi pi-phone"></i> {{ primaryContact.phone }}
|
||||
</div>
|
||||
<div class="contact-item">
|
||||
<i class="pi pi-envelope"></i> {{ primaryContact.email }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="client.customerName !== primaryContact.fullName" class="customer-name">
|
||||
<span class="customer-label">Customer:</span> {{ client.customerName }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="visit-section">
|
||||
<i class="pi pi-calendar"></i>
|
||||
<span>Next Visit: {{ nextVisitDate ? formatDate(nextVisitDate) : 'None' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import Dropdown from 'primevue/dropdown'
|
||||
|
||||
const props = defineProps({
|
||||
client: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
nextVisitDate: {
|
||||
type: [String, Date],
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const selectedAddressIdx = defineModel('selectedAddressIdx')
|
||||
|
||||
const addressOptions = computed(() => {
|
||||
return props.client.addresses.map((addr, index) => ({
|
||||
label: addr.fullAddress,
|
||||
value: index
|
||||
}))
|
||||
})
|
||||
|
||||
const primaryContact = computed(() => {
|
||||
const contactName = props.client.addresses[selectedAddressIdx.value]?.customContactName
|
||||
return props.client.contacts.find(contact => contact.name === contactName) || {}
|
||||
})
|
||||
|
||||
const formatDate = (date) => {
|
||||
// Assuming date is a string or Date object, format as needed
|
||||
return new Date(date).toLocaleDateString()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.top-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 1rem;
|
||||
background: linear-gradient(135deg, #0d4f3c 0%, #1a5f4a 100%);
|
||||
color: #fff;
|
||||
border-bottom: 1px solid #2d5a47;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.address-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.section-label {
|
||||
font-weight: 500;
|
||||
color: #adb5bd;
|
||||
white-space: nowrap;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.address-dropdown {
|
||||
flex: 1;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.contact-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contact-info {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.contact-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
font-size: 0.8rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.customer-name {
|
||||
font-size: 0.75rem;
|
||||
color: #adb5bd;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.customer-label {
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.visit-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-weight: 500;
|
||||
font-size: 0.8rem;
|
||||
background: #495057;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.top-bar {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: 0.5rem;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.address-section {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.contact-section {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.contact-info {
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.visit-section {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue