24日目にLINEミニアプリが完成する初心者 ── Day6. 資料請求フォームの開発準備


# はじめに

前回は「24 日目に LINE ミニアプリが完成する初心者 ── Day5. スターターアプリを LINE ミニアプリ化する」と題して、デプロイした LIFF スターターアプリを LINE Developer に追加して LINE ミニアプリ化しました。

https://qiita.com/non_watanabe/private/7e100a8c0850f829269c

<br/>

今回の記事からは LINE ミニアプリの最初の機能として**資料請求フォーム**の作成を行っていきたいと思います。

この機能のゴールとしては、 URL クリックで表示される資料請求フォームに情報を入力し送信すると、スプレッドシートに内容が書き込まれることを目指します。

Day6 では、機能開発初めの記事ということで、設計と開発準備を行っていきます。

# 資料請求フォームの設計

まず、資料請求フォームに必要な項目を決めます。

今回は弊社 Mahalo Living の資料請求ページを再現していきます。

https://mahalo-living.com/catalog

<br/>
具体的には以下のような情報をユーザーから取得します。

| 項目                 | 必須 |    バリデーション     |
| :------------------- | :--: | :-------------------: |
| お名前               | ⚪︎  |          --           |
| メールアドレス       | ⚪︎  |  メールアドレス形式   |
| お電話番号           | ⚪︎  |    数字 + ハイフン    |
| 郵便番号             | ⚪︎  | 7 桁の数字 + ハイフン |
| 都道府県             | ⚪︎  |    プルダウン選択     |
| 市区町村             | ⚪︎  |          --           |
| 町名・番地           | ⚪︎  |          --           |
| ご意見・ご質問       |  -   |          --           |
| プライバシーポリシー | ⚪︎  |   チェックボックス    |

# 開発準備

本格的に開発を始める前に開発のしやすい環境を作っておきます。

## 不要なフォルダの削除

今回は Next.js で開発を行うため、スターターアプリに用意されている不要なフォルダについてはあらかじめ削除しておきたいと思います。

- `src/nextjs`
- `src/vanilla`

## 絶対 path の設定

スターターアプリでは絶対 path が設定されていないので、import が楽になるように予め設定しておきます。

`tsconfig.json`の`compilerOptions`に、以下の内容を追加しておきましょう。

```json:tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/components/*": ["components/*"]
    }
  }
}
```

## Tailwind CSS のインストール

今回は簡単に Style が設定できるよう Tailwind CSS を使っていきます。

https://tailwindcss.com/

### インストール

ターミナルで`src/nextjs`配下に移動してインストールを行いましょう。

```terminal
$ cd src/nextjs
$ npm install -D tailwindcss postcss autoprefixer
$ npx tailwindcss init -p
```

### tailwind.config.ts の更新

`npx tailwindcss init -p`で`tailwind.config.ts`が作成されるので、内容を以下の通り更新しておきましょう。

```ts:tailwind.config.ts
import type { Config } from "tailwindcss";

const config: Config = {
  content: ["./components/**/*.{js,ts,jsx,tsx,mdx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};
export default config;
```

:::note info
**`tailwind.config.js`で作成される場合もあります。**

筆者は TypeScript メインで開発していくため、.ts ファイルに変更しました。
.js で書く場合は以下の内容になります。

```js:tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./components/**/*.{js,ts,jsx,tsx,mdx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};
```

:::

<br/>
また、今回はよく使う色も primary という名称で定義しておきたいと思います。

```ts:tailwind.config.ts
import type { Config } from "tailwindcss";

const config: Config = {
  content: [
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
    "./stories/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      colors: {
        primary: "#333333",
      },
    },
  },
  plugins: [],
  important: true,
};
export default config;
```

### global.css の更新

tailwind.config.js の更新が完了したら、global.css も更新を行っていきましょう。

`styles/global.css`を開いて以下の内容を追加しておきましょう。

```css:global.css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

### \_app.js の更新

`global.css`はこの`_app.js`で読み込む必要がありますが、スターターキットではすでに読み込まれています。

こちらのファイルも念の為ファイルを`_app.tsx`に変更しておきます。

先ほど絶対 path を設定したので内容は以下に変えておいてもいいかもしれません。

```js:_app.js
// import "../styles/globals.css";
import "/styles/globals.css";
```

## Material-UI のインストール

フォームのデザインを整えるため Material-UI も使っていきます。

https://mui.com/

### インストール

ターミナルで`src/nextjs`配下でインストールを行いましょう。

```terminal
$ npm install @mui/material @emotion/react @emotion/styled
```

## react-hook-form のインストール

フォームのバリデーションには react-hook-form を使っていきます。

https://react-hook-form.com/

### インストール

ターミナルで`src/nextjs`配下でインストールを行いましょう。

```terminal
$ npm install react-hook-form
```

## フォントの設定

\_document.tsx ファイルで Google Fonts を使用してフォントを設定します。

今回は公式サイトで使っているフォントに近く、無料で使える`Zen Maru Gothic`を採用しました。

https://fonts.google.com/specimen/Zen+Maru+Gothic

<br/>

`src/pages`ディレクトリ直下に`_document.tsx`を作成して以下の内容を記述します。

```tsx:/src/_document.tsx
import { Html, Head, Main, NextScript, DocumentProps } from "next/document";

