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:
2025-06-04 19:51:51 +02:00
parent 4d3935e863
commit 2ea72ef24e
5 changed files with 280 additions and 81 deletions

View File

@@ -23,7 +23,8 @@
:disabled="
isRequestingMoreInfo ||
isRequestingMoreInformation ||
isSendingEOI
isSendingEOI ||
isDeleting
"
>
<v-icon start>mdi-information-outline</v-icon>
@@ -36,7 +37,8 @@
:disabled="
isRequestingMoreInfo ||
isRequestingMoreInformation ||
isSendingEOI
isSendingEOI ||
isDeleting
"
>
<v-icon start>mdi-email-outline</v-icon>
@@ -49,19 +51,37 @@
:disabled="
isRequestingMoreInfo ||
isRequestingMoreInformation ||
isSendingEOI
isSendingEOI ||
isDeleting
"
>
<v-icon start>mdi-send</v-icon>
EOI to Sales
</v-btn>
<v-btn
@click="confirmDelete"
variant="text"
color="error"
:loading="isDeleting"
:disabled="
isRequestingMoreInfo ||
isRequestingMoreInformation ||
isSendingEOI ||
isSaving ||
isDeleting
"
class="ml-4"
>
<v-icon start>mdi-delete</v-icon>
Delete
</v-btn>
<v-btn
variant="flat"
color="success"
size="large"
@click="saveInterest"
:loading="isSaving"
:disabled="isSaving"
:disabled="isSaving || isDeleting"
class="ml-2"
>
<v-icon start>mdi-content-save</v-icon>
@@ -340,11 +360,62 @@
</v-row>
</v-card-text>
</v-card>
<!-- Sales Pipeline Status Section -->
<v-card variant="flat" class="mb-6">
<v-card-title class="text-h6 d-flex align-center pb-4">
<v-icon class="mr-2" color="primary">mdi-chart-timeline-variant</v-icon>
Sales Pipeline Status
</v-card-title>
<v-card-text class="pt-2">
<v-row dense>
<v-col cols="12">
<v-select
v-model="interest['Sales Process Level']"
label="Current Sales Level"
variant="outlined"
density="comfortable"
:items="InterestSalesProcessLevelFlow"
prepend-inner-icon="mdi-chart-line"
>
<template v-slot:selection="{ item }">
<v-chip
:color="getSalesLevelColor(item.value)"
size="small"
>
{{ item.value }}
</v-chip>
</template>
<template v-slot:item="{ item, props }">
<v-list-item v-bind="props">
<template v-slot:prepend>
<v-icon :color="getSalesLevelColor(item.value)">
mdi-circle
</v-icon>
</template>
</v-list-item>
</template>
</v-select>
<div class="mt-4">
<v-progress-linear
:model-value="(currentStep + 1) / InterestSalesProcessLevelFlow.length * 100"
height="10"
rounded
:color="getSalesLevelColor(interest['Sales Process Level'])"
/>
<div class="text-caption text-center mt-2">
Progress: {{ currentStep + 1 }} of {{ InterestSalesProcessLevelFlow.length }} stages
</div>
</div>
</v-col>
</v-row>
</v-card-text>
</v-card>
<!-- Berth & Sales Information Section -->
<v-card variant="flat" class="mb-6">
<v-card-title class="text-h6 d-flex align-center pb-4">
<v-icon class="mr-2" color="primary">mdi-anchor</v-icon>
Berth & Sales Information
Berth Information
</v-card-title>
<v-card-text class="pt-2">
<v-row dense>
@@ -357,16 +428,6 @@
prepend-inner-icon="mdi-tape-measure"
></v-text-field>
</v-col>
<v-col cols="12" md="4">
<v-select
v-model="interest['Sales Process Level']"
label="Sales Process Level"
variant="outlined"
density="comfortable"
:items="InterestSalesProcessLevelFlow"
prepend-inner-icon="mdi-chart-line"
></v-select>
</v-col>
<v-col cols="12" md="4">
<v-select
v-model="interest['Lead Category']"
@@ -605,6 +666,7 @@ const isSaving = ref(false);
const isRequestingMoreInfo = ref(false);
const isRequestingMoreInformation = ref(false);
const isSendingEOI = ref(false);
const isDeleting = ref(false);
// Berths related data
const availableBerths = ref<Berth[]>([]);
@@ -962,6 +1024,62 @@ const formatDate = (dateString: string | null | undefined) => {
}
};
// Get color for sales level
const getSalesLevelColor = (level: string) => {
switch (level?.toLowerCase()) {
case "initial inquiry":
return "grey";
case "qualified interest":
return "blue";
case "eoi sent":
return "orange";
case "loi sent":
return "purple";
case "reservation agreement sent":
return "green";
case "reserved":
return "success";
default:
return "grey";
}
};
// Confirm delete
const confirmDelete = () => {
if (!interest.value) return;
if (confirm(`Are you sure you want to delete the interest for ${interest.value['Full Name']}? This action cannot be undone.`)) {
deleteInterest();
}
};
// Delete interest
const deleteInterest = async () => {
if (!interest.value) return;
isDeleting.value = true;
try {
await $fetch("/api/delete-interest", {
method: "POST",
headers: {
"x-tag": user.value?.email ? "094ut234" : "pjnvü1230",
},
body: {
id: interest.value.Id.toString(),
},
});
toast.success("Interest deleted successfully!");
closeModal();
emit("save", interest.value); // Trigger refresh
} catch (error) {
console.error("Failed to delete interest:", error);
toast.error("Failed to delete interest. Please try again.");
} finally {
isDeleting.value = false;
}
};
// Load berths when component mounts
onMounted(() => {
loadAvailableBerths();