Skip to content

Commit fe6359c

Browse files
committed
feat(i18n): apply i18n to contest details page
1 parent 7960ace commit fe6359c

7 files changed

Lines changed: 436 additions & 81 deletions

File tree

.agent/skills/feature/SKILL.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
name: gamers-fe-guide
3+
description: Comprehensive guide to the GAMERS-FE project structure, tech stack, and development patterns.
4+
---
5+
6+
# GAMERS-FE Project Skill
7+
8+
## Project Overview
9+
GAMERS-FE is a Next.js 16 application built with TypeScript and Tailwind CSS v4. It serves as the frontend for a gaming platform/community service, featuring contest management, user profiles, and game integrations (Valorant, LoL).
10+
11+
## Tech Stack
12+
- **Framework**: Next.js 16.1.1 (App Router)
13+
- **Language**: TypeScript 5.x
14+
- **Styling**:
15+
- Tailwind CSS v4
16+
- `clsx` & `tailwind-merge` for class management
17+
- Framer Motion & GSAP for animations
18+
- **State Management**:
19+
- React Query (`@tanstack/react-query`) for server state
20+
- React Context for global UI state
21+
- **Form Handling**: React Hook Form (`react-hook-form`) + Zod validation
22+
- **API Client**: Custom Axios wrapper (`@/lib/api-client`)
23+
- **I18n**: `i18next` & `react-i18next`
24+
- **Package Manager**: npm
25+
26+
## Directory Structure
27+
- `src/app`: Next.js App Router pages and layouts.
28+
- `src/components`:
29+
- `ui`: Reusable UI components (Buttons, Inputs, Modals).
30+
- `contest`: Contest-related components.
31+
- `admin`: Admin dashboard components.
32+
- `layout`: Layout components (Header, Footer).
33+
- `src/services`: API service modules.
34+
- `src/types`: TypeScript definitions, especially API responses (`api.ts`).
35+
- `src/lib`: Utility libraries and configurations (e.g., `api-client`).
36+
- `src/hooks`: Custom React hooks.
37+
- `src/utils`: Helper functions.
38+
- `src/locales`: i18n translation files.
39+
40+
## Key Development Patterns
41+
42+
### 1. API Integration
43+
- **Do not** make direct `fetch` or `axios` calls in components.
44+
- **Always** create a service function in `src/services/` using the `api` client.
45+
- Define request/response types in `src/types/api.ts`.
46+
- Use the `api` client from `@/lib/api-client`.
47+
48+
**Example:**
49+
`src/services/user-service.ts`
50+
```typescript
51+
import { api } from '@/lib/api-client';
52+
import { UserResponse, ApiResponse } from '@/types/api';
53+
54+
export const getUser = async (id: number) => {
55+
return api.get<ApiResponse<UserResponse>>(`/users/${id}`);
56+
};
57+
```
58+
59+
### 2. Styling Rules
60+
- Use Tailwind CSS utility classes found in `src/app/globals.css` (or implicitly via Tailwind v4).
61+
- Use the configured custom colors: `deep-black`, `neon-cyan`, `neon-purple`.
62+
- For conditional classes, use `cn()` (or `clsx` + `tailwind-merge`).
63+
64+
**Example:**
65+
```tsx
66+
import { cn } from "@/lib/utils"; // or explicit imports
67+
68+
<div className={cn("p-4 rounded-lg", isActive ? "bg-neon-cyan" : "bg-gray-800")}>
69+
Content
70+
</div>
71+
```
72+
73+
### 3. Component Structure
74+
- Use functional components with TypeScript interfaces for props.
75+
- Place reusable generic components in `src/components/ui`.
76+
- Place feature-specific components in `src/components/[feature]`.
77+
- Use `export default` or named exports consistently (check existing files).
78+
79+
### 4. Form Handling
80+
- Use `useForm` from `react-hook-form`.
81+
- Define validation schemas with `zod`.
82+
- Use `zodResolver` to integrate them.
83+
84+
### 5. Config Files
85+
- `next.config.ts`: Image domains (`images.unsplash.com`, `discord`, etc.) and redirects.
86+
- `tailwind.config.ts`: Custom theme extensions.
87+
88+
## Development Workflow
89+
- **Start Dev Server**: `npm run dev`
90+
- **Build for Production**: `npm run build`
91+
- **Lint Code**: `npm run lint`
92+
93+
## Critical Rules
94+
1. **Never** use `any` type implicitly or explicitly if possible.
95+
2. **Always** check `swagger.yaml` or backend docs before creating new API types.
96+
3. **Follow** the existing folder structure when adding new files.

