feat(automations): auto-close TimePicker and show skipped send status

TimePicker closes on select without Ok button; send log shows skipped entries from cooldown/max limits.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-24 22:31:27 +03:30
co-authored by Cursor
parent 7a2254bc2d
commit 0d072ba82d
2 changed files with 65 additions and 2 deletions
@@ -301,13 +301,16 @@
<a-switch :checked="hasSms" @change="(v) => toggleChannel('sms', !!v)" />
<a-time-picker
v-if="hasSms && showChannelHours"
v-model:open="smsPickerOpen"
class="auto-editor__hour-picker"
popup-class-name="auto-editor__hour-popup"
:value="smsHourValue"
format="HH:mm"
:minute-step="1"
:show-second="false"
placeholder="ساعت"
allow-clear
@select="onSmsTimeSelect"
@update:value="setSmsTime"
/>
</div>
@@ -320,13 +323,16 @@
<a-switch :checked="hasInApp" @change="(v) => toggleChannel('in_app', !!v)" />
<a-time-picker
v-if="hasInApp && showChannelHours"
v-model:open="inAppPickerOpen"
class="auto-editor__hour-picker"
popup-class-name="auto-editor__hour-popup"
:value="inAppHourValue"
format="HH:mm"
:minute-step="1"
:show-second="false"
placeholder="ساعت"
allow-clear
@select="onInAppTimeSelect"
@update:value="setInAppTime"
/>
</div>
@@ -519,9 +525,48 @@ function pickerToTime(val: Dayjs | string | null | undefined): { hour: number |
return { hour: parsed.hour(), minute: parsed.minute() }
}
const smsPickerOpen = ref(false)
const inAppPickerOpen = ref(false)
const smsSelectCount = ref(0)
const inAppSelectCount = ref(0)
const smsOpenMinute = ref(0)
const inAppOpenMinute = ref(0)
const smsHourValue = computed(() => timeToPicker(props.form.sms_send_hour, props.form.sms_send_minute))
const inAppHourValue = computed(() => timeToPicker(props.form.in_app_send_hour, props.form.in_app_send_minute))
watch(smsPickerOpen, (open) => {
if (!open) return
smsSelectCount.value = 0
smsOpenMinute.value = props.form.sms_send_minute ?? 0
})
watch(inAppPickerOpen, (open) => {
if (!open) return
inAppSelectCount.value = 0
inAppOpenMinute.value = props.form.in_app_send_minute ?? 0
})
function shouldCloseTimePicker(date: Dayjs, selectCount: number, openMinute: number): boolean {
if (date.minute() !== openMinute) return true
return selectCount >= 2
}
function onSmsTimeSelect(date: Dayjs) {
setSmsTime(date)
smsSelectCount.value++
if (shouldCloseTimePicker(date, smsSelectCount.value, smsOpenMinute.value)) {
smsPickerOpen.value = false
}
}
function onInAppTimeSelect(date: Dayjs) {
setInAppTime(date)
inAppSelectCount.value++
if (shouldCloseTimePicker(date, inAppSelectCount.value, inAppOpenMinute.value)) {
inAppPickerOpen.value = false
}
}
function setSmsTime(val: Dayjs | string | null) {
const time = pickerToTime(val)
props.form.sms_send_hour = time.hour
@@ -747,6 +792,10 @@ defineExpose({
border-radius: 10px;
}
:global(.auto-editor__hour-popup .ant-picker-ranges) {
display: none;
}
.auto-editor__hint {
@apply mt-3 text-xs;
color: var(--admin-text-secondary);
+16 -2
View File
@@ -48,8 +48,22 @@
>
<div class="flex items-center justify-between gap-2">
<span>{{ row.customer_name || '—' }} · {{ row.customer_mobile || '—' }}</span>
<span :class="row.status === 'sent' ? 'text-green-600' : 'text-red-600'">
{{ row.status === 'sent' ? 'موفق' : 'ناموفق' }}
<span
:class="
row.status === 'sent'
? 'text-green-600'
: row.status === 'skipped'
? 'text-amber-600'
: 'text-red-600'
"
>
{{
row.status === 'sent'
? 'موفق'
: row.status === 'skipped'
? 'رد شده'
: 'ناموفق'
}}
</span>
</div>
<div class="text-xs text-gray-500">{{ formatSendDate(row.created_at) }}</div>