ノーコード ラボ

NoCode 関連のツールの紹介、使い方などをやさしく説明します。質問やご指摘大歓迎です。わからないことがあったら、コメントや Twitter などで聞いてください!

Bubble で calendly クローンを作ってみる!(初級者向け)7:予約機能の考え方とデータベースへの登録

f:id:yksmt:20220104104258p:plain

この記事は 【 Bubble で calendly クローンを作ってみる!(初級者向け) 】の第7回です。 前提条件等、確認されていない方は先にこちらの記事を確認してください。

blog.nocodelab.jp

みなさん、こんにちは!今回は、いよいよユーザー(お客様)が予約をした時の仕様について、データベースを中心にご紹介したいと思います。やり方は色々あると思いますが、実装例の一つとして参考にしてみてくださいね!作成するページは、前回の第6回の event ページの続きになります。

では、早速はじめていきましょう~!

f:id:yksmt:20210527152018p:plain

1. 関係する主な Data Type

本シリーズで作成する Data Type(テーブル)については、第1回の「作成するページの役割とデータベースの構成について」でも紹介していますが、ここでは予約で関係する主なテーブルについて、再度もう少し詳しくご紹介したいと思います。

Reserve Type

Reserve Type は、予約された時に登録されるメインの テーブルです。

f:id:yksmt:20210326134148p:plain

フィールド名 詳細
Event どの Event に紐づいた Reserve(予約)であるかを登録します。型を Event にすることで Event Type と紐づけています。
Event Date ユーザー(お客様)が選択した日付を登録します。日付以下の時間については Calendar Tool プラグインで取得したときの AM0:00 でフォーマットされたままの状態で登録していて、予約時間については、Time Field で管理します。
Event End Datetime 予約の終了時間を登録します。具体的には、予約時間から Event Type の Duration Minutes の値を加算した日時となります。なお、予約の開始時間(Event Start Datetime)となるようなフィールドは、Event Date と Time フィールドで判断できるため、今回は作成しませんでした。
Invitee 予約したお客様を登録します。実際のお客様データは Invitee(招待者)Type に登録されているデータと紐づきます。型を List にしているのは、複数の招待者のイベントに対応する為です。
range15、range30、range60 これらのフィールドは、Event Type の Duration によって確保される時間枠を管理しています。 例えば、Event Type の Duration Minutes が 60(1時間)のイベントで、AM9:00 から予約された場合、15分間のイベントにおいても、9:00~、9:15~、9:30~、9:45~の時間枠は登録されないようにしておく必要があります。このような状態を管理する方法として、range15 には TimeMasterの「9:00,9:15,9:30,9:45」を Listの状態で登録し、range30 には「9:00,9:30」、range60 には「9:00」を登録させて時間枠を確保し、二重予約は受け付けない判断ができるようにしています。
Remaining number イベントに招待できる残りの人数を登録します。具体的には、予約されたタイミングで Event Type の Max Invitee Count から -1 した値が登録されます。
Time ユーザー(お客様)が選択した時間が登録されます。型を TimeMaster にしておく必要があります。
User イベントの管理者が登録されます。本フィールドについては、Event Type からでも管理者を取得することはできますので、実装する機能などに合わせて適宜検討していただければと思います。

Invitee Type

Invitee Type は予約の招待者データです。今回はメールアドレス(Email)、名前(Name)、予約の際に一言メッセージを添えることができるようにメモ(Memo)フィールドのみを登録していきます。

f:id:yksmt:20210326133958p:plain

TimeMaster Type

TimeMaster Type は、予約時間に関するマスタテーブルです。この Data Type は、参照のみで使用していて、一度初期データを登録したら更新することはありませんのでご注意くださいね。

f:id:yksmt:20210326134408p:plain

TimeMaster Type には、以下の図のような状態でデータが登録されています。

f:id:yksmt:20220104151043p:plain

