Add interest deletion and sales pipeline status tracking
- Add delete button with confirmation dialog to InterestDetailsModal - Implement delete-interest API endpoint - Add sales pipeline status section with visual indicators - Update UI states to handle deletion loading states - Add color-coded sales process level selection
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
<v-row class="mb-6">
|
||||
<v-col>
|
||||
<h1 class="text-h4 font-weight-bold">
|
||||
<v-icon class="mr-2" color="primary">mdi-folder</v-icon>
|
||||
File Browser
|
||||
</h1>
|
||||
<p class="text-subtitle-1 text-grey mt-1">
|
||||
|
||||
@@ -52,7 +52,17 @@
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6" class="d-flex justify-end align-center">
|
||||
<v-col cols="12" md="6" class="d-flex justify-end align-center gap-2">
|
||||
<v-btn
|
||||
v-if="hasActiveFilters"
|
||||
variant="text"
|
||||
color="primary"
|
||||
size="small"
|
||||
@click="clearAllFilters"
|
||||
prepend-icon="mdi-filter-off"
|
||||
>
|
||||
Clear Filters
|
||||
</v-btn>
|
||||
<v-chip-group
|
||||
v-model="selectedSalesLevel"
|
||||
selected-class="text-primary"
|
||||
@@ -119,23 +129,26 @@
|
||||
{{ getInitials(item["Full Name"]) }}
|
||||
</span>
|
||||
</v-avatar>
|
||||
<div>
|
||||
<div class="font-weight-medium">{{ item["Full Name"] }}</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="d-flex align-center gap-2">
|
||||
<span class="font-weight-medium">{{ item["Full Name"] }}</span>
|
||||
<v-tooltip v-if="item['Extra Comments']" location="bottom">
|
||||
<template #activator="{ props }">
|
||||
<v-icon
|
||||
v-bind="props"
|
||||
size="small"
|
||||
color="orange"
|
||||
>
|
||||
mdi-comment-text
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>{{ item["Extra Comments"] }}</span>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
<div class="text-caption text-grey-darken-1">{{ item["Email Address"] }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<v-chip
|
||||
v-if="item['Berth Number']"
|
||||
size="small"
|
||||
color="deep-purple"
|
||||
variant="tonal"
|
||||
>
|
||||
{{ item["Berth Number"] }}
|
||||
</v-chip>
|
||||
<span v-else class="text-grey-darken-1">—</span>
|
||||
</td>
|
||||
<td>
|
||||
<InterestSalesBadge
|
||||
:salesProcessLevel="item['Sales Process Level']"
|
||||
@@ -148,27 +161,6 @@
|
||||
/>
|
||||
<span v-else class="text-grey-darken-1">—</span>
|
||||
</td>
|
||||
<td>
|
||||
<BerthInfoSentStatusBadge
|
||||
v-if="item['Berth Info Sent Status']"
|
||||
:berthInfoSentStatus="item['Berth Info Sent Status']"
|
||||
/>
|
||||
<span v-else class="text-grey-darken-1">—</span>
|
||||
</td>
|
||||
<td>
|
||||
<ContractSentStatusBadge
|
||||
v-if="item['Contract Sent Status']"
|
||||
:contractSentStatus="item['Contract Sent Status']"
|
||||
/>
|
||||
<span v-else class="text-grey-darken-1">—</span>
|
||||
</td>
|
||||
<td>
|
||||
<Deposit10PercentStatusBadge
|
||||
v-if="item['Deposit 10% Status']"
|
||||
:deposit10PercentStatus="item['Deposit 10% Status']"
|
||||
/>
|
||||
<span v-else class="text-grey-darken-1">—</span>
|
||||
</td>
|
||||
<td>
|
||||
<ContractStatusBadge
|
||||
v-if="item['Contract Status']"
|
||||
@@ -183,23 +175,6 @@
|
||||
<div class="text-grey-darken-1">{{ getRelativeTime(item["Created At"]) }}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<v-tooltip v-if="item['Extra Comments']" location="bottom">
|
||||
<template #activator="{ props }">
|
||||
<v-chip
|
||||
v-bind="props"
|
||||
size="small"
|
||||
color="orange"
|
||||
variant="tonal"
|
||||
>
|
||||
<v-icon start size="small">mdi-comment-text</v-icon>
|
||||
Note
|
||||
</v-chip>
|
||||
</template>
|
||||
<span>{{ item["Extra Comments"] }}</span>
|
||||
</v-tooltip>
|
||||
<span v-else class="text-grey-darken-1"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
@@ -230,9 +205,6 @@ import InterestSalesBadge from "~/components/InterestSalesBadge.vue";
|
||||
import InterestDetailsModal from "~/components/InterestDetailsModal.vue";
|
||||
import CreateInterestModal from "~/components/CreateInterestModal.vue";
|
||||
import EOIStatusBadge from "~/components/EOIStatusBadge.vue";
|
||||
import BerthInfoSentStatusBadge from "~/components/BerthInfoSentStatusBadge.vue";
|
||||
import ContractSentStatusBadge from "~/components/ContractSentStatusBadge.vue";
|
||||
import Deposit10PercentStatusBadge from "~/components/Deposit10PercentStatusBadge.vue";
|
||||
import ContractStatusBadge from "~/components/ContractStatusBadge.vue";
|
||||
import { useFetch } from "#app";
|
||||
import { ref, computed } from "vue";
|
||||
@@ -285,19 +257,25 @@ const handleInterestCreated = async (interest: Interest) => {
|
||||
};
|
||||
|
||||
const headers = [
|
||||
{ title: "Contact", key: "Full Name", sortable: true, width: "20%" },
|
||||
{ title: "Berth", key: "Berth Number", sortable: true },
|
||||
{ title: "Contact", key: "Full Name", sortable: true, width: "25%" },
|
||||
{ title: "Sales Status", key: "Sales Process Level", sortable: true },
|
||||
{ title: "EOI Status", key: "EOI Status", sortable: true },
|
||||
{ title: "Berth Info", key: "Berth Info Sent Status", sortable: true },
|
||||
{ title: "Contract Sent", key: "Contract Sent Status", sortable: true },
|
||||
{ title: "Deposit 10%", key: "Deposit 10% Status", sortable: true },
|
||||
{ title: "Contract", key: "Contract Status", sortable: true },
|
||||
{ title: "Category", key: "Lead Category", sortable: true },
|
||||
{ title: "Created", key: "Created At", sortable: true },
|
||||
{ title: "", key: "Extra Comments", sortable: false },
|
||||
];
|
||||
|
||||
// Check if any filters are active
|
||||
const hasActiveFilters = computed(() => {
|
||||
return search.value !== '' || selectedSalesLevel.value !== 'all';
|
||||
});
|
||||
|
||||
// Clear all filters
|
||||
const clearAllFilters = () => {
|
||||
search.value = '';
|
||||
selectedSalesLevel.value = 'all';
|
||||
};
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
if (!dateString) return "-";
|
||||
|
||||
@@ -481,12 +459,86 @@ const getRelativeTime = (dateString: string) => {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* Mobile horizontal scrolling */
|
||||
/* Mobile horizontal scrolling with visual indicators */
|
||||
.table-container {
|
||||
position: relative;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* Scroll indicators */
|
||||
.table-container::before,
|
||||
.table-container::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 40px;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.table-container::before {
|
||||
left: 0;
|
||||
background: linear-gradient(to right, white, transparent);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.table-container::after {
|
||||
right: 0;
|
||||
background: linear-gradient(to left, white, transparent);
|
||||
}
|
||||
|
||||
.table-container:not(.scroll-start)::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.table-container:not(.scroll-end)::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Safari-specific fixes */
|
||||
.modern-table :deep(.v-table__wrapper) {
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
.modern-table :deep(.v-data-table__td) {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Column width constraints */
|
||||
.modern-table :deep(th:nth-child(1)),
|
||||
.modern-table :deep(td:nth-child(1)) {
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.modern-table :deep(th:nth-child(2)),
|
||||
.modern-table :deep(td:nth-child(2)) {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.modern-table :deep(th:nth-child(3)),
|
||||
.modern-table :deep(td:nth-child(3)) {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.modern-table :deep(th:nth-child(4)),
|
||||
.modern-table :deep(td:nth-child(4)) {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.modern-table :deep(th:nth-child(5)),
|
||||
.modern-table :deep(td:nth-child(5)) {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.modern-table :deep(th:nth-child(6)),
|
||||
.modern-table :deep(td:nth-child(6)) {
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.table-container {
|
||||
margin: 0 -12px;
|
||||
@@ -494,7 +546,7 @@ const getRelativeTime = (dateString: string) => {
|
||||
}
|
||||
|
||||
.modern-table :deep(.v-table__wrapper) {
|
||||
min-width: 1200px;
|
||||
min-width: 900px;
|
||||
}
|
||||
|
||||
.modern-table :deep(th) {
|
||||
|
||||
Reference in New Issue
Block a user