Maintain and update the co-parenting-portal (https://hanyunfan.github.io/co-parenting-portal), a Texas child custody schedule calculator for RRISD parents. Use when asked to update the calendar, fix custody rules, add school breaks, modify summer/winter/spring break handling, or apply any Texas Family Code logic to the portal. Also use when debugging calendar display issues, button failures, or ESPO weekend assignments.
Single-file app: index.html — all EN/CN i18n, calendar rendering, custody logic.
endMonth as needed)This is the single most important rule: higher priority always overrides lower priority.
| # | Type | Rule | § |
|---|---|---|---|
| 1 | Father's / Mother's Day | Fri 6pm → Sun 6pm of that weekend | §153.314(5)(6) |
| 2 | Christmas | Even yr: Dad Dec18noon–Dec28noon, then Mom; Odd yr: swap | §153.314(1)(2) |
| 3 | Thanksgiving | Odd yr: Dad Wed6pm–Sun6pm; Even yr: Mom Wed6pm–Sun6pm | §153.314(3) |
| 4 | New Year's Day | Odd yr: Dad; Even yr: Mom (Jan 1 noon–midnight) | §153.314 |
| 5 | Other national holidays | Alternating by year (MLK, Presidents', Memorial, Labor, etc.) | §153.314 |
| 6 | Summer Break | Dad Jun 1–30 (30 consecutive days); Mom Jul31 + Aug1–15 | §153.317 |
| 7 | Spring / Winter Break | Odd yr: Dad 2nd half; Even yr: Dad 1st half | §153.317 |
| 8 | ESPO 1st/3rd/5th Week | Thu after school → Mon morning school = Dad | §153.317 |
| 9 | ESPO 2nd/4th Thursday | Dad 6pm–8pm only (then Mom) | §153.311 |
The Christmas school vacation runs Dec 18 – Jan 3 (RRISD). The statutory split:
School dismisses Wed afternoon. Possession: Wed 6pm → following Sun 6pm.
During school breaks (when classes are not in session), parents split the break evenly:
Half calculation: halfLen = Math.floor(totalDays / 2)
halfLen days → first parent; remaining days → second parentSPO/ESPO regular schedule is SUSPENDED during summer break (no school = no after-school pickup).
Weekend = Thursday (after school) → Sunday 6pm.
Which weeks are 1st/3rd/5th (Dad's)?
Weekend is identified by the Friday that starts it. Weekend number = count of Fridays in the month strictly before that Friday.
// Weekend 1 of next month: when the week's Friday falls in the following month
// (e.g., Apr 30's Thursday → Weekend 1 of May)
function isESPOWeekendDay(year, month, day) {
// Find the Friday of this week
const dow = new Date(year, month, day).getDay();
const mondayOfWeek = new Date(year, month, day);
mondayOfWeek.setDate(day - (dow === 0 ? 6 : dow - 1));
const friOfWeek = new Date(mondayOfWeek);
friOfWeek.setDate(mondayOfWeek.getDate() + 4);
const friDay = friOfWeek.getDate(), friMonth = friOfWeek.getMonth();
// If Friday is in different month → Weekend 1 of next month = ESPO
if (friMonth !== month) return true;
// Count Fridays in this month before friDay
let friCount = 0;
for (let fd = 1; fd < friDay; fd++) {
if (new Date(year, month, fd).getDay() === 5) friCount++;
}
return [1, 3, 5].includes(friCount + 1);
}
index.html)| Function | Purpose |
|---|---|
getFathersDayWeekend(dateStr) | Returns true if date is in Father's Day weekend (Fri–Sun) |
getMothersDayWeekend(dateStr) | Returns true if date is in Mother's Day weekend (Fri–Sun) |
getChristmasCustody(dateStr) | Returns 'dad'/'mom'/'none' for Christmas period |
getThanksgivingCustody(dateStr) | Returns 'dad'/'mom'/'none' for Thanksgiving period |
getNewYearCustody(dateStr) | Returns 'dad'/'mom'/'none' for New Year's Day |
getSchoolBreakCustody(dateStr) | Returns 'dad'/'mom'/'none' for spring/winter break days |
isMomSummerDay(year, month, day) | Returns true for Mom's remaining summer days |
isESPOWeekendDay(year, month, day) | True if the Friday of this week is 1st/3rd/5th Friday |
isInDadESPOMonth(year, month, day) | True if this day is Thu/Fri/Sat/Sun of an ESPO weekend |
isDadThursdayNonESPO(year, month, day) | True if this is a Week 2/4 Thursday (Dad 6–8pm only) |
isSchoolBreak(dateStr) | Returns break object or null |
getHolidayName(year, month, day) | Returns statutory holiday object or null |
Edit schoolBreaks array in index.html. Add entry:
{ start: 'YYYY-MM-DD', end: 'YYYY-MM-DD', label: { en: 'Break Name', cn: '中文名' } }
Spring Break and Winter Break custody is handled by getSchoolBreakCustody() — no separate update needed unless the split rule changes.
Update in both generateSPOCalendar() and generateESPOCalendar():
const endYear = YYYY, endMonth = M; // 0-indexed (7 = August)
See references/rrisd-calendar.md for full key dates.
const fs = require('fs');
const m = fs.readFileSync('index.html','utf8').match(/<script>([\s\S]*?)<\/script>/);
try { new Function(m[1]); console.log('JS OK'); }
catch(e) { console.log('JS ERROR:', e.message); }
const declarations