プロジェクト

全般

プロフィール

バグ #950

未完了

【948-2】フロントエンド基盤実装 - React/TypeScript/Tailwind

Redmine Admin さんが2ヶ月前に追加.

ステータス:
新規
優先度:
急いで
担当者:
-
開始日:
2025-07-31
期日:
進捗率:

0%

予定工数:

説明

【子チケット2】フロントエンド基盤実装

🎯 目的

React + TypeScript + Tailwind CSSベースのフロントエンド基盤を実装し、既存の画面設計を統合する。

📋 実装内容

1. フロントエンド基盤セットアップ

cd /root/form-automation-system/frontend

# Vite + React + TypeScript プロジェクト作成
npm create vite@latest . -- --template react-ts

# 必要パッケージインストール
npm install \
  @tailwindcss/forms \
  @headlessui/react \
  @heroicons/react \
  react-router-dom \
  zustand \
  @tanstack/react-query \
  react-hook-form \
  @hookform/resolvers \
  zod \
  recharts \
  date-fns \
  clsx \
  lucide-react

# 開発依存関係
npm install -D \
  tailwindcss \
  postcss \
  autoprefixer \
  @types/node \
  eslint \
  @typescript-eslint/eslint-plugin \
  @typescript-eslint/parser \
  prettier \
  prettier-plugin-tailwindcss

2. プロジェクト構造

frontend/
├── src/
│   ├── components/           # 再利用可能コンポーネント
│   │   ├── ui/              # 基本UIコンポーネント
│   │   ├── forms/           # フォームコンポーネント
│   │   ├── charts/          # グラフ・チャートコンポーネント
│   │   └── layout/          # レイアウトコンポーネント
│   ├── pages/               # ページコンポーネント
│   │   ├── Dashboard/       # ダッシュボード
│   │   ├── Tasks/           # タスク管理
│   │   ├── Data/            # データ管理
│   │   ├── Settings/        # 設定画面
│   │   └── Monitoring/      # 監視・ログ
│   ├── hooks/               # カスタムフック
│   ├── stores/              # Zustand状態管理
│   ├── services/            # API通信サービス
│   ├── types/               # TypeScript型定義
│   ├── utils/               # ユーティリティ関数
│   └── styles/              # CSS・Tailwind設定
├── public/                  # 静的ファイル
├── Dockerfile               # 本番用Dockerfile
├── Dockerfile.dev           # 開発用Dockerfile
└── package.json

3. 主要設定ファイル

Tailwind設定(tailwind.config.js)

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      colors: {
        // LINEデザイン言語準拠カラーパレット
        'line-green': {
          50: '#f0fdf4',
          100: '#dcfce7',
          200: '#bbf7d0',
          300: '#86efac',
          400: '#4ade80',
          500: '#06c755', // LINE Primary Green
          600: '#059142',
          700: '#047836',
          800: '#065f46',
          900: '#064e3b',
        },
        'line-gray': {
          50: '#f9fafb',
          100: '#f3f4f6',
          200: '#e5e7eb',
          300: '#d1d5db',
          400: '#9ca3af',
          500: '#6b7280',
          600: '#4b5563',
          700: '#374151',
          800: '#1f2937',
          900: '#111827',
        }
      },
      fontFamily: {
        'sans': ['Inter', 'system-ui', 'sans-serif'],
      },
      animation: {
        'fade-in': 'fadeIn 0.5s ease-in-out',
        'slide-up': 'slideUp 0.3s ease-out',
        'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
      },
    },
  },
  plugins: [
    require('@tailwindcss/forms'),
  ],
}

TypeScript設定(tsconfig.json)

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@/components/*": ["./src/components/*"],
      "@/pages/*": ["./src/pages/*"],
      "@/hooks/*": ["./src/hooks/*"],
      "@/stores/*": ["./src/stores/*"],
      "@/services/*": ["./src/services/*"],
      "@/types/*": ["./src/types/*"],
      "@/utils/*": ["./src/utils/*"]
    }
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

4. 基本コンポーネント実装

レイアウトコンポーネント(src/components/layout/Layout.tsx)

import React from 'react';
import { Outlet } from 'react-router-dom';
import { Sidebar } from './Sidebar';
import { Header } from './Header';

export const Layout: React.FC = () => {
  return (
    <div className="min-h-screen bg-gray-50">
      <Sidebar />
      <div className="lg:pl-64">
        <Header />
        <main className="py-6">
          <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
            <Outlet />
          </div>
        </main>
      </div>
    </div>
  );
};

サイドバーナビゲーション

import React from 'react';
import { NavLink } from 'react-router-dom';
import {
  HomeIcon,
  CogIcon,
  ChartBarIcon,
  DocumentTextIcon,
  ClipboardDocumentListIcon,
} from '@heroicons/react/24/outline';

const navigation = [
  { name: 'ダッシュボード', href: '/', icon: HomeIcon },
  { name: 'タスク管理', href: '/tasks', icon: ClipboardDocumentListIcon },
  { name: 'データ管理', href: '/data', icon: DocumentTextIcon },
  { name: '監視・ログ', href: '/monitoring', icon: ChartBarIcon },
  { name: '設定', href: '/settings', icon: CogIcon },
];

export const Sidebar: React.FC = () => {
  return (
    <div className="hidden lg:fixed lg:inset-y-0 lg:z-50 lg:flex lg:w-64 lg:flex-col">
      <div className="flex grow flex-col gap-y-5 overflow-y-auto border-r border-gray-200 bg-white px-6 pb-4">
        <div className="flex h-16 shrink-0 items-center">
          <h1 className="text-xl font-bold text-line-green-500">
            Form Automation
          </h1>
        </div>
        <nav className="flex flex-1 flex-col">
          <ul role="list" className="flex flex-1 flex-col gap-y-7">
            <li>
              <ul role="list" className="-mx-2 space-y-1">
                {navigation.map((item) => (
                  <li key={item.name}>
                    <NavLink
                      to={item.href}
                      className={({ isActive }) =>
                        clsx(
                          isActive
                            ? 'bg-line-green-50 text-line-green-600'
                            : 'text-gray-700 hover:text-line-green-600 hover:bg-gray-50',
                          'group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold'
                        )
                      }
                    >
                      <item.icon className="h-6 w-6 shrink-0" />
                      {item.name}
                    </NavLink>
                  </li>
                ))}
              </ul>
            </li>
          </ul>
        </nav>
      </div>
    </div>
  );
};

5. 状態管理(Zustand)

アプリケーション状態

// src/stores/appStore.ts
import { create } from 'zustand';

interface AppState {
  isLoading: boolean;
  error: string | null;
  user: User | null;
  setLoading: (loading: boolean) => void;
  setError: (error: string | null) => void;
  setUser: (user: User | null) => void;
}

export const useAppStore = create<AppState>((set) => ({
  isLoading: false,
  error: null,
  user: null,
  setLoading: (loading) => set({ isLoading: loading }),
  setError: (error) => set({ error }),
  setUser: (user) => set({ user }),
}));

タスク状態管理

// src/stores/taskStore.ts
import { create } from 'zustand';

interface TaskState {
  tasks: Task[];
  runningTasks: Task[];
  completedTasks: Task[];
  selectedTask: Task | null;
  fetchTasks: () => Promise<void>;
  createTask: (task: CreateTaskRequest) => Promise<void>;
  updateTask: (id: string, updates: Partial<Task>) => Promise<void>;
  deleteTask: (id: string) => Promise<void>;
  setSelectedTask: (task: Task | null) => void;
}

export const useTaskStore = create<TaskState>((set, get) => ({
  tasks: [],
  runningTasks: [],
  completedTasks: [],
  selectedTask: null,
  fetchTasks: async () => {
    // API実装
  },
  createTask: async (task) => {
    // API実装
  },
  updateTask: async (id, updates) => {
    // API実装
  },
  deleteTask: async (id) => {
    // API実装
  },
  setSelectedTask: (task) => set({ selectedTask: task }),
}));

6. API通信サービス

API基盤クライアント

// src/services/api.ts
import axios from 'axios';

const API_BASE_URL = import.meta.env.VITE_API_URL || '/api';

export const apiClient = axios.create({
  baseURL: API_BASE_URL,
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Request interceptor
apiClient.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('auth_token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// Response interceptor
apiClient.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('auth_token');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

7. ルーティング設定

// src/App.tsx
import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Layout } from '@/components/layout/Layout';
import { Dashboard } from '@/pages/Dashboard';
import { Tasks } from '@/pages/Tasks';
import { Data } from '@/pages/Data';
import { Settings } from '@/pages/Settings';
import { Monitoring } from '@/pages/Monitoring';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<Layout />}>
            <Route index element={<Dashboard />} />
            <Route path="tasks/*" element={<Tasks />} />
            <Route path="data/*" element={<Data />} />
            <Route path="settings/*" element={<Settings />} />
            <Route path="monitoring/*" element={<Monitoring />} />
          </Route>
        </Routes>
      </BrowserRouter>
    </QueryClientProvider>
  );
}

export default App;

✅ 完了条件

基盤セットアップ

  • Vite + React + TypeScript プロジェクト作成
  • 必要パッケージインストール完了
  • Tailwind CSS設定完了

プロジェクト構造

  • ディレクトリ構造作成
  • 基本設定ファイル配置
  • TypeScript設定完了

基本コンポーネント

  • Layout・Header・Sidebar実装
  • ナビゲーション機能実装
  • 基本UIコンポーネント実装

状態管理・ルーティング

  • Zustand状態管理セットアップ
  • React Router設定
  • API通信基盤実装

動作確認

  • 開発サーバー起動確認
  • 基本ページ表示確認
  • ナビゲーション動作確認

🔄 次のステップ

フロントエンド基盤完了後、子チケット3(バックエンドAPI実装)に移行。


Claude Code実行プロンプト:

フォーム自動化システムのフロントエンド基盤を実装してください。React + TypeScript + Tailwind CSS + Zustand構成で、既存の画面設計仕様を継承し、LINEデザイン言語準拠のモダンなUIを構築してください。ディレクトリ構造作成から基本コンポーネント実装まで段階的に進め、各ステップの完了を報告してください。

表示するデータがありません

他の形式にエクスポート: Atom PDF