GoとReact+TypeScriptで筋トレメニュー表を作ろう！

## はじめに
初めましての人もそうでない人もこんにちは！

最近暑くなりすぎて我が家の冷凍庫がアイスの箱で埋め尽くされています！

毎日のようにアイスを食べていたらあらびっくり！
体重がめちゃんこ増えてました！

こんなだらしない体では恥ずかしくて海水浴に行けません！(漢心ピ〜ンチ♂)
かなりやばいのでそろそろ筋トレを始める時期だと思っています！

どうせならプログラミングを駆使して筋トレメニュー表を作ることで技術力向上と夢のマッスルボディの両方を鍛えたいです！

そこで今回は筋トレメニュー表をGoとReactを使って作ってみました！
ぜひ最後までご覧ください！

## 今回使う技術
### フロントエンド
React + TypeScript ・ Css

### バックエンド
Go

## 準備をしよう！
```
kintore
├─ backend
|  └─ main.go
├─ frontend
|  └─ src
|     └─ App.tsx
|     └─ App.css
├─　・・・
・・・
```

今回主に使うディレクトリ構成としてはこんな感じです！

まず「kintore」というフォルダを作ってください！
次にkintoreディレクトリに入ったターミナルで
```
npx create-react-app frontend --template typescript
mkdir backend
cd backend
go mod init
```
を入力してください！

これで準備は完了です！
それでは作っていきましょう！

## 作ってみよう！
### バックエンド
まずは回数を出力させたりどんなトレーニングを行うか決めていきましょう！
backendフォルダーの中にmain.goというファイルを作成して以下のコードをコピペしてください！
```backend/main.go
package main

import (
	"encoding/json"
	"math/rand"
	"net/http"
	"time"
)

type Exercise struct {
	Name  string `json:"name"`
	Count int    `json:"count"`
}

var exercises = []string{"腕立て伏せ", "腹筋", "背筋", "腿上げ", "懸垂"}

func getRandomExercises(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")

	var randomExercises []Exercise
	for _, exercise := range exercises {
		count := rand.Intn(100) + 1
		randomExercises = append(randomExercises, Exercise{Name: exercise, Count: count})
	}

	json.NewEncoder(w).Encode(randomExercises)
}

func main() {
	rand.Seed(time.Now().UnixNano())
	http.HandleFunc("/exercises", getRandomExercises)
	http.ListenAndServe(":8080", nil)
}
```
これで筋トレメニューとその回数を出力させる処理ができました！
このコードではあらかじめ腕立て伏せなどトレーニング方法を用意してそれぞれの実施回数を1~100までの回数をランダムに出力させてくれます。

あとは画面を作成するだけです！頑張りましょう！

### フロントエンド

画面を作成する前に以下のコマンドをターミナルに入力してください
```
npm install axios
```

```frontend/src/App.tsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './App.css'; // CSSファイルをインポート

interface Exercise {
  name: string;
  count: number;
  completed: boolean;
}

const App: React.FC = () => {
  const [exercises, setExercises] = useState<Exercise[]>([]);
  const [allCompleted, setAllCompleted] = useState(false);

  const getRandomExercises = async () => {
    try {
      const response = await axios.get('http://localhost:8080/exercises');
      const exercisesWithCompletion = response.data.map((exercise: Exercise) => ({
        ...exercise,
        completed: false
      }));
      setExercises(exercisesWithCompletion);
      setAllCompleted(false); 
    } catch (error) {
      console.error('Error fetching exercises:', error);
    }
  };

  const toggleCompletion = (index: number) => {
    setExercises(prevExercises =>
      prevExercises.map((exercise, i) =>
        i === index ? { ...exercise, completed: !exercise.completed } : exercise
      )
    );
  };

  useEffect(() => {
    // すべての筋トレが完了しているかどうかをチェック
    const allCompleted = exercises.length > 0 && exercises.every(exercise => exercise.completed);
    setAllCompleted(allCompleted);
  }, [exercises]);

  return (
    <div>
      <h1>1日の筋トレメニュー作成表</h1>
      <button onClick={getRandomExercises}>メニュー表を作る</button>
      {exercises.length > 0 ? (
        <>
          <ul className="exercise-list">
            {exercises.map((exercise, index) => (
              <li key={index} className="exercise-item">
                <div className="exercise-block">
                  {exercise.name}: {exercise.count} 回
                  <input
                    type="checkbox"
                    checked={exercise.completed}
                    onChange={() => toggleCompletion(index)}
                    className="exercise-checkbox"
                  />
                </div>
              </li>
            ))}
          </ul>
          {allCompleted && <h2>Excellent! 明日もその調子で頑張ろう！</h2>}
        </>
      ) : (
        <p>さあボタンをクリックして目標を決めよう！</p>
      )}
    </div>
  );
};

export default App;
```

モチベーションを高めるため筋トレが終わったらチェックボックスをクリックして全てにチェックが付いたらエクセレント!・・・と表示させるようにしました！
これで動かすことは可能ですがデザインをより良くするためにcssをいじりたいと思います！

```frontend/src/App.css
.App {
  text-align: center;
}

.exercise-list {
  display: flex;
  flex-wrap: wrap;
  list-style-type: none; /* リストスタイルを削除 */
  padding: 0; /* デフォルトのパディングを削除 */
  margin: 0; /* デフォルトのマージンを削除 */
}

.exercise-item {
  margin: 10px;
}

.exercise-block {
  border: 1px solid #ccc;
  padding: 10px;
  display: flex;
  align-items: center;
}

.exercise-checkbox {
  margin-left: 10px; /* チェックボックスとテキストの間にスペースを追加 */
}
```

これでコーディングは終了です！

### 実行方法
ターミナルを2つ用意してfrontendディレクトリには以下のコマンドを
```
npm start
```
backendディレクトリには以下のコマンドを入力してください
```
go run main.go
```

これで操作することができるはずです！

## おわりに
いやー大変疲れましたねー
前からぼちぼちGO言語の学習を進めていた程度なので個人開発に使うにはカロリーを使いましたねw
おかげで筋トレメニュー表を作っている間にアイスをたくさん食べてしまいました!
筋トレメニュー表を作るために摂取したカロリーをメニュー表を使って消費したいと思います！

またどこかの記事でお会いしましょう！

## Github URL
https://github.com/FrohleinYoshie/kintore