feat: send one SMS from a person or lead and keep the dashboard inside the phone frame

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-13 21:05:17 +03:30
co-authored by Cursor
parent 13ee70764b
commit 42f0573a5f
13 changed files with 733 additions and 113 deletions
+38 -7
View File
@@ -19,6 +19,7 @@ import {
UiTextarea,
} from '@/components/ui';
import RelatedTasksPanel from '@/components/routines/RelatedTasksPanel.vue';
import SmsComposeModal from '@/components/SmsComposeModal.vue';
import type {
ActivityDto,
ConvertLeadResult,
@@ -57,6 +58,7 @@ const followUpAt = ref('');
const followUpBody = ref('');
const editing = ref(false);
const moreOpen = ref(false);
const smsOpen = ref(false);
const copied = ref(false);
const narrow = ref(typeof window !== 'undefined' && window.matchMedia('(max-width: 900px)').matches);
let narrowMq: MediaQueryList | null = null;
@@ -371,6 +373,15 @@ onBeforeUnmount(() => narrowMq?.removeEventListener('change', syncNarrow));
:back-to="{ name: 'leads' }"
>
<template #actions>
<UiButton
v-if="lead && !editing"
variant="secondary"
size="sm"
:disabled="busy || !lead.mobile"
@click="smsOpen = true"
>
پیامک
</UiButton>
<UiButton
v-if="lead && !editing"
variant="secondary"
@@ -444,10 +455,17 @@ onBeforeUnmount(() => narrowMq?.removeEventListener('change', syncNarrow));
<UiIcon name="phone" :size="16" />
تماس
</a>
<button class="m-btn" type="button" @click="smsOpen = true">
<UiIcon name="chat" :size="16" />
پیامک
</button>
<button class="m-btn" type="button" @click="startEdit">
<UiIcon name="pencil" :size="16" />
ویرایش
</button>
<button class="m-btn icon" type="button" aria-label="بیشتر" @click="moreOpen = true">
<UiIcon name="dots" :size="18" />
</button>
<button
v-if="!lead.convertedPersonId"
class="m-btn solid"
@@ -458,9 +476,6 @@ onBeforeUnmount(() => narrowMq?.removeEventListener('change', syncNarrow));
<UiIcon name="user-plus" :size="16" />
تبدیل به مشتری
</button>
<button class="m-btn icon" type="button" aria-label="بیشتر" @click="moreOpen = true">
<UiIcon name="dots" :size="18" />
</button>
</div>
</article>
@@ -704,6 +719,11 @@ onBeforeUnmount(() => narrowMq?.removeEventListener('change', syncNarrow));
<aside class="side">
<button class="sheet-close" type="button" @click="moreOpen = false">بستن</button>
<UiCard title="پیامک">
<UiButton size="sm" :disabled="!lead.mobile" @click="smsOpen = true; moreOpen = false">
ارسال پیامک
</UiButton>
</UiCard>
<UiCard title="تغییر وضعیت">
<UiField label="وضعیت">
<UiSelect v-model="stageId">
@@ -764,6 +784,16 @@ onBeforeUnmount(() => narrowMq?.removeEventListener('change', syncNarrow));
</UiCard>
</aside>
</div>
<SmsComposeModal
:open="smsOpen"
title="ارسال پیامک"
:endpoint="`/leads/${lead.id}/sms`"
:name="lead.contactName || lead.title"
:phone="lead.mobile || lead.phone || ''"
:record-title="lead.title"
:company="lead.contactName ? lead.title : ''"
@close="smsOpen = false"
/>
</template>
</section>
</template>
@@ -1082,14 +1112,15 @@ onBeforeUnmount(() => narrowMq?.removeEventListener('change', syncNarrow));
color: #94a3b8;
}
.m-actions {
.m-actions,
.m-actions.converted {
display: grid;
grid-template-columns: auto auto minmax(0, 1fr) 36px;
grid-template-columns: repeat(3, minmax(0, 1fr)) 36px;
gap: 0.35rem;
}
.m-actions.converted {
grid-template-columns: 1fr 1fr auto;
.m-actions .solid {
grid-column: 1 / -1;
}
.m-btn {