From 02e207860f54544f4d9cd7c49eb858c2ec4683dd Mon Sep 17 00:00:00 2001
From: Regis Freyd <djaiss@users.noreply.github.com>
Date: Thu, 24 Feb 2022 16:31:36 -0500
Subject: [PATCH] feat: indicate time for notification channel
 (monicahq/chandler#47)

---
 .../Notifications/NotificationsController.php |   3 +
 .../NotificationsIndexViewHelper.php          |   1 +
 app/Jobs/SetupAccount.php                     |   1 +
 app/Models/UserNotificationChannel.php        |   1 +
 .../CreateUserNotificationChannel.php         |   5 +-
 .../UserNotificationChannelFactory.php        |   1 +
 .../Notifications/Partials/Emails.vue         | 120 +++++++++++++++++-
 resources/js/Shared/Modules/Reminders.vue     |   3 +-
 .../NotificationsIndexViewHelperTest.php      |   2 +
 .../CreateUserNotificationChannelTest.php     |   1 +
 10 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/app/Http/Controllers/Settings/Notifications/NotificationsController.php b/app/Http/Controllers/Settings/Notifications/NotificationsController.php
index 554d3278bc5..260b1a85853 100644
--- a/app/Http/Controllers/Settings/Notifications/NotificationsController.php
+++ b/app/Http/Controllers/Settings/Notifications/NotificationsController.php
@@ -24,6 +24,8 @@ public function index()
 
     public function store(Request $request)
     {
+        $time = $request->input('hours').':'.$request->input('minutes');
+
         $data = [
             'account_id' => Auth::user()->account_id,
             'author_id' => Auth::user()->id,
@@ -31,6 +33,7 @@ public function store(Request $request)
             'type' =>  UserNotificationChannel::TYPE_EMAIL,
             'content' =>  $request->input('content'),
             'verify_email' => true,
+            'preferred_time' => $time,
         ];
 
         $channel = (new CreateUserNotificationChannel)->execute($data);
diff --git a/app/Http/Controllers/Settings/Notifications/ViewHelpers/NotificationsIndexViewHelper.php b/app/Http/Controllers/Settings/Notifications/ViewHelpers/NotificationsIndexViewHelper.php
index 54f4be36731..112594ca0f6 100644
--- a/app/Http/Controllers/Settings/Notifications/ViewHelpers/NotificationsIndexViewHelper.php
+++ b/app/Http/Controllers/Settings/Notifications/ViewHelpers/NotificationsIndexViewHelper.php
@@ -38,6 +38,7 @@ public static function dtoEmail(UserNotificationChannel $channel, User $user): a
             'content' => $channel->content,
             'active' => $channel->active,
             'verified_at' => $channel->verified_at ? $channel->verified_at->format('Y-m-d H:i:s') : null,
+            'preferred_time' => $channel->preferred_time->format('H:i'),
             'url' => [
                 'store' => route('settings.notifications.store'),
                 'send_test' => route('settings.notifications.test.store', [
diff --git a/app/Jobs/SetupAccount.php b/app/Jobs/SetupAccount.php
index dbf3066b311..624230469a7 100644
--- a/app/Jobs/SetupAccount.php
+++ b/app/Jobs/SetupAccount.php
@@ -90,6 +90,7 @@ private function addNotificationChannel(): void
             'type' => UserNotificationChannel::TYPE_EMAIL,
             'content' => $this->user->email,
             'verify_email' => false,
+            'preferred_time' => '09:00',
         ]);
 
         $channel->verified_at = Carbon::now();
diff --git a/app/Models/UserNotificationChannel.php b/app/Models/UserNotificationChannel.php
index 3e3911c2193..3d6eadc10b6 100644
--- a/app/Models/UserNotificationChannel.php
+++ b/app/Models/UserNotificationChannel.php
@@ -50,6 +50,7 @@ class UserNotificationChannel extends Model
      */
     protected $dates = [
         'verified_at',
+        'preferred_time',
     ];
 
     /**
diff --git a/app/Services/User/NotificationChannels/CreateUserNotificationChannel.php b/app/Services/User/NotificationChannels/CreateUserNotificationChannel.php
index e53173b3781..2d9cb7a8bae 100644
--- a/app/Services/User/NotificationChannels/CreateUserNotificationChannel.php
+++ b/app/Services/User/NotificationChannels/CreateUserNotificationChannel.php
@@ -30,6 +30,7 @@ public function rules(): array
             'type' => 'required|string|max:255',
             'content' => 'required|string|max:65535',
             'verify_email' => 'nullable|boolean',
+            'preferred_time' => 'nullable|date_format:H:i',
         ];
     }
 
@@ -81,8 +82,10 @@ private function create(): void
             'label' => $this->data['label'],
             'type' => $this->data['type'],
             'content' => $this->data['content'],
+            'preferred_time' => $this->data['preferred_time'],
         ]);
 
+        // add a verification link if the channel is email
         if ($this->data['verify_email']) {
             $uuid = Str::uuid();
 
@@ -98,7 +101,7 @@ private function verifyChannel(): void
     {
         if ($this->data['type'] === UserNotificationChannel::TYPE_EMAIL && $this->data['verify_email']) {
             // we need to verify the email address by sending a verification email
-            SendVerificationEmailChannel::dispatch($this->userNotificationChannel);
+            SendVerificationEmailChannel::dispatch($this->userNotificationChannel)->onQueue('high');
         }
     }
 
diff --git a/database/factories/UserNotificationChannelFactory.php b/database/factories/UserNotificationChannelFactory.php
index 734100a52fc..c84f1879f21 100644
--- a/database/factories/UserNotificationChannelFactory.php
+++ b/database/factories/UserNotificationChannelFactory.php
@@ -29,6 +29,7 @@ public function definition()
             'content' => 'admin@admin.com',
             'active' => true,
             'verified_at' => null,
+            'preferred_time' => '09:00:00',
         ];
     }
 }
diff --git a/resources/js/Pages/Settings/Notifications/Partials/Emails.vue b/resources/js/Pages/Settings/Notifications/Partials/Emails.vue
index 0c4eb8768cc..5672209ce58 100644
--- a/resources/js/Pages/Settings/Notifications/Partials/Emails.vue
+++ b/resources/js/Pages/Settings/Notifications/Partials/Emails.vue
@@ -14,6 +14,12 @@
     border-bottom-right-radius: 8px;
   }
 }
+
+select {
+  padding-left: 8px;
+  padding-right: 20px;
+  background-position: right 3px center;
+}
 </style>
 
 <template>
@@ -32,6 +38,7 @@
       <div class="border-b border-gray-200 p-5">
         <errors :errors="form.errors" />
 
+        <!-- content -->
         <text-input
           :ref="'content'"
           v-model="form.content"
@@ -45,16 +52,123 @@
           :maxlength="255"
           @esc-key-pressed="addEmailModalShown = false" />
 
+        <!-- label -->
         <text-input
           v-model="form.label"
           :label="'Give this email address a name'"
           :type="'text'"
           :autofocus="true"
           :input-class="'block w-full'"
+          :div-outer-class="'mb-4'"
           :required="true"
           :autocomplete="false"
           :maxlength="255"
           @esc-key-pressed="addEmailModalShown = false" />
+
+        <!-- preferred time -->
+        <p class="mb-2 block text-sm">At which time should we send the notification, when the reminder occurs?</p>
+        <div class="flex items-center text-sm font-medium text-gray-700">
+          <span class="mr-2">At</span>
+
+          <select
+            v-model="form.hours"
+            class="mr-1 rounded-md border-gray-300 bg-white py-2 px-3 shadow-sm focus:border-indigo-300 focus:outline-none focus:ring focus:ring-indigo-200 focus:ring-opacity-50 sm:text-sm"
+            :required="required">
+            <option value="00">00</option>
+            <option value="01">01</option>
+            <option value="02">02</option>
+            <option value="03">03</option>
+            <option value="04">04</option>
+            <option value="05">05</option>
+            <option value="06">06</option>
+            <option value="07">07</option>
+            <option value="08">08</option>
+            <option value="09">09</option>
+            <option value="10">10</option>
+            <option value="11">11</option>
+            <option value="12">12</option>
+            <option value="13">13</option>
+            <option value="14">14</option>
+            <option value="15">15</option>
+            <option value="16">16</option>
+            <option value="17">17</option>
+            <option value="18">18</option>
+            <option value="19">19</option>
+            <option value="20">20</option>
+            <option value="21">21</option>
+            <option value="23">23</option>
+          </select>
+
+          <span class="mr-2">h:</span>
+
+          <select
+            v-model="form.minutes"
+            class="mr-1 rounded-md border-gray-300 bg-white py-2 px-3 shadow-sm focus:border-indigo-300 focus:outline-none focus:ring focus:ring-indigo-200 focus:ring-opacity-50 sm:text-sm"
+            :required="required">
+            <option value="00">00</option>
+            <option value="01">01</option>
+            <option value="02">02</option>
+            <option value="03">03</option>
+            <option value="04">04</option>
+            <option value="05">05</option>
+            <option value="06">06</option>
+            <option value="07">07</option>
+            <option value="08">08</option>
+            <option value="09">09</option>
+            <option value="10">10</option>
+            <option value="11">11</option>
+            <option value="12">12</option>
+            <option value="13">13</option>
+            <option value="14">14</option>
+            <option value="15">15</option>
+            <option value="16">16</option>
+            <option value="17">17</option>
+            <option value="18">18</option>
+            <option value="19">19</option>
+            <option value="20">20</option>
+            <option value="21">21</option>
+            <option value="22">22</option>
+            <option value="23">23</option>
+            <option value="24">24</option>
+            <option value="25">25</option>
+            <option value="26">26</option>
+            <option value="27">27</option>
+            <option value="28">28</option>
+            <option value="29">29</option>
+            <option value="30">30</option>
+            <option value="31">31</option>
+            <option value="32">32</option>
+            <option value="33">33</option>
+            <option value="34">34</option>
+            <option value="35">35</option>
+            <option value="36">36</option>
+            <option value="37">37</option>
+            <option value="38">38</option>
+            <option value="39">39</option>
+            <option value="40">40</option>
+            <option value="41">41</option>
+            <option value="42">42</option>
+            <option value="43">43</option>
+            <option value="44">44</option>
+            <option value="45">45</option>
+            <option value="46">46</option>
+            <option value="47">47</option>
+            <option value="48">48</option>
+            <option value="49">49</option>
+            <option value="50">50</option>
+            <option value="51">51</option>
+            <option value="52">52</option>
+            <option value="53">53</option>
+            <option value="54">54</option>
+            <option value="55">55</option>
+            <option value="56">56</option>
+            <option value="57">57</option>
+            <option value="57">58</option>
+            <option value="57">59</option>
+          </select>
+
+          <span>m</span>
+        </div>
       </div>
 
       <div class="border-b border-gray-200 p-5">
@@ -97,7 +211,7 @@
             <span class="mb-0 block">{{ email.content }}</span>
             <ul class="bulleted-list mr-2 text-sm text-gray-500">
               <li v-if="email.label" class="mr-1 inline">{{ email.label }}</li>
-              <li class="inline">Sent at 9:00pm</li>
+              <li class="inline">Sent at {{ email.preferred_time }}</li>
             </ul>
           </div>
         </div>
@@ -186,6 +300,8 @@ export default {
       form: {
         content: '',
         label: '',
+        minutes: '',
+        hours: '',
         errors: [],
       },
     };
@@ -193,6 +309,8 @@ export default {
 
   mounted() {
     this.localEmails = this.data.emails;
+    this.form.hours = '09';
+    this.form.minutes = '00';
   },
 
   methods: {
diff --git a/resources/js/Shared/Modules/Reminders.vue b/resources/js/Shared/Modules/Reminders.vue
index 7e043fe884b..7d53ea2d947 100644
--- a/resources/js/Shared/Modules/Reminders.vue
+++ b/resources/js/Shared/Modules/Reminders.vue
@@ -322,7 +322,7 @@ select {
                     v-model="form.month"
                     :data="data.months"
                     :required="true"
-                    :div-outer-class="'mb-5 mr-2'"
+                    :div-outer-class="'mr-2'"
                     :placeholder="'Choose a value'"
                     :dropdown-class="'block w-full'"
                     :label="'Month'" />
@@ -331,7 +331,6 @@ select {
                     v-model="form.day"
                     :data="data.days"
                     :required="true"
-                    :div-outer-class="'mb-5'"
                     :placeholder="'Choose a value'"
                     :dropdown-class="'block w-full'"
                     :label="'Day'" />
diff --git a/tests/Unit/Controllers/Settings/Notifications/ViewHelpers/NotificationsIndexViewHelperTest.php b/tests/Unit/Controllers/Settings/Notifications/ViewHelpers/NotificationsIndexViewHelperTest.php
index 259d93aaf09..75861e77d38 100644
--- a/tests/Unit/Controllers/Settings/Notifications/ViewHelpers/NotificationsIndexViewHelperTest.php
+++ b/tests/Unit/Controllers/Settings/Notifications/ViewHelpers/NotificationsIndexViewHelperTest.php
@@ -50,6 +50,7 @@ public function it_gets_the_data_needed_for_email_notification_channel(): void
             'type' => UserNotificationChannel::TYPE_EMAIL,
             'label' => 'super',
             'verified_at' => '2020-01-01 00:00:00',
+            'preferred_time' => '09:00:00',
         ]);
 
         $array = NotificationsIndexViewHelper::dtoEmail($channel, $user);
@@ -61,6 +62,7 @@ public function it_gets_the_data_needed_for_email_notification_channel(): void
                 'content' => 'admin@admin.com',
                 'active' => $channel->active,
                 'verified_at' => '2020-01-01 00:00:00',
+                'preferred_time' => '09:00',
                 'url' => [
                     'store' => env('APP_URL').'/settings/notifications',
                     'send_test' => env('APP_URL').'/settings/notifications/'.$channel->id.'/test',
diff --git a/tests/Unit/Services/User/NotificationChannels/CreateUserNotificationChannelTest.php b/tests/Unit/Services/User/NotificationChannels/CreateUserNotificationChannelTest.php
index d1d0e94b6a8..96c99a11b14 100644
--- a/tests/Unit/Services/User/NotificationChannels/CreateUserNotificationChannelTest.php
+++ b/tests/Unit/Services/User/NotificationChannels/CreateUserNotificationChannelTest.php
@@ -80,6 +80,7 @@ private function executeService(User $author, Account $account, string $channelT
             'type' => $channelType,
             'content' => 'admin@admin.com',
             'verify_email' => true,
+            'preferred_time' => '09:00',
         ];
 
         $channel = (new CreateUserNotificationChannel)->execute($request);