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:
parent
4d3935e863
commit
2ea72ef24e
|
|
@ -23,7 +23,8 @@
|
||||||
:disabled="
|
:disabled="
|
||||||
isRequestingMoreInfo ||
|
isRequestingMoreInfo ||
|
||||||
isRequestingMoreInformation ||
|
isRequestingMoreInformation ||
|
||||||
isSendingEOI
|
isSendingEOI ||
|
||||||
|
isDeleting
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<v-icon start>mdi-information-outline</v-icon>
|
<v-icon start>mdi-information-outline</v-icon>
|
||||||
|
|
@ -36,7 +37,8 @@
|
||||||
:disabled="
|
:disabled="
|
||||||
isRequestingMoreInfo ||
|
isRequestingMoreInfo ||
|
||||||
isRequestingMoreInformation ||
|
isRequestingMoreInformation ||
|
||||||
isSendingEOI
|
isSendingEOI ||
|
||||||
|
isDeleting
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<v-icon start>mdi-email-outline</v-icon>
|
<v-icon start>mdi-email-outline</v-icon>
|
||||||
|
|
@ -49,19 +51,37 @@
|
||||||
:disabled="
|
:disabled="
|
||||||
isRequestingMoreInfo ||
|
isRequestingMoreInfo ||
|
||||||
isRequestingMoreInformation ||
|
isRequestingMoreInformation ||
|
||||||
isSendingEOI
|
isSendingEOI ||
|
||||||
|
isDeleting
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<v-icon start>mdi-send</v-icon>
|
<v-icon start>mdi-send</v-icon>
|
||||||
EOI to Sales
|
EOI to Sales
|
||||||
</v-btn>
|
</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
|
<v-btn
|
||||||
variant="flat"
|
variant="flat"
|
||||||
color="success"
|
color="success"
|
||||||
size="large"
|
size="large"
|
||||||
@click="saveInterest"
|
@click="saveInterest"
|
||||||
:loading="isSaving"
|
:loading="isSaving"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving || isDeleting"
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
>
|
>
|
||||||
<v-icon start>mdi-content-save</v-icon>
|
<v-icon start>mdi-content-save</v-icon>
|
||||||
|
|
@ -340,11 +360,62 @@
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</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 -->
|
<!-- Berth & Sales Information Section -->
|
||||||
<v-card variant="flat" class="mb-6">
|
<v-card variant="flat" class="mb-6">
|
||||||
<v-card-title class="text-h6 d-flex align-center pb-4">
|
<v-card-title class="text-h6 d-flex align-center pb-4">
|
||||||
<v-icon class="mr-2" color="primary">mdi-anchor</v-icon>
|
<v-icon class="mr-2" color="primary">mdi-anchor</v-icon>
|
||||||
Berth & Sales Information
|
Berth Information
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="pt-2">
|
<v-card-text class="pt-2">
|
||||||
<v-row dense>
|
<v-row dense>
|
||||||
|
|
@ -357,16 +428,6 @@
|
||||||
prepend-inner-icon="mdi-tape-measure"
|
prepend-inner-icon="mdi-tape-measure"
|
||||||
></v-text-field>
|
></v-text-field>
|
||||||
</v-col>
|
</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-col cols="12" md="4">
|
||||||
<v-select
|
<v-select
|
||||||
v-model="interest['Lead Category']"
|
v-model="interest['Lead Category']"
|
||||||
|
|
@ -605,6 +666,7 @@ const isSaving = ref(false);
|
||||||
const isRequestingMoreInfo = ref(false);
|
const isRequestingMoreInfo = ref(false);
|
||||||
const isRequestingMoreInformation = ref(false);
|
const isRequestingMoreInformation = ref(false);
|
||||||
const isSendingEOI = ref(false);
|
const isSendingEOI = ref(false);
|
||||||
|
const isDeleting = ref(false);
|
||||||
|
|
||||||
// Berths related data
|
// Berths related data
|
||||||
const availableBerths = ref<Berth[]>([]);
|
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
|
// Load berths when component mounts
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadAvailableBerths();
|
loadAvailableBerths();
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
<v-row class="mb-6">
|
<v-row class="mb-6">
|
||||||
<v-col>
|
<v-col>
|
||||||
<h1 class="text-h4 font-weight-bold">
|
<h1 class="text-h4 font-weight-bold">
|
||||||
<v-icon class="mr-2" color="primary">mdi-folder</v-icon>
|
|
||||||
File Browser
|
File Browser
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-subtitle-1 text-grey mt-1">
|
<p class="text-subtitle-1 text-grey mt-1">
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,17 @@
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
</v-col>
|
</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-chip-group
|
||||||
v-model="selectedSalesLevel"
|
v-model="selectedSalesLevel"
|
||||||
selected-class="text-primary"
|
selected-class="text-primary"
|
||||||
|
|
@ -119,23 +129,26 @@
|
||||||
{{ getInitials(item["Full Name"]) }}
|
{{ getInitials(item["Full Name"]) }}
|
||||||
</span>
|
</span>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
<div>
|
<div class="flex-grow-1">
|
||||||
<div class="font-weight-medium">{{ item["Full Name"] }}</div>
|
<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 class="text-caption text-grey-darken-1">{{ item["Email Address"] }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</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>
|
<td>
|
||||||
<InterestSalesBadge
|
<InterestSalesBadge
|
||||||
:salesProcessLevel="item['Sales Process Level']"
|
:salesProcessLevel="item['Sales Process Level']"
|
||||||
|
|
@ -148,27 +161,6 @@
|
||||||
/>
|
/>
|
||||||
<span v-else class="text-grey-darken-1">—</span>
|
<span v-else class="text-grey-darken-1">—</span>
|
||||||
</td>
|
</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>
|
<td>
|
||||||
<ContractStatusBadge
|
<ContractStatusBadge
|
||||||
v-if="item['Contract Status']"
|
v-if="item['Contract Status']"
|
||||||
|
|
@ -183,23 +175,6 @@
|
||||||
<div class="text-grey-darken-1">{{ getRelativeTime(item["Created At"]) }}</div>
|
<div class="text-grey-darken-1">{{ getRelativeTime(item["Created At"]) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</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>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -230,9 +205,6 @@ import InterestSalesBadge from "~/components/InterestSalesBadge.vue";
|
||||||
import InterestDetailsModal from "~/components/InterestDetailsModal.vue";
|
import InterestDetailsModal from "~/components/InterestDetailsModal.vue";
|
||||||
import CreateInterestModal from "~/components/CreateInterestModal.vue";
|
import CreateInterestModal from "~/components/CreateInterestModal.vue";
|
||||||
import EOIStatusBadge from "~/components/EOIStatusBadge.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 ContractStatusBadge from "~/components/ContractStatusBadge.vue";
|
||||||
import { useFetch } from "#app";
|
import { useFetch } from "#app";
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
|
|
@ -285,19 +257,25 @@ const handleInterestCreated = async (interest: Interest) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const headers = [
|
const headers = [
|
||||||
{ title: "Contact", key: "Full Name", sortable: true, width: "20%" },
|
{ title: "Contact", key: "Full Name", sortable: true, width: "25%" },
|
||||||
{ title: "Berth", key: "Berth Number", sortable: true },
|
|
||||||
{ title: "Sales Status", key: "Sales Process Level", sortable: true },
|
{ title: "Sales Status", key: "Sales Process Level", sortable: true },
|
||||||
{ title: "EOI Status", key: "EOI Status", 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: "Contract", key: "Contract Status", sortable: true },
|
||||||
{ title: "Category", key: "Lead Category", sortable: true },
|
{ title: "Category", key: "Lead Category", sortable: true },
|
||||||
{ title: "Created", key: "Created At", 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) => {
|
const formatDate = (dateString: string) => {
|
||||||
if (!dateString) return "-";
|
if (!dateString) return "-";
|
||||||
|
|
||||||
|
|
@ -481,12 +459,86 @@ const getRelativeTime = (dateString: string) => {
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mobile horizontal scrolling */
|
/* Mobile horizontal scrolling with visual indicators */
|
||||||
.table-container {
|
.table-container {
|
||||||
|
position: relative;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
-webkit-overflow-scrolling: touch;
|
-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) {
|
@media (max-width: 768px) {
|
||||||
.table-container {
|
.table-container {
|
||||||
margin: 0 -12px;
|
margin: 0 -12px;
|
||||||
|
|
@ -494,7 +546,7 @@ const getRelativeTime = (dateString: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.modern-table :deep(.v-table__wrapper) {
|
.modern-table :deep(.v-table__wrapper) {
|
||||||
min-width: 1200px;
|
min-width: 900px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modern-table :deep(th) {
|
.modern-table :deep(th) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { deleteInterest } from "~/server/utils/nocodb";
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const body = await readBody(event);
|
||||||
|
const { id } = body;
|
||||||
|
const xTag = getHeader(event, "x-tag");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Delete the interest from NocoDB
|
||||||
|
await deleteInterest(id);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Interest deleted successfully",
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 500,
|
||||||
|
statusMessage: error.message || "Failed to delete interest",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -79,7 +79,7 @@ export const updateInterest = async (id: string, data: Partial<Interest>) => {
|
||||||
// Filter the data to only include allowed fields
|
// Filter the data to only include allowed fields
|
||||||
for (const field of allowedFields) {
|
for (const field of allowedFields) {
|
||||||
if (field in data) {
|
if (field in data) {
|
||||||
cleanData[field] = data[field];
|
cleanData[field] = (data as any)[field];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,7 +127,7 @@ export const createInterest = async (data: Partial<Interest>) => {
|
||||||
// Filter the data to only include allowed fields
|
// Filter the data to only include allowed fields
|
||||||
for (const field of allowedFields) {
|
for (const field of allowedFields) {
|
||||||
if (field in data) {
|
if (field in data) {
|
||||||
cleanData[field] = data[field];
|
cleanData[field] = (data as any)[field];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,6 +146,14 @@ export const createInterest = async (data: Partial<Interest>) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const deleteInterest = async (id: string) =>
|
||||||
|
$fetch(`${createTableUrl(Table.Interest)}/${id}`, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"xc-token": getNocoDbConfiguration().token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const triggerWebhook = async (url: string, payload: any) =>
|
export const triggerWebhook = async (url: string, payload: any) =>
|
||||||
$fetch(url, {
|
$fetch(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue