Skip to content
Closed
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,5 @@ output.css
**/src/SmartContract/dump.rdb
make/scripts/certs/certs
.venv
*.ai
docs/welcomPage.jpg
18 changes: 7 additions & 11 deletions srcs/nginx/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { ProfilePage } from './pages/ProfilePage';
import { LoginPage } from './pages/LoginRegisterPage';
import { useAuth } from './providers/AuthProvider';
import { AnimationPage } from './pages/AnimationPage';
import { WelcomePage } from './pages/WelcomePage';

const GuestRoute = ({ children }: { children: React.ReactNode }) => {
const { user, isLoggedIn } = useAuth();
if (user && isLoggedIn) {
return <Navigate to={`/profile/${user.username}`} replace />;
return <Navigate to={`/welcome`} replace />;
// return <Navigate to={`/profile/${user.username}`} replace />;
}
return children;
};
Expand All @@ -24,22 +26,16 @@ export const App = () => {
<main className="h-screen bd-slate-950 text-slate-100">
<Routes>
<Route path="/" element={<AnimationPage />}></Route>
<Route
path="/signup"
element={
<GuestRoute>
<LoginPage isRegister={true} />
</GuestRoute>
}
/>
<Route

<Route path="/welcome" element={<WelcomePage />} />
{/* <Route
path="/login"
element={
<GuestRoute>
<LoginPage isRegister={false} />
</GuestRoute>
}
/>
/> */}
<Route path="/me" element={<MeRedirect />}></Route>
<Route path="/profile/:username" element={<ProfilePage />}></Route>
</Routes>
Expand Down
28 changes: 28 additions & 0 deletions srcs/nginx/src/components/molecules/CircleButton.tsx
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c'est du détail, si ça n'inclut pas d'autres composants, ce serait à ranger dans atoms plutôt que molécules

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { motion } from 'framer-motion';

interface CircleButtonProps {
children?: React.ReactNode;
}

const dropdownStyle = 'shadow-[0_10px_10px_1px_rgba(205,205,205,0.4)] ';

export const CircleButton = ({ children }: CircleButtonProps) => (
<motion.div
whileHover={{ scale: 1.1, color: '#029c8a' }}
whileTap={{ scale: 0.95, color: '#ff0088' }}
transition={{ duration: 0.3 }}
className={`
basis-50
h-56 m-10 p-6
aspect-square
rounded-full
bg-slate-100/80
flex items-center justify-center
font-quantico border border-cyan-300
text-gray-700
${dropdownStyle}
`}
>
<p className="text-2xl text-center whitespace-nowrap">{children}</p>
</motion.div>
);
40 changes: 40 additions & 0 deletions srcs/nginx/src/components/molecules/Halo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useState } from 'react';
import { RegisterForm } from '../organisms/RegisterForm';
import { LoginForm } from '../organisms/LoginForm';
import Circle from '../atoms/Circle';
import { useTranslation } from 'react-i18next';

interface HaloProps {
isRegister: boolean;
className?: string;
size?: number;
onToggleForm: () => void; // Add this line
}
const Halo = ({ className = '', size = 80, isRegister, onToggleForm }: HaloProps) => {
const [isHovered, setIsHovered] = useState(false);
const { t } = useTranslation();
const title = isRegister ? t('auth.signup') : t('auth.login');

return (
<div
className={`absolute ${className}`}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<Circle size={isHovered ? size : 30} className="cursor-pointer p-8">
{/* PLAY text */}
<span className={`text-2xl font-bold ${isHovered ? 'hidden' : 'block'}`}>PLAY</span>

{/* Forms */}
<div className={`min-h-[100px] ${isHovered ? 'block' : 'hidden'}`}>
{isRegister ? (
<RegisterForm onToggleForm={onToggleForm} />
) : (
<LoginForm onToggleForm={onToggleForm} />
)}
</div>
</Circle>
</div>
);
};
export default Halo;
16 changes: 8 additions & 8 deletions srcs/nginx/src/components/organisms/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ async function loginAction(prevState: LoginState | null, formData: FormData) {
}
}

