Skip to content

Commit 7ed5909

Browse files
committed
Fix the send schedule
1 parent 52b55dd commit 7ed5909

2 files changed

Lines changed: 136 additions & 117 deletions

File tree

web/pages/bulk-messages/index.vue

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,15 @@
3939
>Excel template</a
4040
>
4141
and upload it here to send your SMS messages to multiple
42-
recipients at once.
42+
recipients at once. You can also configure
43+
<nuxt-link
44+
class="text-decoration-none"
45+
to="/settings/#send-schedules"
46+
>send schedules</nuxt-link
47+
>
48+
on your phone to make sure messages are sent out at specific times
49+
of the day e.g
50+
<span class="text--secondary">Mon - Fri 9am - 5pm.</span>
4351
</p>
4452
<v-alert v-if="errorTitle" text prominent type="warning">
4553
<h6 class="subtitle-1 font-weight-bold">{{ errorTitle }}</h6>

web/pages/settings/index.vue

Lines changed: 127 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,13 @@
401401
</thead>
402402
<tbody>
403403
<tr v-for="schedule in sendSchedules" :key="schedule.id">
404-
<td class="text-left">{{ schedule.name }}</td>
405-
<td>{{ schedule.timezone }}</td>
406-
<td>
404+
<td class="text-left pt-2" style="vertical-align: top">
405+
{{ schedule.name }}
406+
</td>
407+
<td class="pt-2" style="vertical-align: top">
408+
{{ schedule.timezone }}
409+
</td>
410+
<td class="py-2">
407411
<div
408412
v-for="line in scheduleSummary(schedule)"
409413
:key="`${schedule.id}-${line}`"
@@ -413,7 +417,7 @@
413417
<span class="text--secondary">{{ line[1] }}</span>
414418
</div>
415419
</td>
416-
<td class="text-center">
420+
<td class="text-center pt-2" style="vertical-align: top">
417421
<v-btn
418422
:icon="$vuetify.breakpoint.mdAndDown"
419423
color="info"
@@ -904,8 +908,8 @@
904908
>
905909
<v-card>
906910
<v-card-title>
907-
<span v-if="!activeSchedule.id">Add Send Schedule</span>
908-
<span v-else>Edit Send Schedule</span>
911+
<span v-if="!activeSchedule.id">Create Message Send Schedule</span>
912+
<span v-else>Edit Message Send Schedule</span>
909913
</v-card-title>
910914
<v-card-text class="mt-4">
911915
<v-row>
@@ -914,8 +918,9 @@
914918
v-model="activeSchedule.name"
915919
outlined
916920
dense
917-
label="Schedule name"
918-
placeholder="Business Hours"
921+
persistent-placeholder
922+
label="Schedule Name"
923+
placeholder="e.g Business Hours"
919924
:error="errorMessages.has('name')"
920925
:error-messages="errorMessages.get('name')"
921926
/>
@@ -931,107 +936,91 @@
931936
:error-messages="errorMessages.get('timezone')"
932937
/>
933938
</v-col>
934-
<v-col cols="12">
935-
<v-switch
936-
v-model="activeSchedule.is_active"
937-
inset
938-
label="Active"
939-
class="mt-0"
940-
/>
941-
</v-col>
942939
</v-row>
943-
944-
<v-alert
945-
v-if="errorMessages.has('windows')"
946-
dense
947-
outlined
948-
type="error"
949-
class="mb-4"
950-
>
951-
<div v-for="message in errorMessages.get('windows')" :key="message">
952-
{{ message }}
953-
</div>
954-
</v-alert>
955-
956-
<v-card
957-
v-for="day in weekDays"
958-
:key="day.value"
959-
outlined
960-
class="mb-4"
961-
>
962-
<v-card-text class="pb-2">
963-
<div class="d-flex align-center flex-wrap mb-3">
964-
<div class="font-weight-medium mr-4" style="min-width: 110px">
965-
{{ day.label }}
966-
</div>
967-
<v-switch
968-
:input-value="scheduleDayEnabled(day.value)"
969-
inset
970-
dense
971-
hide-details
972-
class="mt-0 pt-0"
973-
@change="scheduleToggleDay(day.value, $event)"
974-
/>
975-
<v-spacer />
976-
<v-btn
977-
small
978-
text
979-
color="primary"
980-
:disabled="!scheduleDayEnabled(day.value)"
981-
@click="scheduleAddWindow(day.value)"
982-
>
983-
<v-icon left small>{{ mdiPlus }}</v-icon>
984-
Add window
985-
</v-btn>
986-
</div>
987-
988-
<div
989-
v-if="scheduleWindowsForDay(day.value).length === 0"
990-
class="text--secondary"
991-
>
992-
Unavailable
993-
</div>
994-
995-
<div
996-
v-for="(window, index) in scheduleWindowsForDay(day.value)"
997-
:key="`${day.value}-${index}`"
998-
class="d-flex align-center flex-wrap mb-2"
999-
>
1000-
<div class="mr-2 mb-2" style="width: 170px; max-width: 100%">
1001-
<v-text-field
1002-
v-model="window.start_time"
1003-
dense
1004-
outlined
1005-
type="time"
1006-
label="Start"
1007-
hide-details="auto"
1008-
/>
1009-
</div>
1010-
<div class="mb-2 mr-2" style="font-size: 18px">–</div>
1011-
<div class="mr-2 mb-2" style="width: 170px; max-width: 100%">
1012-
<v-text-field
1013-
v-model="window.end_time"
1014-
dense
1015-
outlined
1016-
type="time"
1017-
label="End"
1018-
hide-details="auto"
1019-
/>
1020-
</div>
1021-
<div class="mb-2">
1022-
<v-btn
1023-
icon
1024-
color="error"
1025-
@click="scheduleRemoveWindow(day.value, index)"
1026-
>
1027-
<v-icon>{{ mdiDelete }}</v-icon>
1028-
</v-btn>
1029-
</div>
1030-
</div>
940+
<v-card outlined>
941+
<v-card-text>
942+
<table>
943+
<tbody>
944+
<tr v-for="day in weekDays" :key="day.value">
945+
<td style="vertical-align: top" class="pt-2 pr-4">
946+
<v-switch
947+
:input-value="scheduleDayEnabled(day.value)"
948+
inset
949+
dense
950+
:label="day.label"
951+
class="mt-0 pt-0 text--primary"
952+
@change="scheduleToggleDay(day.value, $event)"
953+
/>
954+
</td>
955+
<td class="pt-2">
956+
<div
957+
v-for="(window, index) in scheduleWindowsForDay(
958+
day.value,
959+
)"
960+
:key="`${day.value}-${index}`"
961+
class="d-flex align-center flex-wrap mb-2"
962+
>
963+
<div
964+
class="mr-2 mb-2"
965+
style="width: 150px; max-width: 100%"
966+
>
967+
<v-text-field
968+
v-model="window.start_time"
969+
dense
970+
outlined
971+
:error="scheduleWindowError(day.value)"
972+
type="time"
973+
label="Start"
974+
hide-details="auto"
975+
/>
976+
</div>
977+
<div class="mb-2 mr-2">–</div>
978+
<div
979+
class="mr-2 mb-2"
980+
style="width: 150px; max-width: 100%"
981+
>
982+
<v-text-field
983+
v-model="window.end_time"
984+
dense
985+
outlined
986+
:error="scheduleWindowError(day.value)"
987+
type="time"
988+
label="End"
989+
hide-details="auto"
990+
/>
991+
</div>
992+
<div class="mb-2">
993+
<v-btn
994+
v-if="index == 0"
995+
icon
996+
color="primary"
997+
@click="scheduleAddWindow(day.value)"
998+
>
999+
<v-icon>{{ mdiPlus }}</v-icon>
1000+
</v-btn>
1001+
<v-btn
1002+
icon
1003+
color="error"
1004+
@click="scheduleRemoveWindow(day.value, index)"
1005+
>
1006+
<v-icon>{{ mdiDelete }}</v-icon>
1007+
</v-btn>
1008+
</div>
1009+
</div>
1010+
<div
1011+
v-if="scheduleWindowError(day.value)"
1012+
class="w-full error--text mt-n2 mb-4"
1013+
>
1014+
{{ scheduleWindowError(day.value) }}
1015+
</div>
1016+
</td>
1017+
</tr>
1018+
</tbody>
1019+
</table>
10311020
</v-card-text>
10321021
</v-card>
10331022
</v-card-text>
1034-
<v-card-actions class="mt-n4 pb-4">
1023+
<v-card-actions class="pb-4">
10351024
<loading-button
10361025
v-if="!activeSchedule.id"
10371026
:icon="mdiContentSave"
@@ -1042,7 +1031,6 @@
10421031
</loading-button>
10431032
<loading-button
10441033
v-else
1045-
small
10461034
color="info"
10471035
:loading="savingSchedule"
10481036
@click="saveSchedule"
@@ -1056,16 +1044,18 @@
10561044
<v-btn
10571045
v-if="activeSchedule.id"
10581046
:disabled="savingSchedule"
1059-
small
10601047
color="error"
10611048
text
10621049
@click="confirmDeleteSchedule"
10631050
>
1064-
<v-icon v-if="$vuetify.breakpoint.lgAndUp" small>
1051+
<v-icon v-if="$vuetify.breakpoint.lgAndUp" small left>
10651052
{{ mdiDelete }}
10661053
</v-icon>
10671054
Delete
10681055
</v-btn>
1056+
<v-btn v-else text color="error" @click="showScheduleEdit = false">
1057+
Close
1058+
</v-btn>
10691059
</v-card-actions>
10701060
</v-card>
10711061
</v-dialog>
@@ -1254,6 +1244,7 @@ export default Vue.extend({
12541244
},
12551245
timezones() {
12561246
try {
1247+
// @ts-ignore
12571248
return Intl.supportedValuesOf('timeZone')
12581249
} catch {
12591250
return []
@@ -1425,7 +1416,7 @@ export default Vue.extend({
14251416
this.showDiscordEdit = false
14261417
this.loadDiscordIntegrations()
14271418
})
1428-
.catch((errors) => {
1419+
.catch((errors: ErrorMessages) => {
14291420
this.errorMessages = errors
14301421
})
14311422
.finally(() => {
@@ -1462,7 +1453,7 @@ export default Vue.extend({
14621453
this.showDiscordEdit = false
14631454
this.loadDiscordIntegrations()
14641455
})
1465-
.catch((errors) => {
1456+
.catch((errors: ErrorMessages) => {
14661457
this.errorMessages = errors
14671458
})
14681459
.finally(() => {
@@ -1500,7 +1491,7 @@ export default Vue.extend({
15001491
this.showWebhookEdit = false
15011492
this.loadWebhooks()
15021493
})
1503-
.catch((errors) => {
1494+
.catch((errors: ErrorMessages) => {
15041495
this.errorMessages = errors
15051496
})
15061497
.finally(() => {
@@ -1539,7 +1530,7 @@ export default Vue.extend({
15391530
this.showWebhookEdit = false
15401531
this.loadWebhooks()
15411532
})
1542-
.catch((errors) => {
1533+
.catch((errors: ErrorMessages) => {
15431534
this.errorMessages = errors
15441535
})
15451536
.finally(() => {
@@ -1578,7 +1569,7 @@ export default Vue.extend({
15781569
this.loadingSendSchedules = true
15791570
this.$store
15801571
.dispatch('getSendSchedules')
1581-
.then((sendSchedules) => {
1572+
.then((sendSchedules: EntitiesSendSchedule[]) => {
15821573
this.sendSchedules = sendSchedules
15831574
})
15841575
.finally(() => {
@@ -1590,7 +1581,7 @@ export default Vue.extend({
15901581
this.loadingWebhooks = true
15911582
this.$store
15921583
.dispatch('getWebhooks')
1593-
.then((webhooks) => {
1584+
.then((webhooks: EntitiesWebhook[]) => {
15941585
this.webhooks = webhooks
15951586
})
15961587
.finally(() => {
@@ -1602,7 +1593,7 @@ export default Vue.extend({
16021593
this.loadingDiscordIntegrations = true
16031594
this.$store
16041595
.dispatch('getDiscordIntegrations')
1605-
.then((discords) => {
1596+
.then((discords: EntitiesDiscord[]) => {
16061597
this.discords = discords
16071598
})
16081599
.finally(() => {
@@ -1614,7 +1605,7 @@ export default Vue.extend({
16141605
this.deletingAccount = true
16151606
this.$store
16161607
.dispatch('deleteUserAccount')
1617-
.then((message) => {
1608+
.then((message: string) => {
16181609
this.$store.dispatch('addNotification', {
16191610
message: message ?? 'Your account has been deleted successfully',
16201611
type: 'success',
@@ -1659,6 +1650,10 @@ export default Vue.extend({
16591650
return hours * 60 + minutes
16601651
},
16611652
1653+
getWeekday(index: number): string {
1654+
return this.weekDays.find((x) => x.value == index)?.label ?? ''
1655+
},
1656+
16621657
scheduleSummary(schedule: EntitiesSendSchedule) {
16631658
return this.weekDays
16641659
.map((day) => {
@@ -1758,6 +1753,22 @@ export default Vue.extend({
17581753
})
17591754
},
17601755
1756+
scheduleWindowError(index: number): string | null {
1757+
const messages = this.errorMessages.has('windows')
1758+
? this.errorMessages.get('windows')
1759+
: []
1760+
if (messages.length == 0) {
1761+
return null
1762+
}
1763+
1764+
const message = messages.find((x: string) =>
1765+
x.includes(`Day of week ${index}`),
1766+
)
1767+
return message
1768+
? message.replace(`Day of week ${index}`, this.getWeekday(index))
1769+
: null
1770+
},
1771+
17611772
scheduleRemoveWindow(dayOfWeek: number, index: number) {
17621773
const matches = this.activeSchedule.windows.filter(
17631774
(x) => x.day_of_week === dayOfWeek,

0 commit comments

Comments
 (0)