Ask activity reminder channel: in-app notification and/or SMS.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-05 02:04:39 +03:30
co-authored by Cursor
parent 83d25ec1c5
commit 36e47e8af3
8 changed files with 212 additions and 10 deletions
+93
View File
@@ -55,6 +55,8 @@ const assigneeId = ref('');
const isDone = ref(false);
const needsNote = ref(false);
const reminderAt = ref('');
const reminderNotifyApp = ref(true);
const reminderNotifySms = ref(false);
const typeOpen = ref(false);
const assigneeOpen = ref(false);
@@ -136,6 +138,8 @@ function resetForm() {
isDone.value = false;
needsNote.value = false;
reminderAt.value = '';
reminderNotifyApp.value = true;
reminderNotifySms.value = false;
tab.value = 'main';
error.value = '';
}
@@ -177,6 +181,8 @@ async function load() {
reminderAt.value = data.reminderAt
? formatLocalDateTimeInput(new Date(data.reminderAt))
: '';
reminderNotifyApp.value = data.reminderNotifyApp ?? true;
reminderNotifySms.value = data.reminderNotifySms ?? false;
personId.value = data.person?.id ?? '';
dealId.value = data.deal?.id ?? '';
assigneeId.value = data.assignee?.id ?? auth.user?.id ?? '';
@@ -218,6 +224,8 @@ function payload(): CreateActivityRequest {
dueAt: due && !Number.isNaN(due.getTime()) ? due.toISOString() : null,
durationMinutes: durationMinutes.value || null,
reminderAt: reminder && !Number.isNaN(reminder.getTime()) ? reminder.toISOString() : null,
reminderNotifyApp: reminder ? reminderNotifyApp.value : false,
reminderNotifySms: reminder ? reminderNotifySms.value : false,
personId: personId.value || null,
companyId: selectedPerson.value?.company?.id ?? null,
dealId: dealId.value || null,
@@ -232,6 +240,9 @@ function validate() {
if (!assigneeId.value) return 'مسئول فعالیت را انتخاب کنید.';
if (isNew.value && !personId.value) return 'شخص یا مشتری مرتبط را انتخاب کنید.';
if (needsNote.value && !description.value.trim()) return 'توضیح این فعالیت را بنویسید.';
if (reminderAt.value && !reminderNotifyApp.value && !reminderNotifySms.value) {
return 'برای یادآوری، اعلان یا پیامک را انتخاب کنید.';
}
return '';
}
@@ -481,6 +492,29 @@ watch([id, isNew], () => void load(), { immediate: true });
icon="bell"
placeholder="یادآوری تنظیم نشده است"
/>
<div v-if="reminderAt" class="reminder-channels">
<p class="channel-title">چگونه یادآوری شود؟</p>
<label class="channel">
<input v-model="reminderNotifyApp" type="checkbox" />
<span>
<strong>اعلان داخل پنل</strong>
<small>در زنگوله اعلان‌های منتو نشان داده می‌شود</small>
</span>
</label>
<label class="channel">
<input v-model="reminderNotifySms" type="checkbox" />
<span>
<strong>پیامک به مسئول</strong>
<small>به شماره موبایل مسئول فعالیت ارسال می‌شود</small>
</span>
</label>
<p
v-if="reminderAt && !reminderNotifyApp && !reminderNotifySms"
class="channel-warn"
>
حداقل یکی از روش‌های یادآوری را انتخاب کنید.
</p>
</div>
</div>
</div>
@@ -914,6 +948,65 @@ watch([id, isNew], () => void load(), { immediate: true });
padding-inline: 0.15rem;
}
.reminder-channels {
display: grid;
gap: 0.55rem;
margin-top: 0.75rem;
padding-top: 0.75rem;
border-top: 1px dashed #e2e8f0;
}
.channel-title {
margin: 0;
font-size: 0.88rem;
font-weight: 800;
color: #0f172a;
}
.channel {
display: flex;
align-items: flex-start;
gap: 0.55rem;
cursor: pointer;
padding: 0.55rem 0.65rem;
border-radius: 12px;
border: 1px solid #e2e8f0;
background: #f8fafc;
}
.channel:has(input:checked) {
border-color: #99f6e4;
background: #f0fdfa;
}
.channel input {
margin-top: 0.2rem;
accent-color: #0d9488;
}
.channel span {
display: grid;
gap: 0.15rem;
min-width: 0;
}
.channel strong {
font-size: 0.9rem;
color: #0f172a;
}
.channel small {
color: #64748b;
font-size: 0.78rem;
line-height: 1.45;
}
.channel-warn {
margin: 0;
color: #b45309;
font-size: 0.8rem;
}
.note-card {
display: grid;
gap: 0.45rem;