diff --git a/app/Http/Controllers/AppointmentController.php b/app/Http/Controllers/AppointmentController.php
index 18efe1d..2a8f19b 100755
--- a/app/Http/Controllers/AppointmentController.php
+++ b/app/Http/Controllers/AppointmentController.php
@@ -25,6 +25,7 @@ use App\Application;
use App\Appointment;
use App\Exceptions\InvalidAppointmentException;
use App\Exceptions\InvalidAppointmentStatusException;
+use App\Http\Requests\CancelAppointmentRequest;
use App\Http\Requests\SaveNotesRequest;
use App\Services\AppointmentService;
use App\Services\MeetingNoteService;
@@ -61,7 +62,7 @@ class AppointmentController extends Controller
/**
* @throws AuthorizationException
*/
- public function updateAppointment(Application $application, $status): RedirectResponse
+ public function updateAppointment(Application $application, string $status): RedirectResponse
{
$this->authorize('update', $application->appointment);
@@ -78,10 +79,32 @@ class AppointmentController extends Controller
->back()
->with('error', $ex->getMessage());
}
+ }
+
+ public function deleteAppointment(CancelAppointmentRequest $request, Application $application)
+ {
+ $this->authorize('update', $application->appointment);
+
+ try {
+
+ $this->appointmentService->deleteAppointment($application, $request->reason);
+
+ return redirect()
+ ->back()
+ ->with('success', __('Appointment cancelled.'));
+
+ }
+ catch (\Exception $ex) {
+ return redirect()
+ ->back()
+ ->with('error', $ex->getMessage());
+ }
}
+
+
public function saveNotes(SaveNotesRequest $request, Application $application)
{
try {
diff --git a/app/Http/Requests/CancelAppointmentRequest.php b/app/Http/Requests/CancelAppointmentRequest.php
new file mode 100644
index 0000000..4ba920e
--- /dev/null
+++ b/app/Http/Requests/CancelAppointmentRequest.php
@@ -0,0 +1,30 @@
+ 'string|required'
+ ];
+ }
+}
diff --git a/app/Notifications/AppointmentCancelled.php b/app/Notifications/AppointmentCancelled.php
new file mode 100644
index 0000000..6b7f8e5
--- /dev/null
+++ b/app/Notifications/AppointmentCancelled.php
@@ -0,0 +1,78 @@
+application = $app;
+ $this->reason = $reason;
+ $this->appointmentDate = $appointmentDate;
+ }
+
+ /**
+ * Get the notification's delivery channels.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function via($notifiable)
+ {
+ return ['mail'];
+ }
+
+ /**
+ * Get the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable)
+ {
+ // TODO: Switch to HTML & Blade.
+
+ return (new MailMessage)
+ ->from(config('notification.sender.address'), config('notification.sender.name'))
+ ->subject(config('app.name').' - Interview Cancelled')
+ ->greeting("Hi " . explode(' ', $this->application->user->name, 2)[0] . ",")
+ ->line('The interview that was previously scheduled with you has been cancelled by a staff member.')
+ ->line('Date & time of the old appointment: '.$this->appointmentDate)
+ ->line('Your appointment was cancelled for the following reason: ' . $this->reason)
+ ->line('A staff member may contact you to reschedule within a new timeframe - you may also let us know of a date and time that suits you.')
+ ->line('Your application will be automatically rejected within 7 days if an interview is not scheduled.')
+ ->action('View ongoing applications', url(route('showUserApps')))
+ ->line('Thank you!');
+ }
+
+ /**
+ * Get the array representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return array
+ */
+ public function toArray($notifiable)
+ {
+ return [
+ //
+ ];
+ }
+}
diff --git a/app/Notifications/AppointmentScheduled.php b/app/Notifications/AppointmentScheduled.php
index e77cd5d..62dbd57 100755
--- a/app/Notifications/AppointmentScheduled.php
+++ b/app/Notifications/AppointmentScheduled.php
@@ -64,11 +64,11 @@ class AppointmentScheduled extends Notification implements ShouldQueue
{
return (new MailMessage)
->from(config('notification.sender.address'), config('notification.sender.name'))
- ->subject(config('app.name').' - Interview scheduled')
+ ->subject(config('app.name').' - Interview Scheduled')
->line('A voice interview has been scheduled for you @ '.$this->appointment->appointmentDate.'.')
->line('With the following details: '.$this->appointment->appointmentDescription)
->line('This meeting will take place @ '.$this->appointment->appointmentLocation.'. You will receive an email soon with details on how to join this meeting.')
- ->line('You are expected to show up at least 5 minutes before the scheduled date.')
+ ->line('Please join a public voice channel (or another platform if specified) at around this time.')
->action('Sign in', url(route('login')))
->line('Thank you!');
}
diff --git a/app/Services/AppointmentService.php b/app/Services/AppointmentService.php
index c00c666..e5a6a65 100644
--- a/app/Services/AppointmentService.php
+++ b/app/Services/AppointmentService.php
@@ -8,6 +8,7 @@ use App\Application;
use App\Appointment;
use App\Exceptions\InvalidAppointmentStatusException;
use App\Notifications\ApplicationMoved;
+use App\Notifications\AppointmentCancelled;
use App\Notifications\AppointmentScheduled;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
@@ -25,6 +26,15 @@ class AppointmentService
];
+ /**
+ * Schedules an appointment for the provided application.
+ *
+ * @param Application $application The target application.
+ * @param Carbon $appointmentDate The appointment's date and time.
+ * @param string $appointmentDescription The appointment description.
+ * @param string $appointmentLocation The appointment location.
+ * @return bool Whether the appointment was scheduled.
+ */
public function createAppointment(Application $application, Carbon $appointmentDate, $appointmentDescription, $appointmentLocation)
{
$appointment = Appointment::create([
@@ -46,6 +56,32 @@ class AppointmentService
return true;
}
+
+ /**
+ * Cancels an appointment for the provided application.
+ *
+ * @param Application $application The target application.
+ * @param string $reason The reason for cancelling the appointment.
+ * @throws \Exception Thrown when there's no appointment to cancel
+ */
+ public function deleteAppointment(Application $application, string $reason): bool
+ {
+ if (!empty($application->appointment))
+ {
+ $application->user->notify(new AppointmentCancelled($application, Carbon::parse($application->appointment->appointmentDate), $reason));
+ $application->appointment->delete();
+
+ $application->setStatus('STAGE_INTERVIEW');
+
+ Log::info('User '.Auth::user()->name.' cancelled an appointment with '.$application->user->name.' for application ID'.$application->id);
+
+ return true;
+ }
+
+ throw new \Exception("This application doesn't have an appointment!");
+
+ }
+
/**
* Updates the appointment with the new $status.
* It also sets the application's status to peer approval.
diff --git a/resources/views/dashboard/user/viewapp.blade.php b/resources/views/dashboard/user/viewapp.blade.php
index a38fabf..981a06d 100755
--- a/resources/views/dashboard/user/viewapp.blade.php
+++ b/resources/views/dashboard/user/viewapp.blade.php
@@ -67,12 +67,37 @@
@method('PATCH')
-
-
+
+
+
+
+
{{ __('Caution') }}
+
+
{{__('Are you sure you want to cancel this appointment? The user will be notified of this via email, and you will be able to reschedule.')}}
+
{{ __('Before you can cancel this appointment, you\'ll need to provide a reason in writing. ') }}