1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.jsを企業向けに最適化!2025年のアプリ構築術 | エピソード4: 管理ダッシュボードの構築

Posted at

目標

  • Next.jsで管理ダッシュボードを作成する。
  • Chart.jsを使ってデータを視覚化する。
  • 管理者権限を設定し、ダッシュボードを保護する。

1. 企業向けアプリにおけるダッシュボードの役割

企業向けアプリでは、管理者がデータを監視・管理するためのダッシュボードが重要です。このエピソードでは、ブログに管理者専用のダッシュボードを追加し、投稿数やユーザー統計を視覚化します。


2. 必要なライブラリのインストール

視覚化のためにChart.jsを導入します。

手順:

ターミナルで以下を実行:

npm install chart.js react-chartjs-2

3. ダッシュボードページの作成

管理者向けのダッシュボードを実装します。

app/admin/dashboard/page.tsxの作成:

'use client';

import { useSession } from 'next-auth/react';
import { redirect } from 'next/navigation';
import { supabase } from '../../../lib/supabase';
import { Bar } from 'react-chartjs-2';
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend } from 'chart.js';

ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend);

export default function Dashboard() {
  const { data: session } = useSession();

  if (!session || session.user?.email !== 'admin@example.com') {
    redirect('/'); // 管理者以外はリダイレクト
  }

  const fetchStats = async () => {
    const { data: posts } = await supabase.from('posts').select('created_at');
    const { data: users } = await supabase.from('users').select('id');
    return { posts: posts || [], users: users || [] };
  };

  const stats = await fetchStats();

  const postDates = stats.posts.reduce((acc, post) => {
    const date = new Date(post.created_at).toLocaleDateString('ja-JP');
    acc[date] = (acc[date] || 0) + 1;
    return acc;
  }, {});

  const chartData = {
    labels: Object.keys(postDates),
    datasets: [
      {
        label: '投稿数',
        data: Object.values(postDates),
        backgroundColor: 'rgba(54, 162, 235, 0.6)',
      },
    ],
  };

  return (
    <div className="max-w-4xl mx-auto p-6">
      <h1 className="text-3xl font-bold text-blue-600 mb-6">管理ダッシュボード</h1>
      <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
        <div className="bg-white p-4 rounded shadow">
          <h2 className="text-xl font-semibold mb-4">投稿統計</h2>
          <Bar data={chartData} options={{ responsive: true }} />
        </div>
        <div className="bg-white p-4 rounded shadow">
          <h2 className="text-xl font-semibold mb-4">ユーザー情報</h2>
          <p>総ユーザー数: {stats.users.length}</p>
        </div>
      </div>
    </div>
  );
}

ナビゲーションに追加:

app/layout.tsxを編集:

import '../globals.css';
import Link from 'next/link';
import { useTranslation } from 'next-i18next';
import { i18n } from 'next-i18next';
import { auth } from 'next-auth';
import { signIn, signOut } from 'next-auth/react';

export const metadata = {
  title: 'Next.js 2025ブログ',
  description: '2025年の最新技術で作られたブログサイト',
};

export default async function RootLayout({ children }) {
  const { t } = useTranslation('common');
  const session = await auth();

  return (
    <html lang={i18n?.language}>
      <body className="font-sans antialiased">
        <header className="bg-blue-800 text-white p-4">
          <nav className="max-w-4xl mx-auto flex justify-between items-center">
            <Link href="/" className="text-xl font-bold">{t('home')}</Link>
            <div className="space-x-4">
              <Link href="/about" className="hover:underline">{t('about')}</Link>
              <Link href="/add-post" className="hover:underline">{t('addPost')}</Link>
              {session?.user?.email === 'admin@example.com' && (
                <Link href="/admin/dashboard" className="hover:underline">ダッシュボード</Link>
              )}
              <Link href="/" locale="ja" className="hover:underline">日本語</Link>
              <Link href="/" locale="en" className="hover:underline">English</Link>
              {session ? (
                <>
                  <span>{session.user?.name}</span>
                  <button onClick={() => signOut()} className="hover:underline">ログアウト</button>
                </>
              ) : (
                <button onClick={() => signIn('google')} className="hover:underline">Googleでログイン</button>
              )}
            </div>
          </nav>
        </header>
        <main>{children}</main>
        <footer className="bg-gray-200 p-4 text-center text-gray-600">
          © 2025 Next.js学習シリーズ
        </footer>
      </body>
    </html>
  );
}

実践:管理者ダッシュボード

  • 統計:投稿数の棒グラフを表示。
  • ユーザー情報:登録ユーザー数を表示。
  • 保護:管理者(例:admin@example.com)のみアクセス可能。

確認

  • npm run devで起動し、http://localhost:3000/admin/dashboardで管理者ログイン後に表示を確認。

エピソード4の終了

  • 管理ダッシュボードを作成し、データを視覚化しました。
  • 管理者権限でアクセスを保護しました。

次回のエピソード:Redisでスケーラビリティを強化し、大規模運用に対応します。


この記事が役に立ったと思ったら、ぜひ「いいね」を押して、ストックしていただければ嬉しいです!次回のエピソードもお楽しみに!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?