Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 107 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1195,12 +1195,118 @@ None / [Description si applicable]
- [ ] Mettre à jour `package.json` (version)
- [ ] Mettre à jour `README.md` (badge version)
- [ ] Ajouter une entrée dans `VERSIONS.md`
- [ ] Créer le fichier de release dans `release-notes/vX.X.X.md`
- [ ] Mettre à jour footer de `AGENTS.md` (date + version + status)
- [ ] Tester en local (dev + build)
- [ ] Tester en Docker (si applicable)

---

## 📦 GitHub Release Notes Guidelines

### Format Standardisé

Chaque release doit avoir un fichier `release-notes/vX.X.X.md` suivant ce format :

**Titre de Release** : `X.X.X (Month DD, YYYY)`

**Titre de Description** : `[Emoji] LolTimeFlash vX.X.X - [Feature Name]`

**Structure** :

```markdown
X.X.X (Month DD, YYYY)

[Emoji] LolTimeFlash vX.X.X - [Feature Name]

### 🔄 Overview

[1-2 phrases résumant la release]

### ✨ What's New (ou 🐛 Bug Fixes / ♻️ Refactoring selon le type)

- **Feature/Fix Name**: Description
- **Feature/Fix Name**: Description

### 📝 Documentation (si applicable)

- Doc change 1
- Doc change 2

### 📦 Technical Changes

**Backend** (si applicable):

- Change 1
- Change 2

**Frontend** (si applicable):

- Change 1
- Change 2

**Modified Files**:
| File | Changes |
|------|---------|
| `path/to/file` | Description |

### 🎯 Impact

[Description de l'impact utilisateur/développeur]

---

**Full Changelog**: https://github.com/yourusername/LolTimeFlash/compare/vX.X.X...vY.Y.Y
```

### Exemples par Type de Release

**MAJOR (X.0.0)** : Breaking changes, architecture majeure

- Emoji titre: 🚀 ou 📦
- Sections: Overview, Breaking Changes, New Features, Migration Guide, Technical Changes, Impact
- Exemple: `🚀 LolTimeFlash v2.0.0 - NestJS Monorepo Architecture`

**MINOR (X.Y.0)** : Nouvelles features, améliorations

- Emoji titre: ✨
- Sections: Overview, What's New, Documentation, Technical Changes, Impact
- Exemple: `✨ LolTimeFlash v2.3.0 - Timer Calibration Controls & UX Polish`

**PATCH (X.Y.Z)** : Bug fixes, hotfixes, optimizations

- Emoji titre: 🐛 (fixes) ou ⚙️ (refactor) ou 📝 (docs)
- Sections: Overview, Bug Fixes/Refactoring, Documentation, Technical Changes, Impact
- Exemple: `⚙️ LolTimeFlash v2.3.1 - Username Storage Refactor`

### Publication sur GitHub

1. Créer le tag Git :

```bash
git tag -a vX.X.X -m "Release vX.X.X"
git push origin vX.X.X
```

2. Créer la release sur GitHub :
- Aller sur Releases → Draft a new release
- Choisir le tag `vX.X.X`
- Titre : `X.X.X (Month DD, YYYY)`
- Description : Copier le contenu de `release-notes/vX.X.X.md`
- Publier

### Fichiers à Mettre à Jour

Pour chaque release :

1. `package.json` - Version number
2. `README.md` - Badge version
3. `VERSIONS.md` - Entrée historique détaillée
4. `release-notes/vX.X.X.md` - Notes de release GitHub
5. `AGENTS.md` - Footer (date + version + status)

---

## 📖 Additional Resources

### External Documentation
Expand Down Expand Up @@ -1697,5 +1803,5 @@ For questions, issues, or contributions:
---

**Last Updated**: November 24, 2025
**Version**: 2.3.1 - Username Storage Refactor
**Version**: 2.3.2 - Username Validation & Lobby Refactor
**Status**: ✅ Production Ready (API + Web + Docker + Timer Sync + Calibration)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

**League of Legends Website Tool: Easily Time and Communicate Summoner Spells - THE FLASH! 🌟**

