この記事は 【 Bubble で calendly クローンを作ってみる!(初級者向け) 】の第9回です。 前提条件等、確認されていない方は先にこちらの記事を確認してください。
本シリーズ最終回となりました。今回も、前回と同じ管理者が予約一覧を確認できるページ(scheduled_events)の続きを作成していきます。では、早速始めていきましょう!
1. 画面作成
1.1. RepeatingGroup Reserve
では、前回作成した RepeatingGroup Reserve の中身を作成していきます。
Reserve Type には以下の図のように、ユーザー(お客さま)が予約するタイミングで登録されるので、日付や時間もごちゃ混ぜの状態になっています。
これを以下の図のように、日時で並び替え、日付部分(yyyy/mm/dd)については、同日のものは一度だけ表示するようにします。
まずは、日付を表示させる部分を作成していきます。Repeating group 内に Group を一つ配置して、Type of content を Reserve とし、Current cell's Reserve として、This element is visible on page load のチェックを外し Collapse this element's height when hidden にチェックを入れて、初期ロードでは非表示としておきます。ここでは、Background color を #F7F7F7 として、W 900、H50、名前を Group Event Detail Day としました。
次に、日付が重複して表示されないように、Conditional を設定します。まずは「予定中」タブの場合は、Do a search for から Event Date = Current cell's Reserve's Event Date、Event End Datetime >= Current date/time、User contains Current User を条件に Reserve を検索し、Event End Datetime を昇順で並び替えて、:first item is Current cell's Reserve としておきます。この条件は、「Repeating group Reserve から取得してきた1行目が Current cell の Reserve と一致する場合(=その日付データの1行目である)」という意味になります。さらに「予約中」タブが選択されている場合に限る必要があるので、条件を and で繋ぎ、scheduled_events's Current Display is 1 としておきます。そして、条件に一致した場合に表示されるように、This element is visible にチェックをいれておきます。
次に「過去」タブが選択されている場合の Conditional を設定します。Event Date = Current cell's Reserve's Event Date、Event End Datetime < Current date/time、User contains Current User を条件として、Event End Datetime を先ほどと同じく昇順で並び替えて、:first item is Current cell's Reserve としておき、条件を and で繋ぎ、scheduled_events's Current Display is 3 としておきましょう。This element is visible にチェックをいれておきます。
次に、下図の Reserve データの内容を表示する部分を作成します。まずは 概要的な内容を表示させ、データをクリックしたら、さらに詳細データを表示するようにします。
概要部分には、Event の色、時間、ベント名と Slug に登録されているリンク名を表示させ、詳細データがあることが分かるように「▼詳細」Text を配置していきます。
Data source を Current cell's Reserve とした Group を一つ配置し、Conditional で、マウスが hovered された時と pressed された時に、Background color を 薄い水色(ここでは #03B4C6 としています)になるように設定しておきます。ここでは Group 名を Group Reserve header としました。
次に Event の色を表示する丸いアイコンを表示させましょう。これは、第3回記事の calendly ページでも作成した同じアイコンになりますので、以前は作成していませんでしたが、Reusable element にした方が良さそうですね!
ということで、この Event Color アイコンを Reusable element にしておきたいと思います。第3回で作成した Group を今回の Reusable element で置き換えていただいても結構です。
New reusabule element の Element name を Event Color Icon として CREATE します。
Type of content を Event として、W30、H30 にリサイズし、Roundness を 15 にして丸くしておきます。Background の Color を Event Color Icon's Event's Event Color's Code と指定しておきましょう。
scheduled_events ページに戻り、作成した Event Color Icon を配置し、Data source を Parent group's Reserve's Event として取得した Reserve Type の Event フィールドを引き渡しておきます。
次に時間の部分を HH:MM ~ HH:MM にフォーマットして表示させるようにします。まず開始時間ですが、AM0:00 でフォーマットされた Event Date に、Time で保存されている分数を加算することで算出することができますので、Parent group's Reserve's Event Date +(minutes): Parent group's Reserve's Time's MinuteNum:formatted as HH:MM とします。
次にテキストで「~」を入力して、終了時間となる Parent group's Reserve's Event End Datetime を :formatted as HH:MM したものと繋いでおきましょう。
Event Color アイコンと時間 Text のレイアウトが整うように、これらの element を複数選択して、Arrange の Group elements in a group から1つの Group にまとめておきます。
次に、Event フィールドの Slug を参照して、マイリンク名を Text に表示させ、その下に Event Name を配置しておき、先ほどと同様に Group でまとめておきます。
一番右側に「▼ 詳細」とした Text を配置します。こちらは詳細データが表示されている場合は「▲ 詳細」となるように後ほど Conditional を設定します。
では次に、概要部分の Group Reserve header がクリックしたときに表示する詳細データの部分を作成していきます。
Group Reserve header の下に、新しい Group を配置し、Data source には、Current cell's Reserve として Repeating group からデータを受け取り、This element is visible on page load のチェックを外して、Collapse this element's height when hidden にチェックを入れておきます。ここでは名前を Group Reserve Toggle としました。
では、詳細データのエリアが作成できましたので、「▼ 詳細」Text の Conditional を設定しておきましょう。Text を選択して、Conditional を Group Reserve Toggle is visible の場合に Text を「▲ 詳細」にするとしておきます。
Group Reserve Toggle の中身を作成していきます。まずは、対象の Reserve(Current cell's Reserve) に対して行うことができるメニューエリアを作成します。Group Reserve header の下に Group を一つ配置して、Data source を Parent group's Reserve として Group Reserve Toggle の Reserve を引き継ぎ、This element is visible on page load のチェックを外して、Collapse this element's height when hidden にチェックを入れ、非表示にしておきます。配置した Group 内には「イベントタイプ編集」「コピーリンク」「キャンセル」とした3つのメニュー(Text element) を作成しておきます。
これらのメニューをまとめた Group は、「過去」タブ選択時には表示させず、「予約中」タブが選択されている場合にのみ表示したいので、Conditional で scheduled_events's Current Display is 1 の場合に、This element is visible としておきます。
次に、Reserve Type から取得した、予約の詳細データを表示させます。ここでは、Email と データ作成日を表示しています。また、Email については、Reserve Type の Invitee フィールドで紐づけられた Invitee Type から取得しています。また、Invitee フィールドは、リストで保存されていますので、表示させる場合は Type of content を Invitee とした Repeating group を配置しています。
次に、最終行の場合は「リストの最後に到達しました」Text が表示されるようにしておきます。This element is visible on page load をオフにして、Collapse this element's height when hidden をオンにした Group を一つ作成して、Text を配置します。
Group の Conditional で、Current cell's index is RepeatingGroup Reserve's List of Reserves:count として最終行である場合は、This element is visible としておきましょう。
以上で、「予約中」と「過去」が選択されている場合の一覧が作成できました。
1.2. RepeatingGroup Event
では次に、「保留」タブが選択されている場合に表示する RepeatingGroup Event の中身を作成していきます。
表示する element の構成は、先ほどの RepeatingGroup Reserve とほぼ同様となりますので、Group Reserve header を丸ごとコピーしてしまいます。コピーしたタイミングで複数の issue が発生しますが、Reserve Type から取得している部分を Event Type に書き換えることで解決することができます。
Reserve から Event へ修正した Data source は下図をご参考ください。
次に、詳細データの部分も同様に Group Reserve Toggle をコピーして作成します。なお、この「保留」タブに表示されているデータは、前回でも解説した通り、1対1やグループのような固定ページが存在しない、1回限りの会議が登録されていることが分かるようにするための一覧ですので、まだ実際にはユーザー(お客様)によって予約されていない Event が表示されている場合もあります。(予約済みの1回限りの会議については、Reserve が存在しますので、「予約中」もしくは「過去」タブに表示されます。)
上記のことから、Group Reserve Toggle からコピーしてきた Email(Invitee)に関するデータは存在しないので、Email を表示する element 群は削除しています。
また、issue を解決する際に、メニューをまとめている Group(ここでは Group Event)に設定されていた Conditional は不要となりますので削除しておいてください。
キャンセル Text については、まだ予約されていない Event に対してのみイベントの削除を行うことができる仕様としますので、文言をキャンセルではなくイベント削除としています。また、Reserve が存在しない Event かどうかを件数で判断して、表示非表示を切り替える Conditional を設定しておきます。
では「保留」タブにも、最終行の場合は「リストの最後に到達しました」Text を表示するようにしておきましょう。
Conditional の条件は、Reserve の時と同じ考え方で、Current cell's index is RepeatingGroup Event's List of Events:count としておきます。
1.3. Popup 作成
「予約中」タブで、キャンセルがクリックされた場合に表示するポップアップを作成しておきます。Popup の Type of content を Reserve として、閉じる Icon、予約をキャンセルします。よろしいですか? Text、キャンセルする Button の3つを配置しておきます。ここでは名前を Popup Reserve Delete としました。
次に、「保留」タブで、イベント削除がクリックされた場合に表示するポップアップを作成します。Popup の Type of content を Event として、閉じる Icon、スケジュールを削除します。よろしいですか? Text、削除する Button の3つを配置しておきます。名前を Popup Event Delete としています。
以上で、画面作成が完成しました!
2. ワークフローの作成
次に、ワークフローを作成していきます。まずは、scheduled_events ページは管理者画面になりますので、event_types ページなどと同じように、管理者以外は締め出すのと、初期データが未登録の場合は強制遷移させる処理を追加しておきましょう。
また、scheduled_events ページを event_types ページからコピーして作成した際に、ヘッダー部分のワークフローも一緒にコピーされていると思いますので、紛らわしいようでしたら、こちらは以下の図のように、Workflow folders にまとめておくと分かりやすいです。
2.1. 「予約中」と「過去」
では、RepeatingGroup Reserve 内に作成した element に対してワークフローを設定していきます。全部で6つになります。
まずは、Group Reserve header がクリックされたら、一覧の詳細データ(Group Reserve Toggle)の表示非表示を Toggle アクションで切り替えます。
次に「イベントタイプ編集」Text がクリックされたら、edit_event_type ページに遷移するように、Go to page しておきます。その際に、edit_event_type ページの Type of content は Event ですので、Data to send に Parent group's Reserve's Event として、Event Type を指定しておきましょう。
次に「コピーリンク」Text がクリックされた場合です。まずは Custom state を一つ用意して(ここでは Text element に対して url という Custom state を設定しています)、Step1で、event ページまでの URL が取得できるように、This url の scheduled_events を event/Parent group's Reserve's Event's Slug で置換した値で Set state します。
Step2 で Custom state にセットした値で、Copy to clipboard します。
次に「キャンセル」Text がクリックされた場合のワークフローです。予約キャンセルについては、Popup を1枚入れますので、Step1 で Popup Reserve Delete に対して Data to display で 該当の Reserve Type を引き渡し、Step2 で Popup を Show させます。
次に Popup での予約キャンセルの処理です。まずは、Reserve からではなく、Invitee Type のデータから Delete して、次に Reserve Type を Delete します。最後に Popup を Hide して閉じておきます。なお、サービスによっては 直接 Delete してしまうのではなく、削除フラグのようなもので判断することもあるかと思います。この辺りはサービスの規模などに合わせて実装していただければと思います。
キャンセルを中止できるように、Popup には閉じる Icon を作成しておきます。Reset data して、Popup を Hide しておきましょう。
なお「過去」タブが選択されている場合、イベントタイプの編集やコピーリンクやキャンセルについては、画面上非表示となっていますので、実行されない仕様としています。
2.2. 「保留」
では次に RepeatingGroup Event 内に作成した element に対してワークフローを設定していきます。
こちらも、先ほどと同じ6つで、処理の内容もほぼ同様となりますので、以下の図を参考に設定してみてください。注意点としては、削除するデータは Reserve ではなく Event になり、その際は 予約件数が0件である場合に限られていますので、Invitee は存在しません。
以上で、すべての画面とワークフローの作成が完成しました!お疲れさまでした。
3. おまけ プライバシールールついて
最後に参考として、プライバシールールを設定する際に考慮する点について、簡単にご紹介しておきたいと思います。
下図は Reserve Type に設定しているプライバシールールです。
本アプリでは、Event の URL を知っている人は、誰でも予約ができる仕様となっています。なので、その日のその時間に予約ができるか?を判断できるようにするには、誰もが Reserve に登録されているデータを検索して、空きがあるか既存の予約を確認する必要があります。具体的には everyone に権限を与える必要がありますが、Email の情報を含む、誰がその Event に参加するのか?については、管理者だけが閲覧できるようにしておきたい情報です。
その為、Reserve Type では、Everyone にも権限が付与されていますが、参照できるフィールドを限定する形で設定しています。
ただし、この場合だと、Reserve Type 経由では Invitee を参照することは出来ないのですが、直接 Invitee Type を検索するような画面がある場合には不十分で、そういった場合は、Invitee Type に対しても別途プライバシールールを設定する必要があります。Invitee Type については、今回のDB設計では権限付与を判断するためのフィールドが足りませんので、アプリの仕様に合わせてフィールドを追加するなどの対応が必要です。
データベース構成を考える場合は、プライバシールールについても考慮して実装してみてくださいね。
では、本シリーズに最後までお付き合いいただき、本当にありがとうございました!本アプリは、calendly の一部機能のみを実装したものになりますが、Bubbleでアプリを実装する際の、アイデアの一つとしてご参考いただければ幸いです!
コンテンツ
Bubble で calendly クローンを作ってみる!(初級者向け)