export const LoginForm = () => {
export const LoginForm = ({ onToggleForm }: { onToggleForm?: () => void }) => {
const { t } = useTranslation();
const [state, formAction, isPending] = useActionState(loginAction, null);
const navigate = useNavigate();
Expand All @@ -88,10 +88,12 @@ export const LoginForm = () => {
if (state?.success && state.fields?.username) {
const username = state.fields.username;
login({ username: username, avatarUrl: null });
navigate(`/profile/${username}`, { replace: true });
// navigate(`/profile/${username}`, { replace: true });
navigate(`/welcome`, { replace: true });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Je ne suis pas sûr que rajouter une page soit la meilleure solution.
Il faudrait plutôt mettre une variable dans le local storage pour ne pas rejouer l'animation et que cette page soit directement intégrée à la racine.
Car lorsque nous ajouterons le retour à l'accueil, lors du clic sur le logo du site, c'est mieux d'aller directement à la racine plutôt que /welcome.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L'animation n'est pas geré dans cette PR (mis en place par francois) je ne m'en occupe pas, elle est mis en place sur la racine. Cela pourrait etre vu par la suite ? On s'etait mis d'accord pour avoir une welcome page (qui remplace /login et /signup), si ca ne te semble pas pertinent, il faudrai que tu propose une autre solution clair (et c'est bien de le proposé avant qu'on se mette a coder). Le display de la page d'acceuil pourrait tres bien se faire a la racine '/' mais la racine est deja dedié a l'animation de bienvenue. Nous pouvons redirer sur '/welcome' en cliquant sur le logo. Nous suivons le plans ce qui a été énoncé aux reunions, tu trouveras un shema UIX dans le discord ! Cette PR permet d'avoir un acces simple au /game/* afin d'avoir un developpement plus aisé de celui ci, et de construire un debut d'UIX final.

Il est préferable, d'arriver sur la welcome Page plutot que sur la page profile en premier lieux.(basique UIX)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

La welcome page et la racine c'est la même chose.
L'animation se lance qu'au premier lancement., elle peut très bien cohabiter avec le bouton play un peu comme le isHovered
Lorsque tu clique sur le logo d'un site il te redirige vers l'accueil genre toto.fr mais jamais toto.fr/welcome
il n'est pas question d'arriver sur /profile mais juste la racine avec le bouton play
Ce que je disais c'est qu'il ne faut pas rajouter une page

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, je comprends ton point de vue, et le fait qu'une page en plus ne te semble pas pertinent. Cepandant, laisse moi rectifier certains concepts...

Non, la welcomePage (ou landing page) et la racine (ou nom de domaine) ne sont pas forcément la meme chose, elles peuvent l'etre, mais ce n'est pas systématique.

La pattern 'www.example.com/landingpage' est régulierement utilisé sur le web (on retrouve souvent une page 'langue', derriere le nom de domaine, qui fait office de landing page). Sur certains site web, quand tu tape le nom de domaine www.example.com, tu es redirigé sur une landing page --> www.example.com/landing_page

exemple:
https://www.facebook.com/?locale=fr_FR
https://www.microsoft.com/fr-fr
https://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Accueil_principal --> (this one is a good one!)
https://www.sap.com/france/index.html
(il y en a pleins d'autres...)

Dans notre cas (pour le moment) la racine est utilisé pour jouer une animation.

Le fait d'avoir une landing page a la racine ou sur une page differente ne change pas grands chose sur notre projet (voir absolument rien).

Si tu veux qu'on reste a la racine, il faudrai modifier les '/welcome' en '/' , c'est pas grands chose à faire en soit mais comme il y a l'animation sur le '/' il faut gerer ca, et comme je te le disais, ce n'est pas dans le scope de ma PR (less is more ;) ).

Ceci dit, je pense que c'est facilement faisable d'associer l'animation + landing page a la racine, mais je ne voit pas pourquoi changer ce comportement (ca ne joue ni sur le rendus du site, ni sur notre eval). Personnellement je trouve que ca marche tres bien comme ca, et je vois pas pourquoi changer (l'animation qu'a fait francois est tres bien a la racine, why not ?) ! Mais on peut toujours le modifier si tu y tiens vraiment ?

So what should we do ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, ton point de vue m'a convaincu.
Je trouvais juste que les outils de React nous évitaient d'avoir de nombreuses pages et que nous gardions l'esprit du SPA

}
if (user?.username) {
navigate(`/profile/${user.username}`, { replace: true });
// navigate(`/profile/${username}`, { replace: true });
navigate(`/welcome`, { replace: true });
}
}, [state?.success, state?.fields?.username, user, navigate, login]);
return (
Expand Down Expand Up @@ -119,11 +121,9 @@ export const LoginForm = () => {

<div className="text-xs text-gray-500 mt-5">
{t('auth.noAccount')}{' '}
<span>
<Link className="hover:text-blue-400" to={`/signup`}>
{t('auth.signup')}
</Link>
</span>
<button type="button" onClick={onToggleForm} className="hover:text-blue-400 underline">
{t('auth.signup')}
</button>
</div>
</form>
);
Expand Down
17 changes: 8 additions & 9 deletions srcs/nginx/src/components/organisms/RegisterForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,24 +112,25 @@ async function signupAction(prevState: SignupState | null, formData: FormData) {
return nextState;
}
}

export const RegisterForm = () => {
export const RegisterForm = ({ onToggleForm }: { onToggleForm?: () => void }) => {
const { t } = useTranslation();
const [state, formAction, isPending] = useActionState(signupAction, null);
const navigate = useNavigate();
const { user, login, isLoggedIn } = useAuth();

useEffect(() => {
if (user && isLoggedIn) {
navigate(`/profile/${user.username}`);
// navigate(`/profile/${user.username}`);
navigate(`/welcome`);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idem register form

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idem -> soit on reviens a la racine '/' avec l'animation, soit sur /welcome, mais pas sur /profile

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oui racine

Copy link
Collaborator Author

@Ilia1177 Ilia1177 Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Il y a une discussion sur le discord, a propos de l'UIX design, ou on parle de la navigation user et du comportement du front. Ce sujet (WelcomePage) a été abordé, et a été validé avec françois. On se retrouve sur le channel pour en parler plus précisement ! C'est toujours mieux d'en parler en amont, plutot que sur les PRs (quand c'est possible).

}
}, [user, isLoggedIn]);

useEffect(() => {
if (state?.success && state.fields?.username) {
const username = state.fields?.username;
login({ username: username, avatarUrl: null });
navigate(`/profile/${username}`);
// navigate(`/profile/${username}`);
navigate(`/welcome`);
}
}, [state?.success, state?.fields?.username, navigate]);

Expand Down Expand Up @@ -167,11 +168,9 @@ export const RegisterForm = () => {

<div className="text-xs text-gray-500 mt-5">
{t('auth.hasAccount')}{' '}
<span>
<Link className="hover:text-blue-400" to={`/login`}>
{t('auth.login')}
</Link>
</span>
<button type="button" onClick={onToggleForm} className="hover:text-blue-400 underline">
{t('auth.login')}
</button>
</div>
</form>
);
Expand Down
2 changes: 1 addition & 1 deletion srcs/nginx/src/hooks/AxiosInterceptor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const AxiosInterceptor = ({ children }: { children: React.ReactNode }) =>
(response) => response,
(error) => {
if (error.statusCode === HTTP_STATUS.UNAUTHORIZED) {
navigate('/login');
navigate('/welcome');
}
return Promise.reject(error);
},
Expand Down
5 changes: 5 additions & 0 deletions srcs/nginx/src/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,10 @@
"copyright": "© 2026 . All rights reserved.",
"privacyPolicy": "Privacy Policy",
"termsOfService": "Terms of Service"
},
"game": {
"playWithAI": "Play with AI",
"playWithFriends": "Play with Friends",
"tournament": "Tournament"
}
}
5 changes: 5 additions & 0 deletions srcs/nginx/src/locales/fr/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,10 @@
"copyright": "© 2026 Tous droits réservés.",
"privacyPolicy": "Politique de confidentialité",
"termsOfService": "Conditions d'utilisation"
},
"game": {
"playWithAI": "Joue avec un ROBOT (no friends?)",
"playWithFriends": "Joue avec ton copaing",
"tournament": "Defi tes potes en tournois"
Comment on lines +71 to +73
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"playWithAI": "Joue avec un ROBOT (no friends?)",
"playWithFriends": "Joue avec ton copaing",
"tournament": "Defi tes potes en tournois"
"playWithAI": "Match IA",
"playWithFriends": "Jouer contre un ami",
"tournament": "Tournoi"

}
}
5 changes: 5 additions & 0 deletions srcs/nginx/src/locales/tf/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,10 @@
"copyright": "© 2026 – C'est à nous.",
"privacyPolicy": "La loi du milieu (on balance rien, t'es en sécurité)",
"termsOfService": "Les règles du jeu (lis ça, sinon t’es un rigolo)"
},
"game": {
"playWithAI": "No friends? Joue avec un ROBOT",
"playWithFriends": "Joue avec ton copaing",
"tournament": "Defi tes potes en tournois"
Comment on lines +70 to +73
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

il faudrait des titres plus courts

Suggested change
"game": {
"playWithAI": "No friends? Joue avec un ROBOT",
"playWithFriends": "Joue avec ton copaing",
"tournament": "Defi tes potes en tournois"
"game": {
"playWithAI": "Seul ? Tape le bot",
"playWithFriends": "Entouré ? Tape ton pote",
"tournament": "Compét"

}
}
2 changes: 1 addition & 1 deletion srcs/nginx/src/pages/AnimationPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const AnimationPage = ({ className = '' }: AnimationPageProps) => {

useEffect(() => {
if (animDone) {
navigate(`/login`);
navigate(`/welcome`);
}
}, [animDone, user]);

Expand Down
91 changes: 91 additions & 0 deletions srcs/nginx/src/pages/WelcomePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { NavBar } from '../components/molecules/NavBar'; // Adjust path based on your folder structure
import Halo from '../components/molecules/Halo';
import { Link } from 'react-router-dom';
import Background from '../components/atoms/Background';
import { useTranslation } from 'react-i18next';
import { RegisterForm } from '../components/organisms/RegisterForm';
import { LoginForm } from '../components/organisms/LoginForm';
import { useState } from 'react';
import Circle from '../components/atoms/Circle';
import { CircleButton } from '../components/molecules/CircleButton';
import { useAuth } from '../providers/AuthProvider';

const colors = {
start: '#00ff9f',
end: '#0088ff',
};

interface LoginRegisterPageProps {
isRegister: boolean;
}
export const WelcomePage = () => {
const { t } = useTranslation();
const [isRegister, setIsRegister] = useState(false);
const { user, isLoggedIn } = useAuth();

const ai = t('game.playWithAI');
const tournament = t('game.tournament');
const friends = t('game.playWithFriends');
return (
<div className={`w-full h-full relative`}>
<Background
grainIntensity={4}
baseFrequency={0.28}
colorStart={colors.start}
colorEnd={colors.end}
>
<NavBar />
{/* Not logged in - show login/register */}
{!isLoggedIn && (
<Halo
size={80}
isRegister={isRegister}
onToggleForm={() => setIsRegister(!isRegister)}
className="top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
/>
)}
{/* Logged in - show 3 game options */}
{isLoggedIn && (
<div className=" flex flex-1 items-center justify-center">
<div className="flex flex-col sm:flex-row gap-4">
<Link to="/game/pong-ai">
<CircleButton>{ai}</CircleButton>
</Link>

<Link to="/game/simple-game">
<CircleButton>{friends}</CircleButton>
</Link>

<Link to="/game/tournament">
<CircleButton>{tournament}</CircleButton>
</Link>
</div>
</div>
)}
</Background>
</div>
);
};
// export const WelcomePage = () => {
// const { t } = useTranslation();
// const [isRegister, setIsRegister] = useState(false);
// const title = isRegister ? t('auth.signup') : t('auth.login');
// return (
// <div className={`w-full h-full relative`}>
// <Background
// grainIntensity={4}
// baseFrequency={0.28}
// colorStart={colors.start}
// colorEnd={colors.end}
// >
// <NavBar />
// <Halo
// size={200}
// isRegister={isRegister}
// onToggleForm={() => setIsRegister(!isRegister)}
// className="top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
// />
// </Background>
// </div>
// );
// };
Loading