[![Version](https://img.shields.io/badge/version-2.3.1-brightgreen?style=flat)](https://github.com/yourusername/LolTimeFlash/releases)
[![Version](https://img.shields.io/badge/version-2.3.2-brightgreen?style=flat)](https://github.com/yourusername/LolTimeFlash/releases)
[![Next.js](https://img.shields.io/badge/Next.js-16.0.1-black?style=flat&logo=next.js)](https://nextjs.org/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.7.2-blue?style=flat&logo=typescript)](https://www.typescriptlang.org/)
[![Socket.IO](https://img.shields.io/badge/Socket.IO-4.8.1-010101?style=flat&logo=socket.io)](https://socket.io/)
Expand Down
51 changes: 51 additions & 0 deletions VERSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,57 @@

## 📚 Version History

### Version 2.3.2 - November 2025 (Username Validation & Lobby Refactor)

**New Features** :

- ✨ **Username Length Validation** : Validation stricte 3-12 caractères (backend + frontend)
- 🎨 **Visual Validation Feedback** : Indicateurs check/croix en temps réel avec feedback couleur
- 🏗️ **Lobby Architecture Refactor** : Réécriture complète en composants atomiques mémorisés
- ⚡ **Performance Improvements** : Mémorisation des composants réduit les re-renders

**Security** :

- 🔐 **Backend Validation** : Protection contre la manipulation localStorage (username > 12 chars rejeté)

**Technical Changes** :

**Backend** :
- Nouveau fichier : `apps/api/libs/shared/src/constants/username.ts` (MIN/MAX constants)
- Mise à jour : `JoinRoomDto` validation (3-12 caractères avec constantes locales)

**Frontend** :
- Nouveau composant : `UsernameValidationFeedback.component.tsx` (feedback réutilisable)
- Nouveaux composants lobby : `CreateLobbyForm`, `JoinLobbyForm`, `LobbyDivider`
- Refactoring : `app/lobby/page.tsx` (134 → 28 lignes, -78%)
- Architecture : Pattern `features/` avec barrel exports
- Mémorisation : `React.memo()` sur tous les nouveaux composants

**Fichiers Modifiés** :

| Fichier | Changements |
| ---------------------------------------------------------- | -------------------------------------------- |
| `apps/api/libs/shared/src/constants/username.ts` | **Created** - Constantes longueur username |
| `apps/api/src/game/dto/join-room.dto.ts` | Validation 3-12 caractères |
| `apps/web/features/settings/components/username-validation-feedback.component.tsx` | **Created** - Composant feedback |
| `apps/web/features/lobby/components/create-lobby-form.component.tsx` | **Created** - Form création |
| `apps/web/features/lobby/components/join-lobby-form.component.tsx` | **Created** - Form join |
| `apps/web/features/lobby/components/lobby-divider.component.tsx` | **Created** - Divider mémorisé |
| `apps/web/features/lobby/components/index.ts` | **Created** - Barrel exports |
| `apps/web/app/lobby/page.tsx` | **Refactored** - Réduction de 78% |
| `features/settings/components/username-input-modal.component.tsx` | Intégration feedback validation |
| `app/settings/page.tsx` | Intégration feedback validation |

**Impact** :

- ✅ Sécurité renforcée (validation backend)
- ✅ UX améliorée (feedback visuel instantané)
- ✅ Architecture propre (composants atomiques)
- ✅ Performance optimisée (mémorisation)
- ✅ Maintenabilité accrue (code -78% sur lobby)

---

### Version 2.3.1 - November 2025 (Username Storage Refactor)

**Refactoring & Optimization** :
Expand Down
1 change: 1 addition & 0 deletions apps/api/libs/shared/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './cooldowns';
export * from './roles';
export * from './username';
2 changes: 2 additions & 0 deletions apps/api/libs/shared/src/constants/username.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const MAX_USERNAME_LENGTH: number = 12;
export const MIN_USERNAME_LENGTH: number = 3;
9 changes: 7 additions & 2 deletions apps/api/src/game/dto/join-room.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { IsString, IsNotEmpty, Length, Matches } from 'class-validator';
import { IsNotEmpty, IsString, Length, Matches } from 'class-validator';

const MIN_USERNAME_LENGTH = 3;
const MAX_USERNAME_LENGTH = 12;

export class JoinRoomDto {
@IsString()
Expand All @@ -11,6 +14,8 @@ export class JoinRoomDto {

@IsString()
@IsNotEmpty()
@Length(3, 20, { message: 'Username must be between 3 and 20 characters' })
@Length(MIN_USERNAME_LENGTH, MAX_USERNAME_LENGTH, {
message: `Username must be between ${MIN_USERNAME_LENGTH} and ${MAX_USERNAME_LENGTH} characters`,
})
username: string;
}
124 changes: 9 additions & 115 deletions apps/web/app/lobby/page.tsx
Original file line number Diff line number Diff line change
@@ -1,133 +1,27 @@
'use client'

import { useState } from 'react'

import { useRouter } from 'next/navigation'
import Link from 'next/link'

import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { useToast } from '@/hooks/use-toast.hook'
import {
CreateLobbyForm,
JoinLobbyForm,
LobbyDivider,
} from '@/features/lobby/components'

import { RxTrackPrevious } from 'react-icons/rx'
import { GrFormNextLink } from 'react-icons/gr'
import { FaCopy } from 'react-icons/fa'
import { cn, generateLobbyCodeId } from '@/lib/utils'

export default function Home() {
const router = useRouter()
const { toast } = useToast()

const [joinLobbyCode, setJoinLobbyCode] = useState<string>('')
const [lobbyCode, setLobbyCode] = useState<string>('')
const [isError, setIsError] = useState<boolean>(false)

function createLobbyCode() {
const code: string = generateLobbyCodeId(10)
setLobbyCode(code)
}

export default function LobbyPage() {
return (
<main className="flex min-h-screen flex-col items-center justify-center gap-8 p-20 sm:flex sm:flex-row sm:justify-around sm:gap-0">
<Link className="fixed left-6 top-6 sm:left-20 sm:top-10" href={'/'}>
<Button variant="outline" size="icon">
<RxTrackPrevious className="h-4 w-4" />
</Button>
</Link>
{/* CREATE LOBBY */}
<div className="flex flex-col items-center justify-center gap-4 sm:w-1/3 sm:gap-8">
<h1 className="text-xl">Create a Lobby</h1>
{!lobbyCode && (
<Button variant="outline" onClick={() => createLobbyCode()}>
Create Lobby
</Button>
)}
{lobbyCode && (
<div className="flex w-full flex-col items-center justify-start gap-4">
<p>Your lobby code is :</p>
<div className="flex items-center justify-center gap-1">
<Input
className="bg-background font-sans"
type="text"
placeholder="Flash Timer"
value={lobbyCode || ''}
readOnly
/>
<Button
variant="outline"
size="icon"
onClick={() => {
if (lobbyCode) {
navigator.clipboard.writeText(lobbyCode)
toast({
title:
'Your lobby code has been copied to your clipboard!',
})
}
}}
>
<FaCopy className="h-4 w-4" />
</Button>
</div>
<Button
onClick={() => {
router.push(`/game/${lobbyCode}`)
}}
variant="outline"
size="icon"
>
<GrFormNextLink className="h-4 w-4" />
</Button>
</div>
)}
</div>
{/* BORDER */}
<div className="h-[1px] w-4/5 bg-slate-500 sm:h-[600px] sm:w-[1px]"></div>
{/* JOIN LOBBY */}
<div className="flex flex-col items-center justify-center gap-4 sm:w-1/3 sm:gap-8">
<h1 className="text-xl">Join a Lobby</h1>
<form
className="flex items-center justify-center gap-4"
onSubmit={(e) => {
e.preventDefault()
if (joinLobbyCode.length === 10) {
router.push(`/game/${joinLobbyCode}`)
} else {
setIsError(true)
}
}}
>
<Input
type="text"
className="bg-background font-sans"
placeholder="Enter lobby code"
value={joinLobbyCode}
onChange={(e) => setJoinLobbyCode(e.target.value)}
/>
<Button
variant="outline"
size="icon"
onClick={() => {
if (joinLobbyCode.length === 10) {
router.push(`/game/${joinLobbyCode}`)
} else {
setIsError(true)
}
}}
>
<GrFormNextLink className="h-4 w-4" />
</Button>
</form>
{isError && (
<p
className={cn('text-xs font-bold text-red-700', {
'text-green-500': joinLobbyCode.length === 10,
})}
>
The lobby code must be 10 characters, {joinLobbyCode.length} actual.
</p>
)}
</div>
<CreateLobbyForm />
<LobbyDivider />
<JoinLobbyForm />
</main>
)
}
Loading
Loading