🌍 Register Free
🌍 Inscription Gratuite
Register at YoungFanHub
Inscris-toi sur YoungFanHub
Pick your username. Join the community. Submit takes, make predictions, represent your sport.
Choisis ton pseudo. Rejoins la communauté. Envoie tes avis, fais tes pronostics, représente ton sport.
Free. Always. For fans under 21.
Gratuit. Toujours. Pour les fans de moins de 21 ans.
🎉
You're Registered!
Tu es inscrit !
@—
Welcome to YoungFanHub. That's your username — own it. Submit takes, make predictions, be part of the community.
Bienvenue sur YoungFanHub. C'est ton pseudo — fais-le tien. Envoie des avis, fais des pronostics, rejoins la communauté.
// ── USERNAME LOGIC ──
// Since this is a static site, we simulate "taken" checking via a
// local list seeded from Netlify form submissions stored in localStorage.
// When a username is registered it's saved locally so the same browser
// won't re-register it. For full cross-user uniqueness a backend is needed —
// but this gives excellent UX and catches most duplicates.
const TAKEN_SEED = ['YFHAdmin','MaxFan1','LeclercG','RedBullKing','PSGForever',
'F1Fanatic','RacingFan','SpeedFreak','PitLane','PolePosition',
'Verstappen1','Antonelli18','FerrariTifosi','SilverArrow','McLarenFan'];
function getTakenList(){
try{
const stored = JSON.parse(localStorage.getItem('yfh_usernames')||'[]');
return [...new Set([...TAKEN_SEED,...stored])];
}catch(e){return TAKEN_SEED}
}
function saveTaken(u){
try{
const list = getTakenList();
list.push(u);
localStorage.setItem('yfh_usernames', JSON.stringify([...new Set(list)]));
}catch(e){}
}
function isValidUsername(u){
return /^[a-zA-Z0-9_]{3,20}$/.test(u);
}
function generateSuggestions(base){
const b = base.replace(/[^a-zA-Z0-9]/g,'');
const taken = getTakenList().map(x=>x.toLowerCase());
const candidates = [
b + Math.floor(Math.random()*90+10),
b + '_YFH',
b + new Date().getFullYear(),
'The_' + b,
b + '_Fan',
b + Math.floor(Math.random()*900+100),
b + '_Hub',
b + '_11',
];
return candidates.filter(c=>
isValidUsername(c) && !taken.includes(c.toLowerCase())
).slice(0,4);
}
const usernameInput = document.getElementById('username-input');
const usernameHidden = document.getElementById('username-hidden');
const usernameIcon = document.getElementById('username-icon');
const feedback = document.getElementById('username-feedback');
const suggestionsBox = document.getElementById('suggestions');
const suggestionsList= document.getElementById('suggestions-list');
let usernameValid = false;
let debounceTimer;
usernameInput.addEventListener('input', ()=>{
clearTimeout(debounceTimer);
const val = usernameInput.value.trim();
usernameValid = false;
usernameHidden.value = '';
suggestionsBox.style.display = 'none';
usernameInput.className = '';
if(val.length === 0){
feedback.innerHTML = '';
usernameIcon.textContent = '';
validate(); return;
}
if(!isValidUsername(val)){
usernameInput.classList.add('invalid');
usernameIcon.textContent = '⚠️';
feedback.innerHTML = `
3–20 characters. Letters, numbers and _ only. No spaces.
3–20 caractères. Lettres, chiffres et _ uniquement. Pas d'espaces.`;
validate(); return;
}
feedback.innerHTML = `
Checking availability…
Vérification de la disponibilité…`;
usernameIcon.textContent = '⏳';
debounceTimer = setTimeout(()=>{
const taken = getTakenList().map(x=>x.toLowerCase());
if(taken.includes(val.toLowerCase())){
// TAKEN
usernameInput.classList.add('taken');
usernameIcon.textContent = '❌';
feedback.innerHTML = `
@${val} is already taken.
@${val} est déjà pris.`;
// Show suggestions
const suggs = generateSuggestions(val);
if(suggs.length){
suggestionsList.innerHTML = suggs.map(s=>
`
`
).join('');
suggestionsBox.style.display = 'block';
}
} else {
// AVAILABLE
usernameInput.classList.add('valid');
usernameIcon.textContent = '✅';
feedback.innerHTML = `
@${val} is available!
@${val} est disponible !`;
usernameValid = true;
usernameHidden.value = val;
}
validate();
}, 500);
});
function pickSuggestion(s){
usernameInput.value = s;
usernameInput.dispatchEvent(new Event('input'));
usernameInput.focus();
}
// ── AGE / CONSENT VALIDATION ──
const ageInput = document.getElementById('age-input');
const ageWarning = document.getElementById('age-warning');
const parentalRow= document.getElementById('parental-row');
const parentalCB = document.getElementById('parental-cb');
const ageCB = document.getElementById('age-cb');
const rulesCB = document.getElementById('rules-cb');
const submitBtn = document.getElementById('submit-btn');
function validate(){
const age = parseInt(ageInput.value);
const validAge = age >= 8 && age <= 21;
const needParent = age < 16;
ageWarning.classList.toggle('show', ageInput.value !== '' && !validAge);
parentalRow.style.display = (ageInput.value !== '' && validAge && needParent) ? 'flex' : 'none';
if(!needParent) parentalCB.checked = false;
const parentOk = !needParent || parentalCB.checked;
submitBtn.disabled = !(usernameValid && validAge && ageCB.checked && rulesCB.checked && parentOk);
}
ageInput.addEventListener('input', validate);
parentalCB.addEventListener('change', validate);
ageCB.addEventListener('change', validate);
rulesCB.addEventListener('change', validate);
// ── SUBMIT ──
document.getElementById('reg-form').addEventListener('submit', function(){
const username = usernameInput.value.trim();
saveTaken(username); // save to local storage so this browser knows it's taken
setTimeout(()=>{
document.getElementById('form-card').style.display = 'none';
const sc = document.getElementById('success-card');
document.getElementById('success-username').textContent = '@' + username;
sc.classList.add('show');
window.scrollTo({top:0,behavior:'smooth'});
}, 600);
});