カレンダー形式でスケジュールが表示できるようになったので、今回はスケジュールの予約機能の実装方法を紹介します。
ユーザースケジュール予約機能作成
①スケジュール詳細表示用のモーダルを作成する。
ここではBreezeで導入したモーダルコンポーネントを利用してモーダルウインドウを作成します。
{{-- 予約モーダル --}}
<button type="submit" id="user-reserve-modal-button" class='hidden'
x-data=""
x-on:click.prevent="$dispatch('open-modal', 'user-reserve-modal')"
>予約
</button>
<x-modal name="user-reserve-modal">
<form method="post" action="{{ route('reserve.add') }}" class="p-6">
@csrf
@method('post')
<h2 class="text-lg font-medium text-gray-900">
スケジュール予約
</h2>
<p class="mt-1 text-sm text-gray-600">
</p>
<div class="mt-6">
<input type="hidden" id="schedule_id" value="" name="schedule_id">
<input type="hidden" id="user_id" value="{{ Auth::user()->id }}" name="user_id">
<p>タイトル:<span class="" id="modal-data-title"></span></p>
<p>開始日時:<span class="" id="modal-data-start"></span></p>
<p>終了日時:<span class="" id="modal-data-end"></span></p>
<p>スタッフ:<span class="" id="modal-data-staff"></span></p>
<p>上限人数:<span class="" id="modal-data-limit"></span></p>
</div>
<div class="mt-6 flex justify-end">
<x-secondary-button x-on:click="$dispatch('close')">
{{ __('Cancel') }}
</x-secondary-button>
<x-primary-button class="ml-3">
予約
</x-primary-button>
</div>
</form>
</x-modal>②Viewファイルをインクルードする。
※下記、L25を参照
+ @include('reserve-modal');
</main>③カレンダーのスケジュールをクリックしたときにスケジュール詳細モーダルを表示する処理を実装する。
※下記、参照箇所
// イベントクリック時の処理
eventClick: function(info) {
//alert('Event: ' + info.event.title);
//console.log(info.event.extendedProps);
//モーダルへのデータセット
document.getElementById("schedule_id").value = info.event.id;
document.getElementById("modal-data-title").innerHTML = info.event.title;
document.getElementById("modal-data-start").innerHTML = info.event.start;
document.getElementById("modal-data-end").innerHTML = info.event.end;
document.getElementById("modal-data-staff").innerHTML = info.event.extendedProps.staff;
document.getElementById("modal-data-limit").innerHTML = info.event.extendedProps.limit;
//モーダルを表示
let modal_button = document.getElementById("user-reserve-modal-button");
modal_button.click();
},④予約登録用のルーティングを追加する。
※下記、L35を参照
Route::middleware('auth')->group(function () {
// プロフィールページ
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
+ Route::get('/calendar', [EventController::class, 'index'])->name('event.index');
//中略
});⑤EventControllerに予約登録の処理を実装する。
※下記、L18~L60を参照
class EventController extends Controller
{
//中略
+ public function addReserve(Request $request)
+ {
+ // バリデーション
+ $request->validate([
+ 'schedule_id' => 'required|integer|exists:schedules,id',
+ 'user_id' => 'required|integer|exists:users,id'
+ ]);
+
+ try {
+ // スケジュールデータを取得
+ $schedule = Schedule::find($request->input('schedule_id'));
+
+ // スケジュールに紐付く予約情報を取得
+ $reserves = $schedule->reserves;
+
+ // 予約数上限を取得、ない場合は99とする
+ $limit = $schedule->reservation_limit ?? 99;
+
+ // すでに予約済みかどうか確認
+ $reserved_count = $reserves->where('user_id', $request->input('user_id'))->count();
+ if ($reserved_count > 0) {
+ // すでに予約済みなら終了
+ return redirect()->route('event.index')->with('message', 'already reserve!');
+ }
+
+ // 現在の予約数が予約上限以下であれば予約を行なう
+ if ($limit > $reserves->count()) {
+ $reserve = new Reserve();
+ $reserve->schedule_id = $request->input('schedule_id');
+ $reserve->user_id = $request->input('user_id');
+ $reserve->save();
+
+ // 予約完了メールの送信
+ $this->sendReserveMail($reserve);
+
+ return redirect()->route('event.index')->with('message', 'add reserve!');
+ } else {
+ return redirect()->route('event.index')->with('message', 'reserve limited!');
+ }
+ } catch (Exception $e) {
+ Log::error($e->getMessage());
+ }
+ }
}⑥予約登録時にユーザーに予約完了メールを送信するために、メール送信処理を実装する。
送信メールのクラスを作成します。
$sail artisan make:mail UserReserved下記のように表示されたら成功。
INFO Mailable [app/Mail/UserReserved.php] created successfully. 生成されたファイルを下記のように変更します。
namespace App\Mail;
+ use App\Models\Reserve;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
+ use Illuminate\Mail\Mailables\Address;
use Illuminate\Queue\SerializesModels;
class UserReserved extends Mailable
{
- use Queueable, SerializesModels;
+ use Queueable;
+ use SerializesModels;
+
+ public $reserve;
/**
* Create a new message instance.
+ *
+ * @return void
*/
- public function __construct()
+ public function __construct(Reserve $reserve)
{
- //
+ $this->reserve = $reserve;
}
/**
* Get the message envelope.
+ *
+ * @return \Illuminate\Mail\Mailables\Envelope
*/
- public function envelope(): Envelope
+ public function envelope()
{
return new Envelope(
- subject: 'User Reserved',
+ from: new Address('no-reply@example.com', '簡易予約アプリ'),
+ subject: 'スケジュール予約完了のお知らせ',
);
}
/**
* Get the message content definition.
+ *
+ * @return \Illuminate\Mail\Mailables\Content
*/
- public function content(): Content
+ public function content()
{
return new Content(
- view: 'view.name',
+ view: 'emails.reserved-user',
);
}
/**
* Get the attachments for the message.
*
- * @return array<int, \Illuminate\Mail\Mailables\Attachment>
+ * @return array
*/
- public function attachments(): array
+ public function attachments()
{
return [];
}
- }
+ }⑦送信メールのテンプレートファイルを作成する。
resources/views/emails/reserved-user.blade.phpを新規作成します。
<!DOCTYPE html>
<html lang="ja">
<head>
</head>
<body>
<h1>
スケジュールを予約しました。
</h1>
<p>
{{ $reserve->user->name }} 様
</p>
<p>
スケジュールの予約が完了しました。
</p>
<p>
予約番号:{{ $reserve->id }} <br>
タイトル:{{ $reserve->schedule->title }} <br>
日時:{{ $reserve->schedule->from_date }} ~ {{ $reserve->schedule->due_date }} <br>
スタッフ:{{ $reserve->schedule->staff_name }}
</p>
</body>
</html>⑧メール送信処理をEventControllerに実装し、addReserve()から呼び出すようにする。
※下記、L23~L66を参照
class EventController extends Controller
{
// 中略
public function getEvents()
{
// 中略
}
+ public function addReserve(Request $request)
+ {
+ // バリデーション
+ $request->validate([
+ 'schedule_id' => 'required|integer|exists:schedules,id',
+ 'user_id' => 'required|integer|exists:users,id'
+ ]);
+
+ try {
+ // スケジュールデータを取得
+ $schedule = Schedule::find($request->input('schedule_id'));
+
+ // スケジュールに紐付く予約情報を取得
+ $reserves = $schedule->reserves;
+
+ // 予約数上限を取得、ない場合は99とする
+ $limit = $schedule->reservation_limit ?? 99;
+
+ // すでに予約済みかどうか確認
+ $reserved_count = $reserves->where('user_id', $request->input('user_id'))->count();
+ if ($reserved_count > 0) {
+ // すでに予約済みなら終了
+ return redirect()->route('event.index')->with('message', 'already reserve!');
+ }
+
+ // 現在の予約数が予約上限以下であれば予約を行なう
+ if ($limit > $reserves->count()) {
+ $reserve = new Reserve();
+ $reserve->schedule_id = $request->input('schedule_id');
+ $reserve->user_id = $request->input('user_id');
+ $reserve->save();
+
+ // 予約完了メールの送信
+ $this->sendReserveMail($reserve);
+
+ return redirect()->route('event.index')->with('message', 'add reserve!');
+ } else {
+ return redirect()->route('event.index')->with('message', 'reserve limited!');
+ }
+ } catch (Exception $e) {
+ Log::error($e->getMessage());
+ }
+ }
+
}⑨予約登録時に管理者にも予約完了メールを送信する処理を実装する。
$sail artisan make:mail AdminReserved※下記の様に表示されたら成功。
$INFO Mailable [app/Mail/AdminReserved.php] created successfully. ⑩ユーザー宛と同様に送信メールのテンプレートファイルを作成し、メールクラスを設定する。
resources/views/emails/reserved-admin.blade.php を新規作成します。
<!DOCTYPE html>
<html lang="ja">
<head>
</head>
<body>
<h1>
スケジュールが予約されました。
</h1>
<p>
予約番号:{{ $reserve->id }} <br>
ユーザー:{{ $reserve->user->name }} 様 <br>
タイトル:{{ $reserve->schedule->title }} <br>
日時:{{ $reserve->schedule->from_date }} ~ {{ $reserve->schedule->due_date }} <br>
スタッフ:{{ $reserve->schedule->staff_name }}
</p>
</body>
</html>管理者宛メール送信処理をEventController->sendReserveMail()に追加実装する。
※下記、L23~L31を参照
class EventController extends Controller
{
// 中略
public function addReserve(Request $request)
{
// 中略
}
+ private function sendReserveMail(Reserve $reserve)
+ {
+ //send user email
+ Mail::to($reserve->user->email)->send(new UserReserved($reserve));
+
+ //send admin email
+ $admin_user = Admin::first();
+ Mail::to($admin_user->email)->send(new AdminReserved($reserve));
+ }
}確認事項
・ユーザーのカレンダーページからスケジュールをクリックできるかを確認する。
・スケジュールの詳細がモーダルで表示できるかを確認する。
・モーダルで予約ボタンをクリックした時に予約が完了し、ユーザーのメールアドレス宛に予約完了メールが送信されるかを確認する。
・管理者のメールアドレス宛も予約完了メールが送信されるかを確認する。
・管理画面予約管理に予約した情報が表示されかを確認する。
