【ChatGpt開発入門】Next.jsで投資成長計算アプリを作成してみた🎵

## 概要:
本記事では、Next.jsを使用して、元金、年利、毎月の積立額を入力し、投資成長の計算結果をグラフ表示するアプリケーションの作成方法を紹介します。
## 前提条件とセットアップ
プロジェクトのセットアップ方法と前提条件を説明します。
### 前提条件
- Node.jsおよびnpmがインストールされていること

### プロジェクトのセットアップ
1. 新しいNext.jsプロジェクトを作成します：
    ```bash
    npx create-next-app investment-growth
    cd investment-growth
    npm install chart.js react-chartjs-2
    ```

2. 必要な依存関係をインストールします：
    ```bash
    npm install chart.js react-chartjs-2 japanize_matplotlib
    ```
## 基本的なページの作成
基本的なページの作成方法とコードの説明を行います。
### 基本的なページの作成
1. `pages/index.js`ファイルを作成し、以下のコードを追加します。

    ```jsx
    import React, { useState } from 'react';
    import { Line } from 'react-chartjs-2';
    import Chart from 'chart.js/auto';
    import { CategoryScale } from 'chart.js';
    import { calculateInvestmentGrowth } from '../utils/calculateInvestmentGrowth';
    
    // Chart.jsにCategoryScaleを登録する
    Chart.register(CategoryScale);
    
    export default function Home() {
      const [principals, setPrincipals] = useState("15000000, 10000000");
      const [annualRates, setAnnualRates] = useState("15, 10");
      const [monthlyContributions, setMonthlyContributions] = useState("200000, 100000");
      const [years, setYears] = useState(10);
      const [results, setResults] = useState([]);
      const [chartData, setChartData] = useState({});
    
      const handleSubmit = (e) => {
        e.preventDefault();
        const principalList = principals.split(',').map(Number);
        const annualRateList = annualRates.split(',').map(Number);
        const monthlyContributionList = monthlyContributions.split(',').map(Number);
    
        const allValues = principalList.map(principal => 
          annualRateList.map(annualRate => 
            monthlyContributionList.map(monthlyContribution => 
              ({ principal, annualRate, monthlyContribution, values: calculateInvestmentGrowth(principal, annualRate, monthlyContribution, years) })
            )
          )
        ).flat(2);
        setResults(allValues);
    
        const labels = Array.from({ length: years + 1 }, (_, i) => i);
        const datasets = allValues.map(data => ({
          label: `元金 ${data.principal / 10000}万円, 年利 ${data.annualRate}%, 毎月積立 ${data.monthlyContribution / 10000}万円`,
          data: data.values,
          fill: false,
          borderColor: `#${Math.floor(Math.random()*16777215).toString(16)}`,  // ランダムな色を使用
        }));
        
        const data = {
          labels,
          datasets,
        };
        setChartData(data);
      };
    
      return (
        <div>
          <h1>投資成長計算アプリ</h1>
          <form onSubmit={handleSubmit}>
            <div>
              <label>元金（円）</label>
              <input
                type="text"
                value={principals}
                onChange={(e) => setPrincipals(e.target.value)}
              />
            </div>
            <div>
              <label>年利（%）</label>
              <input
                type="text"
                value={annualRates}
                onChange={(e) => setAnnualRates(e.target.value)}
              />
            </div>
            <div>
              <label>毎月積立額（円）</label>
              <input
                type="text"
                value={monthlyContributions}
                onChange={(e) => setMonthlyContributions(e.target.value)}
              />
            </div>
            <div>
              <label>期間（年）</label>
              <input
                type="number"
                value={years}
                onChange={(e) => setYears(Number(e.target.value))}
              />
            </div>
            <button type="submit">計算</button>
          </form>
    
          {results.length > 0 && (
            <div>
              <h2>結果</h2>
              <Line data={chartData} />
              {results.map((result, index) => (
                <div key={index}>
                  <h3>元金 {result.principal / 10000}万円, 年利 {result.annualRate}%, 毎月積立 {result.monthlyContribution / 10000}万円</h3>
                  <table>
                    <thead>
                      <tr>
                        <th>年数</th>
                        <th>資産額 (円)</th>
                      </tr>
                    </thead>
                    <tbody>
                      {result.values.map((value, i) => (
                        <tr key={i}>
                          <td>{i}</td>
                          <td>{value}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              ))}
            </div>
          )}
        </div>
      );
    }
    ```

2. `utils/calculateInvestmentGrowth.js`ファイルを作成し、以下のコードを追加します。

    ```js
    export function calculateInvestmentGrowth(principal, annualRate, monthlyContribution, years) {
      const monthlyRate = annualRate / 12 / 100;
      const values = [principal];
      
      for (let year = 1; year <= years; year++) {
        let futureValue = values[values.length - 1];
        for (let month = 1; month <= 12; month++) {
          futureValue = (futureValue + monthlyContribution) * (1 + monthlyRate);
        }
        values.push(futureValue);
      }
      
      return values;
    }
    ```
## 実行手順
次に、プロジェクトの実行方法を説明します。
### プロジェクトの実行
以下のコマンドを実行して、ローカルホストでアプリケーションを起動します。

```bash
npm run dev
```

ブラウザで http://localhost:3000 にアクセスすると、投資成長計算アプリケーションが表示されます。


### 5. 結果とスクリーンショット

### 結果
以下は、
元金1500万円または1000万円、
年利15%,10％、
毎月の積立額20万円,10万円、
期間10年の例です。
![スクリーンショット_9-2-2025_183338_localhost.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/2cd8215c-356c-cf5e-bd83-031619da815a.jpeg)

### 開発において発生したエラーと回避
#### エラー１
```
以下のエラーが出ました、どうすればいいですか　Error: ./ App Router and Pages Router both match path: / Next.js does not support having both App Router and Pages Router routes matching the same path. Please remove one of the conflicting routes.
```
回答
```
App RouterまたはPages Routerのどちらかを削除:
appディレクトリまたはpagesディレクトリのどちらかを削除します。どちらを使うか決めたら、もう一方のディレクトリを削除してください。
```
回避：appを削除して実行できました。
#### エラー２
```
app を削除したら、実行できました。しかし、計算を押すと以下のエラーが出ました。　Error: "category" is not a registered scale.
```
回答
```
これは、Chart.jsのスケールタイプが正しく設定されていないことが原因です。この問題を解決するには、Chart.jsに必要なスケールを登録する必要があります。これを行うために、Chart.jsのregisterablesをインポートして登録します。

次に、pages/index.jsファイルを更新して、Chart.jsのスケールを正しく登録します。
```

コード回答。。。省略
この変更により、categoryスケールが正しく登録され、エラーが解消されるはずです。再度実行して確認してください。
### 最後に、ここでは詳細は省きますが、このnext.js版の前にpythonで同様なアプリを作りましたが、最初にいくつかエラーがでています。
特にグラフをChatGpt内で描画させましたが、でたらめなグラフを描画していました。
### グラフは描けますか
申し訳ありませんが、私はグラフを直接描くことはできません。しかし、グラフを作成するためのアドバイスやステップを提供することはできます。たとえば、ExcelやGoogle Sheetsなどのツールを使用して、データを視覚化する方法をお教えします。

ということで、出力された表からGoogleSheetで描画しました。

## まとめ
Next.jsを使用して、元金、年利、毎月の積立額を入力し、投資成長の計算結果をグラフ表示するアプリケーションを作成しました。この記事が参考になれば幸いです。