フィールド名 詳細
Time 15分刻みの時間を text 型で登録しています。
Display15、Display30、Display60 これらは yes/no を型にしたフラグフィールドで、イベントの所要時間によって、どの時間を表示するのか絞り込みを行う場合に使用しています。例えば、30分間のイベントで表示する時間データは、Display30 が yes のデータで検索しています。
MinuteNum 時間の分数をnumber 型で保持しています。こうした値を持っておくことで、AM0:00 でフォーマットした日付に対して Bubble の「+(minutes):」機能を使って値を加算し、対象の時間を取得することができます。
range30、range60 これらのフィールドは、対象の Time が30分枠、60分枠のどの枠に該当するかを管理しています。例えば、Time の値が 9:45 の場合は、30分間イベントでは「9:30」からの枠に含まると考え、1時間イベントでは「9:00」からの枠に含まれると考えます。なお、range15 フィールドは Time と同じ値となりますので作成していません。

※ TimeMaster Type の range30、range60 は、Reserve Type の range30、range60 とは意味合いが異なりますので、混同しないようにご注意ください。分かりにくいようであれば、リネームして実装していただければと思います。

2. Conditional の設定

では、前回の第6回の続きで、まだ Conditional の設定が残っている部分に Conditional を追加していきます。

f:id:yksmt:20220106104914p:plain

設定する element は、時間選択ポップアップ(Popup date)内にある、Group TimeMaster です。このボタンは、既に別の人によって予約が埋まってしまっている場合や、時間がすでに過ぎている場合はクリックできないように非活性にしておく必要があります。実際はボタンではなく、Group と Text で作成していますので、それぞれに Conditional を設定しましょう。

f:id:yksmt:20220106104532p:plain

まずは、Group TimeMaster です。この element には、以下の条件の場合に Conditional が必要です。

  1. Popup date の Custom state の clickable が no の時はクリックできない

  2. Reserve Type(予約テーブル)に管理者主催の Event の同時刻予約データが存在する時はクリックできない

  3. 現在時刻より過去の時間帯はクリックできない

  4. もし、管理者主催の Event の同時刻予約データが存在しても、残席があればクリックできる

1つ目の、Popup date の Custom state の clickable が no になる時というのは、第6回の Workflow で Set state した値を参照していて、いずれかの時間がクリックされたら他の時間帯はクリックできないようにするための Conditional です。When を Popup date's clickable is "no" として、Border color を #CCCCCC とし、This element isn't clickable にチェックを入れます。

f:id:yksmt:20220106111403p:plain

2つ目の、同時刻の予約データが存在するかどうかの条件文は、以下のようになります。 まずは、15分イベントから設定しましょう。Do search for から Reserve を選択し、Event Date = Popup date's date 、User contains Current Page Event's User:first item を条件に絞り込み range15 フィールドを参照したいので :each item's range15 を選択します。「range15 フィールドを参照したい」というのは、もし予約が入っていれば、range15フィールドに9時だったら 9:00 というデータが予約済み枠として登録されているため、このrange15フィールドを参照しています。 次に、contains Parent group's TimeMaster として、この Reserve から検索してきた List に、親グループで保持している TimeMaster の値が含まれるかどうかをチェックします。そして、この Event が15分の場合である必要があるので、and Current Page Event's Duration Minutes is 15 とします。言葉だと分かりにくいと思いますので、以下の図を参考にしてください。

f:id:yksmt:20220106111622p:plain

これと同じ条件で、range15 を range30、range60 に、Current Page Event's Duration Minutesの15 を 30、60 にそれぞれ変更した Conditional を設定します。

なお、Reserve Type から管理者のEventを取得する条件文「User contains Current Page Event's User:first item」についてですが、今回のシリーズでは Reserve Type の User フィールドは List で構成しているものの、管理者が複数人でコラボするような Event を作成する機能は実装していないため「Current Page Event's User:first item」としても問題ない(登録されている User は1件のみの想定だから)のですが、もしコラボ開催を実装するような場合だと、この条件では問題が出てきます。User フィールドに List の状態で複数人登録されている場合で、かつ取得した Reserve Type も List の状態のもの同士を検索したい場合は、:filtered で Advanced: から contain list を使用します。以下の図は、60分イベントの場合で取得させたものです。