export default function Document(props: DocumentProps) {
  return (
    <Html lang="ja">
      <Head>
        <link
          href="https://fonts.googleapis.com/css2?family=Zen+Maru+Gothic:wght@400;500;700&display=swap"
          rel="stylesheet"
        />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}
```

<br/>
ここまで完了したら最後に念の為以下で立ち上げ直しをしておきましょう。

```terminal
$ npm run dev
```

# コンポーネントの作成

次に、資料請求フォームで使うコンポーネントを作成していきます。

`src/nextjs`配下に`components/ui`ディレクトリを作成してその中に実装をしていきます。

具体的なディレクトリ構成は以下のようになります。

```
src/nextjs
├── components
│   ├── pages
│   │   └── catalog
│   │       └── CatalogPage.tsx
│   ├── ui
│   │   ├── Button
│   │   │   └── Button.tsx
│   │   ├── Checkbox
│   │   │   └── Checkbox.tsx
│   │   ├── Input
│   │   │   └── Input.tsx
│   │   ├── Select
│   │   │   └── Select.tsx
│   │   ├── Textarea
│   │   │   └── Textarea.tsx
│   │   └── index.ts
│   └── layout.tsx
├── pages
│   ├── catalog
│   │   └── index.tsx
│   ├── _app.tsx
│   ├── _document.tsx
│   └── index.js
└── styles
    └── globals.css
```

今回はメインの内容ではないため、具体的なコードについては GitHub からご確認ください。

https://github.com/watanabe-goodlocal/mahalo_living/tree/develop/src/nextjs/components/ui

<br/>
以下で少しだけ補足をしておきます。

## forwardRef について

`components`ディレクトリ内のコンポーネントは、`react-hook-form`の`register`メソッドと連携するために`forwardRef`を使用しています。

以下は`Input.tsx`のコードの一部です。

```typescript:src/nextjs/components/ui/Input/Input.tsx
import { forwardRef } from "react";
import { TextField, FormControl, FormLabel } from "@mui/material";
import { InputProps } from "./type";

const Input = forwardRef<HTMLInputElement, InputProps>(
  (
    { label, required = false, placeholder, formSize = "w-full", ...props },
    _ref
  ) => {
    return (
      <div className="pb-5">
        <FormControl className={formSize}>
          <FormLabel
            className="font-bold text-primary"
            required={required}
            style={{ fontFamily: "Zen Maru Gothic, sans-serif" }}
            sx={{ fontSize: "15px" }}
          >
            {label}
          </FormLabel>
          <TextField
            {...props}
            inputRef={_ref}
            placeholder={placeholder}
            sx={{
              input: {
                "&::placeholder": {
                  fontFamily: "Zen Maru Gothic, sans-serif",
                },
              },
            }}
          />
        </FormControl>
      </div>
    );
  }
);

Input.displayName = "Input";

export default Input;
```

## Textarea の style について

`Textarea.tsx`では、MUI の TextField と style を合わせるために以下のように設定しています。

```css:globals.css
.textarea {
  padding: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  outline: none;
  transition: border-color 0.3s, box-shadow 0.3s;
}

.textarea:focus {
  border-color: #1976d2; /* MUIのTextFieldのフォーカス時の色 */
  box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.5); /* #1976d2のrgba */
}

.textarea.error {
  border-color: #d32e2e;
}

.textarea.error:focus {
  border-color: #d32e2e; /* MUIのエラー時のフォーカス色 */
  box-shadow: 0 0 0 2px rgba(211, 46, 46, 0.5); /* #d32e2eのrgba */
}
```

## Storybook について

GitHub のコードには Storybook のコードも含まれています。

これは筆者が開発しやすいよう追加しましたが、必須ではありませんので導入はお任せします。

# まとめ

ここまでで、設計と開発準備が完了しました。

次回は、今回作成したコンポーネントを元に、資料請求フォームの作成を行っていきたいと思います。

残りは 18 日！
気になる方は是非フォローやカレンダー購読をお願いします:star: