feat(tournaments): enhance age eligibility logic and date parsing
- Improved the getCutoffDate method to derive cutoff dates from performance class if not explicitly provided. - Updated getAgeLimitFromText to handle various age class formats, returning structured age limit objects. - Introduced getBirthYearFromPerformanceClass to extract birth year information from performance class strings. - Refined isEligibleByAge to incorporate new eligibility rules based on performance class and age limits, ensuring accurate age validation for tournament participation.
This commit is contained in:
@@ -1117,7 +1117,13 @@ export default {
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
},
|
||||
getCutoffDate(c) {
|
||||
return this.parseDateFlexible(c.cutoffDate || c.stichtag || '');
|
||||
let val = c.cutoffDate || c.stichtag || '';
|
||||
if (!val && (c.performanceClass || c.leistungsklasse)) {
|
||||
const pc = String(c.performanceClass || c.leistungsklasse || '');
|
||||
const m = pc.match(/stichtag\s*:?\s*([0-3]?\d\.[01]?\d\.\d{4})/i);
|
||||
if (m) val = m[1].trim();
|
||||
}
|
||||
return this.parseDateFlexible(val);
|
||||
},
|
||||
getMemberBirthDate(member) {
|
||||
return this.parseDateFlexible(member.birthDate || '');
|
||||
@@ -1128,14 +1134,20 @@ export default {
|
||||
if (fromStart) return this.parseDateFlexible(fromStart[1]);
|
||||
return this.parseDateFlexible(this.parsed?.parsedData?.termin || '');
|
||||
},
|
||||
// Uxx oder AK xx erkennen -> Maximalalter in Jahren
|
||||
// Uxx, Jugend N, Mädchen N, AK xx erkennen -> { limit, exclusive }
|
||||
// exclusive=true: Alter < limit (U12); exclusive=false: Alter <= limit (Jugend 12)
|
||||
getAgeLimitFromText(text) {
|
||||
if (!text) return null;
|
||||
const t = String(text).toUpperCase();
|
||||
let m = t.match(/\bU\s*(\d{1,2})\b/);
|
||||
if (m) return Number(m[1]);
|
||||
m = t.match(/\bAK\s*(\d{1,2})\b/);
|
||||
if (m) return Number(m[1]);
|
||||
const t = String(text);
|
||||
// Jugend 12 / Mädchen 12: max Alter 12 (Alter <= 12)
|
||||
let m = t.match(/(?:jugend|mädchen|maedchen)\s+(\d{1,2})\b/i);
|
||||
if (m) return { limit: Number(m[1]), exclusive: false };
|
||||
// U12: unter 12 (Alter < 12)
|
||||
m = t.match(/\bU\s*(\d{1,2})\b/i);
|
||||
if (m) return { limit: Number(m[1]), exclusive: true };
|
||||
// AK 12 nur wenn nicht in Klammern wie (AK1) - (AK1) ist Kategorie-Nr, nicht Alter
|
||||
const akMatch = t.match(/\bAK\s*(\d{1,2})\b/i);
|
||||
if (akMatch && !/\(\s*AK\s*\d+\s*\)/i.test(t)) return { limit: Number(akMatch[1]), exclusive: true };
|
||||
return null;
|
||||
},
|
||||
calculateAgeOnDate(birthDate, refDate) {
|
||||
@@ -1152,17 +1164,46 @@ export default {
|
||||
if (/jugend/.test(txt)) return 'both';
|
||||
return 'both';
|
||||
},
|
||||
getBirthYearFromPerformanceClass(c) {
|
||||
const pc = c.performanceClass || c.leistungsklasse || '';
|
||||
const s = String(pc);
|
||||
// "Jahrgang 2017 und jünger" -> minBirthYear 2017 (geboren 2017 oder später)
|
||||
const mUndJünger = s.match(/jahrgang\s+(\d{4})\s+und\s+jünger/i);
|
||||
if (mUndJünger) return { minYear: Number(mUndJünger[1]) };
|
||||
// "Jahrgang 2014" -> exakt Jahr 2014
|
||||
const mExact = s.match(/jahrgang\s+(\d{4})\b/i);
|
||||
if (mExact) return { exact: Number(mExact[1]) };
|
||||
return null;
|
||||
},
|
||||
isEligibleByAge(member, c) {
|
||||
const cutoff = this.getCutoffDate(c);
|
||||
const bd = this.getMemberBirthDate(member);
|
||||
if (cutoff) {
|
||||
if (!bd || !(bd.getTime() > cutoff.getTime())) return false; // jünger als Stichtag
|
||||
if (!bd) return false;
|
||||
|
||||
// 1. Jahrgang YYYY (z.B. "Jahrgang 2014") oder "Jahrgang 2017 und jünger"
|
||||
const birthYearRule = this.getBirthYearFromPerformanceClass(c);
|
||||
if (birthYearRule != null) {
|
||||
const memberYear = bd.getFullYear();
|
||||
if (birthYearRule.exact != null) return memberYear === birthYearRule.exact;
|
||||
if (birthYearRule.minYear != null) return memberYear >= birthYearRule.minYear;
|
||||
}
|
||||
const limit = this.getAgeLimitFromText((c.ageClassCompetition || c.altersklasseWettbewerb || ''));
|
||||
if (limit != null) {
|
||||
|
||||
// 2. Stichtag (z.B. "01.01.2014 und jünger") -> geboren nach Stichtag
|
||||
const cutoff = this.getCutoffDate(c);
|
||||
if (cutoff) {
|
||||
if (!(bd.getTime() > cutoff.getTime())) return false; // jünger = geboren nach Stichtag
|
||||
}
|
||||
|
||||
// 3. Alterslimit aus Titel (Jugend 12, U12, AK 12)
|
||||
const ageLimit = this.getAgeLimitFromText((c.ageClassCompetition || c.altersklasseWettbewerb || ''));
|
||||
if (ageLimit != null) {
|
||||
const ref = this.getReferenceDate(c);
|
||||
const age = this.calculateAgeOnDate(bd, ref);
|
||||
if (age == null || !(age < limit)) return false; // Uxx => Alter < xx
|
||||
if (age == null) return false;
|
||||
if (ageLimit.exclusive) {
|
||||
if (!(age < ageLimit.limit)) return false; // U12: Alter < 12
|
||||
} else {
|
||||
if (!(age <= ageLimit.limit)) return false; // Jugend 12: Alter <= 12
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
@@ -1195,50 +1236,7 @@ export default {
|
||||
const yyyy = d.getFullYear();
|
||||
return `${dd}.${mm}.${yyyy}`;
|
||||
},
|
||||
// Eligibility helpers
|
||||
parseDateFlexible(s) {
|
||||
if (!s || typeof s !== 'string') return null;
|
||||
const t = s.trim();
|
||||
let m = t.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
|
||||
if (m) {
|
||||
const d = new Date(Number(m[3]), Number(m[2]) - 1, Number(m[1]));
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
m = t.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||||
if (m) {
|
||||
const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
const d = new Date(t);
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
},
|
||||
getCutoffDate(c) {
|
||||
return this.parseDateFlexible(c.cutoffDate || c.stichtag || '');
|
||||
},
|
||||
getMemberBirthDate(member) {
|
||||
return this.parseDateFlexible(member.birthDate || '');
|
||||
},
|
||||
getGenderRule(c) {
|
||||
const txt = `${c.ageClassCompetition || c.altersklasseWettbewerb || ''} ${c.openTo || c.offenFuer || ''}`.toLowerCase();
|
||||
if (/(mädchen|weiblich|\bw\b)/.test(txt)) return 'female';
|
||||
if (/(jungen|männlich|\bm\b)/.test(txt)) return 'male';
|
||||
if (/jugend/.test(txt)) return 'both';
|
||||
return 'both';
|
||||
},
|
||||
isEligibleForCompetition(member, c) {
|
||||
const rule = this.getGenderRule(c);
|
||||
const g = member.gender || 'unknown';
|
||||
if (rule === 'female' && g !== 'female') return false;
|
||||
if (rule === 'male' && g !== 'male') return false;
|
||||
const cutoff = this.getCutoffDate(c);
|
||||
if (cutoff) {
|
||||
const bd = this.getMemberBirthDate(member);
|
||||
if (!bd) return false;
|
||||
if (!(bd.getTime() > cutoff.getTime())) return false; // jünger als Stichtag => geboren nach Stichtag
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
|
||||
async removeTournament(t) {
|
||||
const confirmed = await this.showConfirm(
|
||||
'Turnier löschen',
|
||||
|
||||
Reference in New Issue
Block a user