「同意してチェックしてください」を実装したときのエピソード＆雑談

## 先日、a-blog cmsアドベントカレンダーの振り返りイベントがありました。
[a-blog cms LIVE Vol.21](https://ablogcms-live.doorkeeper.jp/events/181711)を視聴しました。
振り返ることができる復習系のイベント、嬉しいです。
LIVEを視聴し、12月にアドベントカレンダーを読んだ時は、使おう！と思っていたtipsたちを全然使いこなせていなかったことに気づきました。

:::note info
使おうと思っていたが、使えていなかったtipsたち:point_down:
* [【a-blog cms】テーマ実装に役立つ！便利な機能3選](https://zenn.dev/suzulabo/articles/af975b429cc42f)
* [ユニット設定を使いこなす](https://developer.a-blogcms.jp/blog/custom/unit-setting.html)

:::


あと、tips関連での気づきですが、Xやアドベントカレンダーを見ていて、**便利なtipsを自分でキャッチして使いこなせる人や、最新技術を早速使っている人は、日頃から色んな方向にアンテナを張ってるんだなー**:satellite:ということです。

最近、仕事で「**正規表現**」を使うことがありました。
その言葉自体はなんか耳にすることがあるな、くらいの認知度で、**自分の仕事の領域には全く関係ないものだ**と勝手に思い込んでいました。（もっとエンジニア向けの表記方法だとばかり思っていた。）
ですが、あるとき使う機会があり、便利さを知りました。
自分には全く関係ないと思い込んでいる知識も、めっちゃ役にたつもんなんだなーと思いました。
関係ないと思う知識でも知らないものは、検索するなり、人に聞いてみるなり、まず興味を持とうと思いました。:sunny:

さて、では本題に行きましょう。
**今回は、予約フォームなどでよく見る、同意チェックボックスを取り上げてみました:point_up:**

## 皆さん同意画面、どうやって作ってますか？
予約フォームの一番下に、同意画面がほしいというタスクが来たときの話です。
そのときは、以下の要望がありました。

:::note warn
同意文は、**確実に**読んでもらいたい！
:::

この要望のすり合わせに、まず、手こずりました。
同意文を「**確実に読んでもらう**」のは、同意の文章が長いと、かな〜り難しいです。
なので、確実に読んでもらうのが難しいなりに、最初は、以下のようなものを想定していました。
STEPブロックを使用して、同意画面を、確認画面へ行く前に強制的に挟み込むというやり方です。
下図の様な感じ。（備忘録でメモ。[入力ステップの分割表示](https://developer.a-blogcms.jp/document/form/split.html)、[stepブロックを知ろう](https://developer.a-blogcms.jp/document/form/form-practice2.html)）
![.スクリーンショット 2025-02-27 16.22.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/9a627519-e903-4aeb-a647-24afd0c143cb.png)

しかし、よくよく関係者にヒアリングした結果、**確実に同意文を読んでもらうより、**「**形式的にでも必ず同意が欲しい**」ということが発覚しました。
ヒアリングって大事なんですね:thinking:
なので、まず「**同意**」**をしてもらうのが絶対**という方向性に変更しました。
そして、世間ではどんな同意画面があるのかをチェックしてみました。
下図の様な2種類のパターンをよく見かけました。

▼「同意して次へ」はボタンのタイプで、ボタンを押したら確認画面にいくパターン
![.スクリーンショット 2025-02-27 17.00.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/5448ca01-a07d-4008-aca0-2d9266186040.png)
▼チェックボックスがあり、同意をさせ、確認画面へのボタンは別のボタンというパターン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/3abe8cd3-2f6b-466b-9ff1-048f8d759133.png)

今回は、**自らの意思で同意をしてもらう**のが肝心だったので、結果的にボタンではなくチェックボックスを設けることになりました。
さらに、チェックボックスは、同意文をすべてスクロールするまで、チェックが打てないようにしたい、ということになりました。
（最後までスクロールしてチェック、という挙動を入れることで、最初の「同意文を確実に読んで貰いたい」という要望が少し解消された効果もあったかも。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/3abe8cd3-2f6b-466b-9ff1-048f8d759133.png)


## 方向性が定まってから、実際にどう実装したか
ディレクターにアドバイスを貰いつつ、どう実装するか計画を立てました:writing_hand:。

▼ざっと似たようなことを実装されている記事をいくつか読んで参考に。
* [JavaScriptで最後までスクロールしないとチェックできない規約を作る](https://qiita.com/buntafujikawa/items/fcf48a25146808e0542f)
* [【jQuery】最後までスクロールしなければいけない利用規約を作成](https://qiita.com/daichi0713/items/009a63493697b90771f9)

実装としては、同意文を記述したエントリーを1記事作成し、それをモジュールで、予約フォームの同意部分へ出力させるやり方にすることに決まりました。
（テンプレートに記述せず、モジュールを使った理由として、**同意文の内容で変更が必要な場合、エントリーで出力されていれば、編集が誰でも簡単なため**という理由です。今後を見据えた実装にすることになりました。）

:::note info 
手順

1. 出力用のエントリーを作成しておく。（今回は、/agreement/と言うカテゴリーを作成。その中にファイル名無しの出力用エントリーを1記事作成した。）
2.  /contact/form/agreement.html を作成（モジュール用）し、中身を書く（※1　agreement.htmlは以下を記述）。モジュール側の設定は下図。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/0d47314d-07b5-4d56-802a-a3f18107cd74.png)
3. cssで装飾する、小窓みたいにする。(※2　cssの変更箇所)
4. agreement.html をcontact/form/input.htmlにてインクルードさせる
5. contact/form/input.htmlの「内容の確認へ」のボタンの前に入力用チェックボックスを付ける。（※3　同意のチェックボックス作成） 「※1　agreement.htmlは以下を記述」にチェックボックスのコード記載済みなので、改めて記述の必要が無い場合は6.へ進む。
6. contact/form/confirm.html で「同意しました」が出力できるように出力用コードを入れる。（※4　出力用コードを入れる）
7. いったん、ここまでで、思い通りの挙動か確認する。メールフォームの一般向け・管理者向けの確認メールにも反映されているか確認。問題なかったら、「最後までスクロールしてチェック」の挙動を実装していく。
8. チャットGPTに聞きながら、JavaScriptを書いてもらい、js.htmlに記述（※5　具体的なコードについて）

完成

:::




※1　agreement.htmlは以下を記述。
基本はエントリーボディを使用しており、不要なコードは削除しました。
```
<legend class="form-label">
    <span class="label-required">必須</span>〇〇への同意　　
</legend>
<div class="box">
<!-- BEGIN_MODULE Entry_Body  id="body_agreement"-->
<div>
	<!-- BEGIN notFound -->
	<p>ただいまページを準備しております。もうしばらくお待ちください。</p>
	<!-- END notFound -->
	
	<!-- BEGIN entry:loop -->
	<div>
		<div>
			<!-- BEGIN unit:veil -->
			<div class="acms-entry">
				<div class="acms-grid-r">
				@include("/include/unit.html")
				</div>
			</div>
			<hr class="clearHidden">
			<!-- END unit:veil -->
				
			@include("/admin/entry/edit-%{IS_ADMIN}.html")
	
			
			@include("/admin/entry/action.html")
		</div>

	</div>
	<!-- END entry:loop -->
</div>
<!-- END_MODULE Entry_Body -->
</div>
  
  <p><span class="bold dangerColor">※上記は、必ずご一読ください。</br>※最後までスクロールしてチェックを入れてください。</span></p>
  

  
  <td>
	  <div class="acms-admin-form-checkbox">
		<input type="checkbox" name="doui[]" {doui:checked#doui} id="input-checkbox-doui-doui" value="doui" />
		<label for="input-checkbox-doui-doui">
		  <i class="acms-admin-ico-checkbox"></i>最後までスクロールして同意しました</label>
	  </div>
	  <input type="hidden" name="field[]" value="doui" />
	  <input type="hidden" name="doui:v#required" id="doui-v-required" value="" />
	  
	  
	  <div data-validator-label="doui-v-required" class="validator-result-{doui:v#required}">
		<p class="form-error-text"><span class="acms-icon acms-icon-news" aria-hidden="true"></span>最後までスクロールして、同意にチェックをお願いいたします。</p>
	  </div>
	  
	</td>
```




.box部分は、以下のような感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/aa87c326-63dc-6cb4-b502-e4826abef547.png)




※2　cssの変更箇所

```

/*  同意文のBOXの装飾
------------------------------ */
.box {
  min-height: 50vh;
  height: 50vh;
  border: 1px solid;
  overflow-y: scroll;
  padding-right: 5px; 
  padding-left: 5px;
  width: 95%;
  overflow-x: hidden;
}

.box ul{
	padding-right: 20px;
	padding-left: 20px;
}

.box p,.box h1,.box h2,.box h3{
	padding-right: 10px;
	padding-left: 10px;
}

.RootCategory__contact .entry-style-grid>.is-h2:first-child h2{
	margin-top: auto;
}


@media (max-width: 769px){
	.RootCategory__contact .form-checkbox-only{
		margin-right: 15px;
	}
}

@media (min-width: 769px){
	.acms-admin-form-checkbox input:disabled+label {
	opacity: .6;
	font-size: x-large;
	}
	
	a.FooterCta__telBtn.telBtn.js-viewing-indelible {
		pointer-events: none;
		cursor: default;
	  }
}


```
※3　同意のチェックボックス作成
[カスタムフィールドメーカー](https://developer.a-blogcms.jp/tools/custom-field.html)を必要な箇所だけ使用しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/df43f206-d68a-ed14-0e12-eec0ae00487e.png)

※4　出力用コードを入れる
メールフォームで送られてくるものなので、一旦控えておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/4357a1f4-a0a1-4a89-71e2-e3e6bf1aa3c3.png)

※5　具体的なコードについて
チャットGPTには、以下のように質問しました。
「・最後までスクロールを、下から50pxのところまで来たら、チェックボックスを有効にしたい
・HTMLは以下です（HTMLを載せる）」
質問の結果、返ってきたJavaScriptが以下です。
```
<script>
 document.addEventListener('DOMContentLoaded', () => {
   let box = document.querySelector('.box');
   let checkBox = document.getElementById('input-checkbox-doui-doui');
 
   if (box && checkBox) {
     checkBox.disabled = true;
 
     const enableCheckBox = () => {
       // 下から50px以内にスクロールしたか確認
       if (box.scrollTop + box.clientHeight >= box.scrollHeight - 50) {
         checkBox.disabled = false;
       }
     };
 
     box.addEventListener('scroll', enableCheckBox);
   }
 });

 
 </script>

```
## 完成した見た目
チェックできるようになると、なぜか文字サイズが変わってしまうので、それを調整したいなと思いました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/f61c1a74-2d61-4aab-a166-3672ae51449d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638020/7ac6d86c-0305-4bc5-acf8-aa9c1cc44b36.png)

## 感想
けっこう大変でした:sweat_smile:。
実装していても思い通り挙動しなかったり、チャットGPTに聞くにも、JavaScriptに詳しくないので聞き方が難しいなと思いました。
あと、着手前のヒアリングが、かなり大切だと思いました。ヒアリングによって、完成品が大きく変わってくるものなんだと知った機会でした。
最初に、**どういうことをしたいのか**？**何を一番実現したいのか（優先順位）**？を、ちゃんと調査しきれておらず、着手する前から右往左往してしまい、時間を消費してしまいました。
なので、「**まず、ヒアリングと調査**:writing_hand:」を心がけようと思います。