f:id:yksmt:20220106135607p:plain

Search for Reserves では、Event Date だけを絞り込みの条件とし、

f:id:yksmt:20220106135818p:plain

:filtered で Advanced: を使って This Reserve's User contains list Current Page Event's User とします。この辺りは、実装するアプリの仕様で異なると思いますので、他のやり方なども含めて色々検討してみてくださいね。

以上で、2つ目の条件(Reserve Type に管理者主催の Event の同時刻予約データが存在する時はクリックできない)の Conditional が 15分、30分、60分と、合計3つ設定されました。

次は、3つ目の「現在時刻より過去の時間帯はクリックできない」です。Group TimeMaster の日時と現在時刻を比較するので、Popup date's date +(minutes): Parent group's TimeMaster's MinuteNum < Current date/time とします。 This element isn't clickable にチェックを入れてクリックできないようにしておきましょう。

f:id:yksmt:20220106143536p:plain

最後の4つ目は「もし、管理者主催の Event の同時刻予約データが存在しても、残席があればクリックできる」ようにします。Conditional は上から順番に読み込まれます。なので、2つ目の条件で、同時刻の予約データがある場合は非活性状態になっているので、残席がある場合はクリックできるように戻しておきます。

Do search for で Reserve Type から Event = Current Page Event、Event Date = Popup date's date、Time = This Group's TimeMaster を条件にユーザー(お客様)に選択された Event を検索し、:first item's Remaining number > 0 で残席数を調べます。なお、ボタンの活性状態が画面上に反映されるときのチラつきが気になるといった場合は、2つ目の Conditional で設定した非活性状態にする部分に、この4つ目の条件を15,30、60のそれぞれに追加して、この Conditional は設定しないという方法もあります。

f:id:yksmt:20220106145507p:plain

次に時間を表示している Text です。これは、Group TimeMaster がクリックできない場合には、文字をグレーアウトさせるように、Group TimeMaster isn't clickable の時に Font color を #CCCCCC としておきます。

f:id:yksmt:20220106150431p:plain

以上で Conditional の設定が完了しました!

3. ワークフローの作成

では、次に予約したときのワークフローを設定していきます。具体的には、予約フォームポップアップ(Popup TimeMaster)でスケジュール登録ボタンがクリックされたタイミングです。

f:id:yksmt:20220106152330p:plain

スケジュール登録ボタンは、Duration Minutes の15分、30分、60分で処理を別にして作成していきます。

f:id:yksmt:20220107105110p:plain

3.1. Custom event の作成

3.1.1 Create Reserve

まずは、共通化できそうな処理を Custom event にまとめていきます。ここでは、Invitee と Reserve の登録や更新処理をまとめていきたいと思います。Click here to add an event... から Custom event を作成し、名前を Create Reserve とします。

f:id:yksmt:20220107105220p:plain

Create Reserve の Step1 で、画面に入力された情報を Invitee に登録します。Email、Memo、Name を Input から取得してセットしましょう。

f:id:yksmt:20220106153153p:plain

次に Step2 で Reserve に必要な情報を登録していきます。登録するフィールドは、Event、Event Date、Time、Event End Datetime、Remaining number、Invitee、User の7つです。Event End Datetime は、ユーザー(お客様)が指定した日時に、Duration Minutes を加算させています。Remaining number は Event の最大招待人数(Max Invitee Count)から -1 をさせています。Invitee には Step1で登録したデータを引き渡しています。その他のセットする値は、以下の図を参考に設定してみてください。

f:id:yksmt:20220106153626p:plain

3.1.2. Update Reserve

次に Reserve を更新する Custom event を作成します。名前は Update Reserve としました。 Step1は Create Reserve の時と同じ Invitee を新規登録します。

f:id:yksmt:20220106154642p:plain

Step2 は、この Event の Reserve に対して、Remaining number と Invitee だけを更新します。

f:id:yksmt:20220106155359p:plain

この Update Reserve が呼び出されるのは、Event の招待人数が複数人の場合に実行される処理です。なので、複数人が参加する Event に対して予約が実行される際、その予約が一人目だった場合は Create event を実行して、Invitee も Reserve も両方作成し、二人目だった場合は、すでに Reserve のデータは存在しているので、Invitee だけ新規作成して、Reserve は招待人数などを更新しておくという流れになります。

3.2. スケジュール登録 クリックイベント

では、スケジュール登録ボタンがクリックされた時の処理を追加していきます。Duration Minutes 別に処理を変えたいので、クリックイベントの Only when に Current Page Event's Duration Minutes is として、15,30、60 の3つを条件として作成します。

f:id:yksmt:20220107105651p:plain

そして、それぞれのクリックイベント全てに、Step1 には、先ほど作成した Custom Event の Update Reserve を Trigger します。Only when には Search for Reserves:count > 0 として対象の Reserve が既に存在する場合は実行するようにしておきましょう。Reserve から取得する条件は以下の図を参考にしてください。

f:id:yksmt:20220107110205p:plain

同様に、Step2には Create Reserve を Trigger します。この時の Only when には、対象のReserveが0件の時としておきます。なお、もしこのような条件を使って Create と Update を一連の流れで実行する場合は、必ず Update から実行する必要がありますので注意してくださいね。Create を先に実行してしまうと、次のUpdate ではデータが必ず存在することになってしまうので、結果 Create も Update も両方実行されるといったことになります。また、この Step1 と Step2 のアクションは、Duration Minutes 毎に作成した3つのクリックイベントで共通のアクションとなるので、コピーしていただければと思います。

f:id:yksmt:20220107110851p:plain

では、Duration Minutes 別に Step3 のアクションを追加していきましょう。Step3 では、Step1 もしくは Step2 で登録された Reserve に対して、range15、range30、range60 フィールドの値に予約された時間枠を Make changes to thing... で更新する処理を設定します。これが意味するところは、「この管理者の、この時間は既に予約が入っていますよ」ということになります。

3.2.1. 15分間 Event でクリックされた時

まずは、15のものから設定します。

Make changes to thing... アクションを追加して、Thing to change を以下の図の条件で Reserve を検索し :first item で絞り込みます。 この Thing to change に登録する条件は、15でも、次に作成する30でも、60でも全て同じになります。

f:id:yksmt:20220107112432p:plain

次に、range15、range30、range60 フィールドに TimeMaster から検索した時間を add list していきます。

予約される Event の Duration Minutes が15分間の場合、range15 に登録して確保したい時間は、お客様が指定した時間、例えば9:00なら9:00だけを登録したいので、TimeMaster からは This Reserve’s Time's Time で取得した値になります。

f:id:yksmt:20220107113611p:plain

次に、range30 に登録して確保したい時間を考えます。Event 自体は15分間だけなので、先ほどの例で言うと 9:00 予約であれば 9:15 までですが、この管理者は9:00 開始の予約は、別の30分間Event や1時間Event においても、受け付けることはできないことになります。なので、range30 に登録して確保したい時間は、TimeMaster の range30 フィールドの値を条件にして This Reserve’s Time's range30 となり、range60 では、This Reserve’s Time's range60 を条件に取得した値となります。

f:id:yksmt:20220107113720p:plain

f:id:yksmt:20220107113820p:plain

15分間Event で登録される Reserve のデータは以下のような状態になります。(サンプル図は12:00に予約した場合です。)

f:id:yksmt:20220107120610p:plain

以上で、15分間 Event の Reserve Type へ登録できたので、次の Step4 では表示している Popup を閉じて、Step5 で Page を Refresh するアクションを追加していきます。Step4、Step5 も Step1 と Step2 の時と同じように、Duration Minutes の 15,30,60 のそれぞれのクリックイベントで共通の処理になりますので、コピーするようにしてください。もしくは、Custom Event を利用して共通化していただいても大丈夫です。

f:id:yksmt:20220107141554p:plain

f:id:yksmt:20220107142259p:plain

以上で、Current Page Event's Duration Minutes is 15 のクリックイベントが完成です。もう一度まとめておきますと、Step3 の Reserve Type の range15、range30、range60 へ add list する Search fo TimeMasters の条件が異なる以外は、Step1と Step2、Step4 と Step5 の各アクションは 15 も 30 も 60 も同一のものになります。

3.2.2. 30分間 Event でクリックされた時

では、次に Current Page Event's Duration Minutes is 30 のクリックイベントの Step3 を登録していきましょう。

30分間 Event に対して予約が入った場合、range15 には 2枠の時間が使用されることになりますので、TimeMaster を検索するときの条件は、Display15="yes" と range30=This Reserve's Time's range30 を条件にします。混乱しやすいですが、この This Reserve's Time's range30 の range30 は Reserve Type の range30 ではなく TimeMaster の range30 が参照されていることに注意してください。

f:id:yksmt:20220107142845p:plain

range30 には予約時間の1枠を登録したいので、Time = This Reserve's Time's range30 が条件になります、

f:id:yksmt:20220107142930p:plain

range60 も30の時と同様に、予約時間の1枠を登録したいので、Time = This Reserve's Time's range60 が条件となります、

f:id:yksmt:20220107142953p:plain

30分間Event で登録される Reserve のデータは以下のような状態になります。(サンプル図は15:00に予約した場合です。)

f:id:yksmt:20220107144504p:plain

Step4、Step5 は、15分間 Event の時と同じものになります。

3.2.3. 1時間 Event でクリックされた時

最後に 次に Current Page Event's Duration Minutes is 60 のクリックイベントの Step3 です。

1時間 Event に対して予約が入った場合、range15 には 合計4枠の時間が使用されることになりますので、Display15="yes" とrange60=This Reserve's Time's range60 を条件に TimeMaster を検索して add list します。

f:id:yksmt:20220107151342p:plain

range30 には 合計2枠の時間が使用されることになりますので、Display30="yes" と range60=This Reserve's Time's range60 を条件に TimeMaster を検索して add list します。

f:id:yksmt:20220107150306p:plain

range60 には 1枠が使用されることになりますので、Time =This Reserve's Time's Time となります。

f:id:yksmt:20220107143201p:plain

1時間Event で登録される Reserve のデータは以下のような状態になります。(サンプル図は16:00に予約した場合です。)

f:id:yksmt:20220107144758p:plain

1時間 Event においても、Step4、Step5 は、15分間 Event の時と同じものになりますので、コピーなどで追加するようにしてくださいね。

以上で、event ページの完成となります!お疲れさまでした!

本アプリでは、Reserve Type の range15~60 フィールドを活用することで、予約機能を実装しました。フィールド名や Data Type が混在するので、分かりにくいかもしませんが、ぜひ参考にしてみてくださいね。

次回

では、次回は管理者が予約を確認できる「予約一覧ページの作成」についてご紹介したいと思います。ここまでお読みいただき、ありがとうございました!では、次回もどうぞお楽しみに~!

コンテンツ

Bubble で calendly クローンを作ってみる!(初級者向け)

1:作成するページの役割とデータベースの構成について

2:ログイン周りとアカウントページの作成

3:ダッシュボードとイベントカレンダー一覧ページの作成

4:イベントの新規作成ページの作成

5:イベントの編集ページの作成

6:Repeating group カレンダーの作成方法とイベントカレンダーページの作成

7:予約機能の考え方とデータベースへの登録

8:予約一覧ページの作成(前半)

9:予約一覧ページの作成(後半)