diff --git a/components/EOISection.vue b/components/EOISection.vue
index a163a38..aa5730d 100644
--- a/components/EOISection.vue
+++ b/components/EOISection.vue
@@ -91,7 +91,10 @@
mdi-account
- Client Signature Link
+
+ Client Signature Link
+ mdi-check-circle
+
{{ interest['Full Name'] }}
@@ -114,7 +117,10 @@
mdi-account-check
- CC Signature Link
+
+ CC Signature Link
+ mdi-check-circle
+
Oscar Faragher
@@ -137,7 +143,10 @@
mdi-account-tie
- Developer Signature Link
+
+ Developer Signature Link
+ mdi-check-circle
+
David Mizrahi
@@ -313,6 +322,18 @@ const selectedFile = ref(null);
const showDeleteConfirmDialog = ref(false);
const isDeleting = ref(false);
+// Signature status tracking
+const signatureStatus = ref({
+ documentStatus: '',
+ clientSigned: false,
+ allSigned: false,
+ signedRecipients: [] as any[],
+ unsignedRecipients: [] as any[]
+});
+
+// Polling interval for signature status
+let statusPollingInterval: NodeJS.Timeout | null = null;
+
const hasEOI = computed(() => {
return !!(props.interest['Signature Link Client'] ||
props.interest['Signature Link CC'] ||
@@ -520,4 +541,102 @@ const deleteEOI = async () => {
isDeleting.value = false;
}
};
+
+// Check signature status from Documenso
+const checkSignatureStatus = async () => {
+ if (!hasEOI.value || isEOISigned.value) return;
+
+ try {
+ const response = await $fetch<{
+ success: boolean;
+ documentStatus: string;
+ clientSigned: boolean;
+ allSigned: boolean;
+ signedRecipients: any[];
+ unsignedRecipients: any[];
+ }>('/api/eoi/check-signature-status', {
+ headers: {
+ 'x-tag': '094ut234'
+ },
+ query: {
+ interestId: props.interest.Id.toString()
+ }
+ });
+
+ if (response.success) {
+ signatureStatus.value = {
+ documentStatus: response.documentStatus,
+ clientSigned: response.clientSigned,
+ allSigned: response.allSigned,
+ signedRecipients: response.signedRecipients,
+ unsignedRecipients: response.unsignedRecipients
+ };
+
+ // If all signed, update the EOI status
+ if (response.allSigned && props.interest['EOI Status'] !== 'Signed') {
+ try {
+ await $fetch('/api/update-interest', {
+ method: 'POST',
+ headers: {
+ 'x-tag': '094ut234'
+ },
+ body: {
+ id: props.interest.Id.toString(),
+ data: {
+ 'EOI Status': 'Signed',
+ 'Sales Process Level': 'Made Reservation'
+ }
+ }
+ });
+ emit('update'); // Refresh parent data
+ stopSignaturePolling(); // Stop polling once signed
+ } catch (updateError) {
+ console.error('Failed to update EOI status:', updateError);
+ }
+ }
+ }
+ } catch (error) {
+ console.error('Failed to check signature status:', error);
+ }
+};
+
+// Check if a specific email has signed
+const isSignedByEmail = (email: string) => {
+ return signatureStatus.value.signedRecipients.some(
+ recipient => recipient.email === email
+ );
+};
+
+// Start polling for signature status
+const startSignaturePolling = () => {
+ // Initial check
+ checkSignatureStatus();
+
+ // Poll every 30 seconds
+ statusPollingInterval = setInterval(() => {
+ checkSignatureStatus();
+ }, 30000);
+};
+
+// Stop polling
+const stopSignaturePolling = () => {
+ if (statusPollingInterval) {
+ clearInterval(statusPollingInterval);
+ statusPollingInterval = null;
+ }
+};
+
+// Watch for changes in EOI status
+watch(() => hasEOI.value, (newValue) => {
+ if (newValue && !isEOISigned.value) {
+ startSignaturePolling();
+ } else {
+ stopSignaturePolling();
+ }
+}, { immediate: true });
+
+// Cleanup on unmount
+onUnmounted(() => {
+ stopSignaturePolling();
+});
diff --git a/server/api/email/fetch-thread.ts b/server/api/email/fetch-thread.ts
index af97bda..d2ddcfe 100644
--- a/server/api/email/fetch-thread.ts
+++ b/server/api/email/fetch-thread.ts
@@ -13,6 +13,7 @@ interface EmailMessage {
timestamp: string;
direction: 'sent' | 'received';
threadId?: string;
+ attachments?: any[];
}
export default defineEventHandler(async (event) => {
@@ -304,6 +305,15 @@ async function fetchImapEmails(
return;
}
+ // Extract attachments
+ const attachments = parsed.attachments ? parsed.attachments.map((att: any) => ({
+ filename: att.filename || 'attachment',
+ name: att.filename || 'attachment',
+ size: att.size || 0,
+ type: att.contentType || 'application/octet-stream',
+ cid: att.cid || undefined
+ })) : [];
+
const email: EmailMessage = {
id: parsed.messageId || `${Date.now()}-${seqno}`,
from: fromEmail,
@@ -312,7 +322,8 @@ async function fetchImapEmails(
body: parsed.text || '',
html: parsed.html || undefined,
timestamp: parsed.date?.toISOString() || new Date().toISOString(),
- direction: fromEmail.toLowerCase().includes(userEmail.toLowerCase()) ? 'sent' : 'received'
+ direction: fromEmail.toLowerCase().includes(userEmail.toLowerCase()) ? 'sent' : 'received',
+ attachments: attachments
};
if (parsed.headers.has('in-reply-to')) {
diff --git a/server/api/email/send.ts b/server/api/email/send.ts
index 6957d87..9a5ee89 100644
--- a/server/api/email/send.ts
+++ b/server/api/email/send.ts
@@ -181,7 +181,8 @@ export default defineEventHandler(async (event) => {
html: htmlBody,
timestamp: new Date().toISOString(),
direction: 'sent',
- interestId: interestId
+ interestId: interestId,
+ attachments: attachments // Include attachment info
};
const objectName = `interest-${interestId}/${Date.now()}-sent.json`;