.agent/skills/review/SKILL.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
name: code-review
3+
description: standard code review guidelines for GAMERS-FE
4+
---
5+
6+
# Code Review Skill
7+
8+
Use this skill when reviewing Pull Requests or code snippets for the GAMERS-FE project.
9+
10+
## 1. General Checklist
11+
- [ ] **Functionality**: Does the code perform the intended task correctly?
12+
- [ ] **Requirements**: Does it satisfy the user's request or the ticket description?
13+
- [ ] **Bugs**: Are there any obvious logic errors or potential edge cases missing?
14+
- [ ] **Security**: detailed check for sensitive data leakage or unsafe patterns.
15+
16+
## 2. Project-Specific Rules (GAMERS-FE)
17+
Verify these specific patterns are followed:
18+
19+
### Architecture & Structure
20+
- **API Calls**: Ensure no direct `fetch/axios` in components. All API logic must be in `src/services/` using the `@/lib/api-client`.
21+
- **Directory Structure**:
22+
- UI components -> `src/components/ui`
23+
- Feature components -> `src/components/[feature]`
24+
- Pages -> `src/app`
25+
- **Imports**: Check for absolute imports (`@/...`) instead of relative `../../`.
26+
27+
### TypeScript & Types
28+
- **No `any`**: Strictly forbid `any`. Look for proper interfaces/types.
29+
- **API Types**: Request/Response types should be defined in `src/types/api.ts`.
30+
- **Props**: Component props must be typed explicitly.
31+
32+
### Styling (Tailwind CSS)
33+
- **Utility Classes**: Ensure standard Tailwind classes are used.
34+
- **Custom Colors**: Verify usage of `neon-cyan`, `deep-black`, `neon-purple` logic instead of hardcoded hex values where applicable.
35+
- **Class Merging**: Check for `cn(...)` usage when merging external `className` props.
36+
37+
### React & Next.js
38+
- **Server vs Client**: Is `use client` used only when necessary?
39+
- **Images**: Are `next/image` components used with proper `width/height` or `fill`?
40+
- **Hooks**: Are custom hooks used for complex logic?
41+
- **Performance**: Check for unnecessary re-renders or heavy computations in render path.
42+
43+
## 3. Style & Naming
44+
- **Components**: `PascalCase` (e.g., `ContestCard.tsx`)
45+
- **Functions/Variables**: `camelCase`
46+
- **Constants**: `UPPER_SNAKE_CASE`
47+
- **Files**: match the export (e.g., component file matches component name).
48+
49+
## 4. Review Etiquette
50+
- **Be Constructive**: "Have you considered X?" instead of "Change this to X."
51+
- **Explain "Why"**: Provide context for your suggestions.
52+
- **Praise**: Point out good code patterns as well.

src/components/contest/ContestDetailClient.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use client';
2+
import { useTranslation } from 'react-i18next';
23

34
import React from 'react';
45
import { useQuery } from '@tanstack/react-query';
@@ -9,6 +10,7 @@ import { Loader2, AlertCircle } from 'lucide-react';
910
import { useParams } from 'next/navigation';
1011

1112
export default function ContestDetailClient({ contestId }: { contestId: string }) {
13+
const { t } = useTranslation();
1214
const { data: contestResponse, isLoading, error } = useQuery({
1315
queryKey: ['contest', contestId],
1416
queryFn: () => contestService.getContest(Number(contestId)),
@@ -28,8 +30,8 @@ export default function ContestDetailClient({ contestId }: { contestId: string }
2830
return (
2931
<div className="min-h-screen flex flex-col items-center justify-center text-white gap-4">
3032
<AlertCircle className="w-12 h-12 text-red-500" />
31-
<h1 className="text-2xl font-bold">大会情報の読み込みに失敗しました</h1>
32-
<p className="text-neutral-400">URLを確認するか、しばらく経ってから再度お試しください。</p>
33+
<h1 className="text-2xl font-bold">{t('contestPlayground.loadingFail', 'Failed to load contest info')}</h1>
34+
<p className="text-neutral-400">{t('contestPlayground.retry', 'Please check the URL or try again later.')}</p>
3335
</div>
3436
);
3537
}

src/components/contest/PlaygroundHeader.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useGSAP } from '@gsap/react';
66
import { Gamepad2 } from 'lucide-react';
77
import Image from 'next/image';
88
import { ContestResponse } from '@/types/api';
9+
import { useTranslation } from 'react-i18next';
910

1011
gsap.registerPlugin(useGSAP);
1112

@@ -14,6 +15,7 @@ interface PlaygroundHeaderProps {
1415
}
1516

1617
export default function PlaygroundHeader({ contest }: PlaygroundHeaderProps) {
18+
const { t } = useTranslation();
1719
const containerRef = useRef<HTMLDivElement>(null);
1820
const bgRef = useRef<HTMLDivElement>(null);
1921
const contentRef = useRef<HTMLDivElement>(null);
@@ -61,7 +63,7 @@ export default function PlaygroundHeader({ contest }: PlaygroundHeaderProps) {
6163
{contest.title}
6264
</h1>
6365
<p className="header-content-item text-neutral-400 text-sm md:text-base uppercase tracking-widest border border-neon-purple/50 px-4 py-1 rounded-full bg-deep-black/50 backdrop-blur-sm">
64-
プレイグラウンド
66+
{t('contestPlayground.header.label', 'Playground')}
6567
</p>
6668
</div>
6769
</section>

0 commit comments

Comments
 (0)