Major new version #2

Merged
LeoVasanko merged 86 commits from vol002 into main 2025-08-26 05:58:24 +01:00
Showing only changes of commit 8c8a01f7cb - Show all commits

View File

@ -31,6 +31,9 @@ const eventSaved = ref(false)
const titleInput = ref(null) const titleInput = ref(null)
const modalRef = ref(null) const modalRef = ref(null)
// UI display mode - stays fixed unless user manually changes it
const uiDisplayFrequency = ref('weeks') // 'weeks' | 'months' | 'years'
// Drag functionality // Drag functionality
const isDragging = ref(false) const isDragging = ref(false)
const dragOffset = ref({ x: 0, y: 0 }) const dragOffset = ref({ x: 0, y: 0 })
@ -107,11 +110,66 @@ const fallbackWeekdays = computed(() => {
return fallback return fallback
}) })
// Repeat mapping uses 'weeks' | 'months' | 'none' directly // Computed property to handle UI frequency (weeks/months/years) vs store frequency (weeks/months)
const displayFrequency = computed({
get() {
return uiDisplayFrequency.value
},
set(val) {
const oldFreq = uiDisplayFrequency.value
const currentDisplayValue = displayInterval.value // Get the current display value before changing
uiDisplayFrequency.value = val
if (oldFreq === val) return // No change
if (oldFreq === 'years' && val === 'months') {
// Converting from years to months: keep the display value the same, but now it represents months
recurrenceFrequency.value = 'months'
recurrenceInterval.value = currentDisplayValue // Keep the same number, now as months
} else if (oldFreq === 'months' && val === 'years') {
// Converting from months to years: keep the display value the same, but now it represents years
recurrenceFrequency.value = 'months'
recurrenceInterval.value = currentDisplayValue * 12 // Convert to months for storage
} else if (val === 'years') {
// Converting from weeks to years
recurrenceFrequency.value = 'months'
recurrenceInterval.value = 12 // Default to 1 year
} else if (val === 'months') {
// Converting to months from weeks
recurrenceFrequency.value = 'months'
if (oldFreq === 'weeks') {
recurrenceInterval.value = 1 // Default to 1 month
}
} else if (val === 'weeks') {
// Converting to weeks
recurrenceFrequency.value = 'weeks'
recurrenceInterval.value = 1 // Default to 1 week
}
},
})
// Computed property for display interval (handles years conversion)
const displayInterval = computed({
get() {
if (uiDisplayFrequency.value === 'years') {
return recurrenceInterval.value / 12
}
return recurrenceInterval.value
},
set(val) {
if (uiDisplayFrequency.value === 'years') {
recurrenceInterval.value = val * 12
} else {
recurrenceInterval.value = val
}
},
})
// Repeat mapping uses 'weeks' | 'months' | 'none' directly (store only supports weeks/months)
const repeat = computed({ const repeat = computed({
get() { get() {
if (!recurrenceEnabled.value) return 'none' if (!recurrenceEnabled.value) return 'none'
return recurrenceFrequency.value // 'weeks' | 'months' return recurrenceFrequency.value // Always 'weeks' | 'months' for store
}, },
set(val) { set(val) {
if (val === 'none') { if (val === 'none') {
@ -119,8 +177,16 @@ const repeat = computed({
return return
} }
recurrenceEnabled.value = true recurrenceEnabled.value = true
if (val === 'weeks') recurrenceFrequency.value = 'weeks' if (val === 'weeks') {
else if (val === 'months') recurrenceFrequency.value = 'months' recurrenceFrequency.value = 'weeks'
uiDisplayFrequency.value = 'weeks'
if (recurrenceInterval.value >= 12) {
recurrenceInterval.value = 1 // Reset to sensible weekly default
}
} else if (val === 'months') {
recurrenceFrequency.value = 'months'
// Don't change UI display frequency here - let it be determined by context
}
}, },
}) })
@ -187,6 +253,7 @@ function openCreateDialog(selectionData = null) {
recurrenceEnabled.value = false recurrenceEnabled.value = false
recurrenceInterval.value = 1 recurrenceInterval.value = 1
recurrenceFrequency.value = 'weeks' recurrenceFrequency.value = 'weeks'
uiDisplayFrequency.value = 'weeks' // Set initial UI display mode
recurrenceWeekdays.value = [false, false, false, false, false, false, false] recurrenceWeekdays.value = [false, false, false, false, false, false, false]
recurrenceOccurrences.value = 0 recurrenceOccurrences.value = 0
colorId.value = calendarStore.selectEventColorId(start, end) colorId.value = calendarStore.selectEventColorId(start, end)
@ -294,6 +361,21 @@ function openEditDialog(payload) {
loadWeekdayPatternFromStore(event.repeatWeekdays) loadWeekdayPatternFromStore(event.repeatWeekdays)
repeat.value = event.repeat // triggers setter mapping into recurrence state repeat.value = event.repeat // triggers setter mapping into recurrence state
if (event.repeatInterval) recurrenceInterval.value = event.repeatInterval if (event.repeatInterval) recurrenceInterval.value = event.repeatInterval
// Set UI display frequency based on loaded data
if (event.repeat === 'weeks') {
uiDisplayFrequency.value = 'weeks'
} else if (event.repeat === 'months') {
// If it's a yearly interval (multiple of 12), show as years
if (event.repeatInterval && event.repeatInterval % 12 === 0 && event.repeatInterval >= 12) {
uiDisplayFrequency.value = 'years'
} else {
uiDisplayFrequency.value = 'months'
}
} else {
uiDisplayFrequency.value = 'weeks' // fallback
}
// Map repeatCount // Map repeatCount
const rc = event.repeatCount ?? 'unlimited' const rc = event.repeatCount ?? 'unlimited'
recurrenceOccurrences.value = rc === 'unlimited' ? 0 : parseInt(rc, 10) || 0 recurrenceOccurrences.value = rc === 'unlimited' ? 0 : parseInt(rc, 10) || 0
@ -510,7 +592,7 @@ const finalOccurrenceDate = computed(() => {
const base = editingEventId.value ? calendarStore.getEventById(editingEventId.value) : null const base = editingEventId.value ? calendarStore.getEventById(editingEventId.value) : null
if (!base) return null if (!base) return null
const start = new Date(base.startDate + 'T00:00:00') const start = new Date(base.startDate + 'T00:00:00')
if (recurrenceFrequency.value === 'weeks') { if (uiDisplayFrequency.value === 'weeks') {
// iterate days until we count 'count-1' additional occurrences (first is base if selected weekday) // iterate days until we count 'count-1' additional occurrences (first is base if selected weekday)
const pattern = buildStoreWeekdayPattern() // Sun..Sat const pattern = buildStoreWeekdayPattern() // Sun..Sat
// Build Monday-first pattern again for selection clarity // Build Monday-first pattern again for selection clarity
@ -530,11 +612,16 @@ const finalOccurrenceDate = computed(() => {
} }
if (occs === count) return cursor if (occs === count) return cursor
return null return null
} else if (recurrenceFrequency.value === 'months') { } else if (uiDisplayFrequency.value === 'months') {
const monthsToAdd = recurrenceInterval.value * (count - 1) const monthsToAdd = displayInterval.value * (count - 1)
const d = new Date(start) const d = new Date(start)
d.setMonth(d.getMonth() + monthsToAdd) d.setMonth(d.getMonth() + monthsToAdd)
return d return d
} else if (uiDisplayFrequency.value === 'years') {
const yearsToAdd = displayInterval.value * (count - 1)
const d = new Date(start)
d.setFullYear(d.getFullYear() + yearsToAdd)
return d
} }
}) })
@ -560,15 +647,18 @@ const formattedFinalOccurrence = computed(() => {
const recurrenceSummary = computed(() => { const recurrenceSummary = computed(() => {
if (!recurrenceEnabled.value) return 'Does not recur' if (!recurrenceEnabled.value) return 'Does not recur'
if (recurrenceFrequency.value === 'weeks') { if (uiDisplayFrequency.value === 'weeks') {
return recurrenceInterval.value === 1 ? 'Weekly' : `Every ${recurrenceInterval.value} weeks` return displayInterval.value === 1 ? 'Weekly' : `Every ${displayInterval.value} weeks`
} else if (uiDisplayFrequency.value === 'years') {
return displayInterval.value === 1 ? 'Annually' : `Every ${displayInterval.value} years`
} }
// months frequency // For months frequency - always check the underlying recurrenceInterval for yearly patterns
if (recurrenceInterval.value % 12 === 0) { if (recurrenceFrequency.value === 'months' && recurrenceInterval.value % 12 === 0) {
const years = recurrenceInterval.value / 12 const years = recurrenceInterval.value / 12
return years === 1 ? 'Annually' : `Every ${years} years` return years === 1 ? 'Annually' : `Every ${years} years`
} }
return recurrenceInterval.value === 1 ? 'Monthly' : `Every ${recurrenceInterval.value} months` // Regular monthly display
return displayInterval.value === 1 ? 'Monthly' : `Every ${displayInterval.value} months`
}) })
</script> </script>
@ -610,15 +700,16 @@ const recurrenceSummary = computed(() => {
<div v-if="recurrenceEnabled" class="recurrence-form"> <div v-if="recurrenceEnabled" class="recurrence-form">
<div class="line compact"> <div class="line compact">
<Numeric <Numeric
v-model="recurrenceInterval" v-model="displayInterval"
:prefix-values="[{ value: 1, display: 'Every' }]" :prefix-values="[{ value: 1, display: 'Every' }]"
:min="2" :min="2"
number-prefix="Every " number-prefix="Every "
aria-label="Interval" aria-label="Interval"
/> />
<select v-model="recurrenceFrequency" class="freq-select"> <select v-model="displayFrequency" class="freq-select">
<option value="weeks">{{ recurrenceInterval === 1 ? 'week' : 'weeks' }}</option> <option value="weeks">{{ displayInterval === 1 ? 'week' : 'weeks' }}</option>
<option value="months">{{ recurrenceInterval === 1 ? 'month' : 'months' }}</option> <option value="months">{{ displayInterval === 1 ? 'month' : 'months' }}</option>
<option value="years">{{ displayInterval === 1 ? 'year' : 'years' }}</option>
</select> </select>
<Numeric <Numeric
class="occ-stepper" class="occ-stepper"
@ -630,7 +721,7 @@ const recurrenceSummary = computed(() => {
extra-class="occ" extra-class="occ"
/> />
</div> </div>
<div v-if="recurrenceFrequency === 'weeks'" @click.stop> <div v-if="uiDisplayFrequency === 'weeks'" @click.stop>
<WeekdaySelector <WeekdaySelector
v-model="recurrenceWeekdays" v-model="recurrenceWeekdays"
:fallback="fallbackWeekdays" :fallback="fallbackWeekdays"