const state = { cycleLength: 28, periodLength: 5, periodStart: null, viewDate: luxon.DateTime.local(), chart: null }; document.addEventListener('DOMContentLoaded', () => { document.getElementById('period-start').valueAsDate = new Date(); document.getElementById('calculate-btn').addEventListener('click', calculateCycle); document.getElementById('prev-month').addEventListener('click', showPreviousMonth); document.getElementById('next-month').addEventListener('click', showNextMonth); }); function calculateCycle() { state.cycleLength = parseInt(document.getElementById('cycle-length').value) || 28; state.periodLength = parseInt(document.getElementById('period-length').value) || 5; const periodStart = document.getElementById('period-start').value; if (!periodStart) { alert('Επιλέξτε την ημερομηνία έναρξης της περιόδου'); return; } state.periodStart = luxon.DateTime.fromISO(periodStart); state.viewDate = state.periodStart; document.getElementById('result-container').classList.remove('hidden'); updateCycleDetails(); updateChart(); renderCalendar(); } function updateCycleDetails() { if (!state.periodStart) return; const nextPeriodStart = state.periodStart.plus({ days: state.cycleLength }); const ovulationDay = nextPeriodStart.minus({ days: 14 }); const fertileStart = ovulationDay.minus({ days: 5 }); const fertileEnd = ovulationDay.plus({ days: 1 }); const safePeriod1Start = state.periodStart.plus({ days: state.periodLength }); const safePeriod1End = fertileStart.minus({ days: 1 }); const safePeriod2Start = fertileEnd.plus({ days: 1 }); const safePeriod2End = nextPeriodStart.minus({ days: 1 }); document.getElementById('cycle-details').innerHTML = `
Εμμηνορροϊκή περίοδος
${state.periodStart.toFormat('yyyy-MM-dd')} - ${state.periodStart.plus({ days: state.periodLength-1 }).toFormat('MM-dd')}
Προσοχή στην ξεκούραση και την υγιεινή
Περίοδος κινδύνου
${fertileStart.toFormat('MM-dd')} - ${fertileEnd.toFormat('MM-dd')}
Υψηλή πιθανότητα σύλληψης (ημέρα ωορρηξίας περίπου 30%)
Ημέρα ωορρηξίας
${ovulationDay.toFormat('MM-dd')}
Η υψηλότερη πιθανότητα σύλληψης
Περίοδος χαμηλής πιθανότητας σύλληψης
${safePeriod1Start.toFormat('MM-dd')} - ${safePeriod1End.toFormat('MM-dd')}
${safePeriod2Start.toFormat('MM-dd')} - ${safePeriod2End.toFormat('MM-dd')}
Χαμηλή πιθανότητα σύλληψης (<5%)
Επόμενη προβλεπόμενη περίοδος
${nextPeriodStart.toFormat('yyyy-MM-dd')}
`; } function updateChart() { const ctx = document.getElementById('cycle-chart').getContext('2d'); if (state.chart) { state.chart.destroy(); } const totalDays = state.cycleLength; const fertileDays = 7; const safeDays = totalDays - state.periodLength - fertileDays; state.chart = new Chart(ctx, { type: 'doughnut', data: { labels: ['Εμμηνορροϊκή περίοδος', 'Περίοδος κινδύνου', 'Ημέρα ωορρηξίας', 'Ασφαλής περίοδος'], datasets: [{ data: [state.periodLength, 6, 1, safeDays], backgroundColor: ['#fecaca', '#fef08a', '#f59e0b', '#bbf7d0'], borderWidth: 0 }] }, options: { responsive: true, plugins: { legend: { position: 'bottom' }, tooltip: { callbacks: { label: function(context) { const label = context.label || ''; const value = context.raw; const percentage = Math.round((value / totalDays) * 100); return `${label}: ${value}days (${percentage}%)`; } } } }, cutout: '65%', animation: { animateScale: true, animateRotate: true } } }); } function renderCalendar() { if (!state.periodStart) return; const monthStart = state.viewDate.startOf('month'); const monthEnd = state.viewDate.endOf('month'); const startDay = monthStart.weekday; const daysInMonth = monthEnd.day; document.getElementById('current-month').textContent = state.viewDate.toFormat('yyyy-MM'); const calendarDays = document.getElementById('calendar-days'); calendarDays.innerHTML = ''; const prevMonthEnd = monthStart.minus({ days: 1 }); for (let i = startDay - 1; i >= 0; i--) { const day = prevMonthEnd.day - i; const date = prevMonthEnd.set({ day: day }); calendarDays.appendChild(createDayElement(date, day, true)); } const today = luxon.DateTime.local(); for (let day = 1; day<= daysInMonth; day++) { const date = monthStart.set({ day: day }); calendarDays.appendChild(createDayElement(date, day, false, date.hasSame(today, 'day'))); } const daysToAdd = 42 - (startDay + daysInMonth); for (let day = 1; day<= daysToAdd; day++) { const date = monthEnd.plus({ days: day }); calendarDays.appendChild(createDayElement(date, day, true)); } } function createDayElement(date, day, isOtherMonth, isToday = false) { const dayElement = document.createElement('div'); dayElement.className = 'calendar-day'; dayElement.textContent = day; if (isOtherMonth) { dayElement.classList.add('text-gray-400'); return dayElement; } if (isToday) dayElement.classList.add('today'); let currentPeriod = state.periodStart; while (date > currentPeriod.plus({ days: state.cycleLength })) { currentPeriod = currentPeriod.plus({ days: state.cycleLength }); } const nextPeriod = currentPeriod.plus({ days: state.cycleLength }); const ovulationDay = nextPeriod.minus({ days: 14 }); const fertileStart = ovulationDay.minus({ days: 5 }); const fertileEnd = ovulationDay.plus({ days: 1 }); const tooltip = document.createElement('div'); tooltip.className = 'tooltip'; if (date >= currentPeriod && date< currentPeriod.plus({ days: state.periodLength })) { dayElement.classList.add('menstrual'); tooltip.innerHTML = `
Εμμηνορροϊκή περίοδος
Προσοχή στην ξεκούραση και την υγιεινή
`; } else if (date >= fertileStart && date<= fertileEnd) { if (date.hasSame(ovulationDay, 'day')) { dayElement.classList.add('ovulation'); tooltip.innerHTML = `
Ημέρα ωορρηξίας
Υψηλότερη πιθανότητα σύλληψης (περίπου 30%)
`; } else { dayElement.classList.add('fertile'); const daysDiff = Math.abs(date.diff(ovulationDay, 'days').days); const probability = 30 - daysDiff * 5; tooltip.innerHTML = `
Περίοδος κινδύνου
Πιθανότητα σύλληψης περίπου ${probability}%
`; } } else { dayElement.classList.add('safe'); tooltip.innerHTML = `
Ασφαλής περίοδος
Χαμηλή πιθανότητα σύλληψης (<5%)
`; } dayElement.appendChild(tooltip); return dayElement; } function showPreviousMonth() { state.viewDate = state.viewDate.minus({ months: 1 }); renderCalendar(); } function showNextMonth() { state.viewDate = state.viewDate.plus({ months: 1 }); renderCalendar(); }