Webアプリ「出退勤管理アプリ」を作ってみた

【Webアプリ】出退勤管理アプリ⑥ 管理者画面の強化

次に管理者画面を強化していきます。

変更内容

内容説明
① 社員一覧を管理者画面で表示誰が登録されているかを一覧で見たい
② スタッフごとの過去の履歴も見たい日付ごとの出退勤履歴を社員ごとに確認

進め方のイメージ

順番に作っていきます。

  1. Firestoreに「社員リスト」を作成
  2. 管理者ページで社員一覧表示
  3. 各社員ごとに「今の出勤状況」を表示
  4. 社員をクリックすると「その人の履歴一覧ページ」にジャンプ

①最初のステップ:「社員リスト」を作ろう

Firestoreに「usersコレクション」を作成する

  • コレクション名:users
  • ドキュメント:社員ごとのデータ
  • データ例:
    • name: “田中 太郎”
    • email: “tanaka@example.com
    • role: “employee”(普通の社員ならemployee、管理者ならadmin)

🛠 Firestoreに手動で追加する方法

  1. Firebaseコンソールに行く
  2. Firestore Databaseを開く
  3. 「コレクションを開始」をクリック
  4. コレクションIDに users と入力
  5. ドキュメントIDは自動生成でもOK
  6. フィールドを追加:
    • name : “山田 太郎”(←社員名)
    • email : “yamada@example.com“(←社員のメールアドレス)
    • role : “employee”(←社員ならemployee)

これでOKです!

次にやること

管理者ページ(admin.html)で、
この users コレクションを読み込んで、社員一覧を表示します!

イメージ👇

名前メールアドレス出勤状況
山田 太郎yamada@example.com出勤中
佐藤 花子sato@example.com退勤済み

今あるadmin.htmlの <body> 部分をちょっと変えます👇

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>出退勤履歴一覧</title>
    <script src="https://www.gstatic.com/firebasejs/10.11.0/firebase-app-compat.js"></script>
    <script src="https://www.gstatic.com/firebasejs/10.11.0/firebase-firestore-compat.js"></script>
</head>
<body>
    <h1>管理者ページ</h1>

    <table border="1">
        <thead>
            <tr>
                <th>名前</th>
                <th>メールアドレス</th>
                <th>出勤状況</th>
            </tr>
        </thead>
        <tbody id="userList">
            <!-- ここに社員リストが表示される -->
        </tbody>
    </table>

    <script>
        // ここにFirebase設定と初期化を追加!!👇
        const firebaseConfig = {
            apiKey: "あなたのAPIキー",
            authDomain: "あなたのプロジェクトID.firebaseapp.com",
            projectId: "あなたのプロジェクトID",
            storageBucket: "あなたのプロジェクトID.appspot.com",
            messagingSenderId: "送信者ID",
            appId: "アプリID"
        };

        // Firebase初期化
        firebase.initializeApp(firebaseConfig);

        // Firestore使うよ
        const db = firebase.firestore();

        function loadUsers() {
            db.collection("users").get()
                .then((querySnapshot) => {
                    const userList = document.getElementById("userList");
                    userList.innerHTML = ""; // 一回クリア

                    querySnapshot.forEach((doc) => {
                        const user = doc.data();

                        // 出勤状況は今は仮で「不明」
                        const status = "不明";

                        const row = `
                            <tr>
                                <td>${user.name}</td>
                                <td>${user.email}</td>
                                <td>${status}</td>
                            </tr>
                        `;
                        userList.innerHTML += row;
                    });
                })
                .catch((error) => {
                    console.error("エラー:", error);
                });
        }

        // ページが開いたら実行
        window.onload = loadUsers;
    </script>
</body>
</html>

更に修正

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>出退勤履歴一覧</title>
</head>
<body>
  <h1>管理者ページ</h1>

  <table border="1">
    <thead>
      <tr>
        <th>名前</th>
        <th>メールアドレス</th>
        <th>出勤状況</th>
      </tr>
    </thead>
    <tbody id="userList"></tbody>

  <script type="module">
    import { initializeApp } from "https://www.gstatic.com/firebasejs/10.11.0/firebase-app.js";
    import {
      getFirestore,
      collection,
      getDocs,
      query,
      where,
      orderBy,
      limit
    } from "https://www.gstatic.com/firebasejs/10.11.0/firebase-firestore.js";

    const firebaseConfig = {
        apiKey: "あなたのAPIキー",
            authDomain: "あなたのプロジェクトID.firebaseapp.com",
            projectId: "あなたのプロジェクトID",
            storageBucket: "あなたのプロジェクトID.appspot.com",
            messagingSenderId: "送信者ID",
            appId: "アプリID"
    };

    const app = initializeApp(firebaseConfig);
    const db = getFirestore(app);

    async function loadUsers() {
      const userList = document.getElementById("userList");
      userList.innerHTML = "";

      try {
        const usersSnapshot = await getDocs(collection(db, "users"));

        for (const doc of usersSnapshot.docs) {
          const user = doc.data();
          const uid = doc.id;
          let status = "不明";

          try {
            const attendanceQuery = query(
              collection(db, "attendance"),
              where("uid", "==", uid),
              orderBy("timestamp", "desc"),
              limit(1)
            );
            const attendanceSnapshot = await getDocs(attendanceQuery);

            if (!attendanceSnapshot.empty) {
              const last = attendanceSnapshot.docs[0].data();
              status = last.type === "出勤" ? "出勤中" : "退勤済み";
            }
          } catch (e) {
            console.warn("出退勤データ取得エラー:", e);
          }

          const row = `
            <tr>
              <td>${user.name}</td>
              <td>${user.email}</td>
              <td>${status}</td>
            </tr>
          `;
          userList.innerHTML += row;
        }
      } catch (error) {
        console.error("ユーザーデータ取得エラー:", error);
      }
    }

    window.onload = loadUsers;
  </script>
</body>
</html>

✅【変更点①】Firebase SDKのモジュール方式への変更

比較項目一つ目のコード二つ目のコード
Firebaseの読み込み方法compatバージョン(古い互換モード)ESモジュール(モダン方式)
firebase.initializeApp(...)initializeApp(...)(ES6 import)

➕ メリット

  • 軽量&高速:モジュール式の方が不要な機能を除外できるため、読み込みが速くなります。
  • 最新仕様準拠:将来のメンテナンスがしやすく、ドキュメントもモジュール方式が主流。

✅【変更点②】出勤状況の取得機能追加

比較項目一つ目のコード二つ目のコード
出勤状況固定で「不明」attendance コレクションから最新のデータを取得し、出勤中 / 退勤済みを判定
使用したFirestore関数get()のみquery()where()orderBy()limit() を組み合わせて使用

➕ メリット

  • リアルタイムな出勤状況が表示可能
    • 最新の出退勤ログから判断して「今出勤中かどうか」を反映。
  • データベース設計の意図が明確に
    • uidで紐づけ、時系列でソート、1件取得という効率的で安全な取得処理。

✅【変更点③】async/await を使用した構造

比較項目一つ目のコード二つ目のコード
非同期処理の方法.then().catch()チェーンasync/awaitで直線的なロジック構造
可読性やや複雑より読みやすく保守しやすい

➕ メリット

  • 読みやすくエラー処理が簡潔:複雑な非同期ロジックでもエラーを1ヶ所で処理しやすい。

✅【その他の細かいメリット】

項目内容
セキュリティ最新SDKを使うことで、セキュリティ更新に追従しやすい。
クエリの最適化limit(1) で無駄なデータ取得を抑えている。

✅まとめ:変更の目的と効果

観点改善内容
モダン化Firebase SDKのモジュール化でパフォーマンス・可読性UP
機能強化出勤状況をリアルタイムに取得して、意味のある管理画面に進化
可読性・保守性async/await や構造的なクエリ設計で、今後の拡張やバグ修正がしやすい