mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
31f6ec1f47
* feat(vacay): read-only calendar shares on the server (#444, #667) * feat(vacay): shared calendars card and ring overlay on desktop * feat(vacay): share sheet and calendar rings on mobile * test(vacay): cover the calendar share flows * docs(vacay): document read-only calendar sharing
63 lines
2.6 KiB
TypeScript
63 lines
2.6 KiB
TypeScript
import { useEffect, useState, useCallback } from 'react'
|
|
import { useVacayStore } from '../../store/vacayStore'
|
|
import { addListener, removeListener } from '../../api/websocket'
|
|
|
|
/**
|
|
* Vacay page logic — pulls the vacay store, owns the page-local UI state
|
|
* (settings modal, delete-year prompt, mobile drawer), wires the WebSocket live
|
|
* sync and the per-year (re)loads, and exposes the add-prev/next-year helpers.
|
|
* VacayPage stays a wiring container around its sidebar/calendar JSX.
|
|
* Behaviour is identical to the previous in-component logic.
|
|
*/
|
|
export function useVacay() {
|
|
const { years, selectedYear, setSelectedYear, addYear, removeYear, loadAll, loadPlan, loadEntries, loadStats, loadHolidays, loadShares, loadSharedCalendars, loading, incomingInvites, acceptInvite, declineInvite, plan, sharedCalendars } = useVacayStore()
|
|
const [showSettings, setShowSettings] = useState<boolean>(false)
|
|
const [deleteYear, setDeleteYear] = useState<number | null>(null)
|
|
const [showMobileSidebar, setShowMobileSidebar] = useState<boolean>(false)
|
|
|
|
useEffect(() => { loadAll() }, [])
|
|
|
|
// Live sync via WebSocket
|
|
const handleWsMessage = useCallback((msg: { type: string }) => {
|
|
if (msg.type === 'vacay:update' || msg.type === 'vacay:settings') {
|
|
loadPlan()
|
|
loadEntries(selectedYear)
|
|
loadStats(selectedYear)
|
|
if (msg.type === 'vacay:settings') loadAll()
|
|
}
|
|
if (msg.type === 'vacay:invite' || msg.type === 'vacay:accepted' || msg.type === 'vacay:declined' || msg.type === 'vacay:cancelled' || msg.type === 'vacay:dissolved') {
|
|
loadAll()
|
|
}
|
|
if (msg.type === 'vacay:share' || msg.type === 'vacay:share-removed' || msg.type === 'vacay:shared-update') {
|
|
loadShares()
|
|
loadSharedCalendars(selectedYear)
|
|
}
|
|
}, [selectedYear])
|
|
|
|
useEffect(() => {
|
|
addListener(handleWsMessage)
|
|
return () => removeListener(handleWsMessage)
|
|
}, [handleWsMessage])
|
|
useEffect(() => {
|
|
if (selectedYear) { loadEntries(selectedYear); loadStats(selectedYear); loadHolidays(selectedYear); loadSharedCalendars(selectedYear) }
|
|
}, [selectedYear])
|
|
|
|
const handleAddNextYear = () => {
|
|
const nextYear = years.length > 0 ? Math.max(...years) + 1 : new Date().getFullYear()
|
|
addYear(nextYear)
|
|
}
|
|
|
|
const handleAddPrevYear = () => {
|
|
const prevYear = years.length > 0 ? Math.min(...years) - 1 : new Date().getFullYear()
|
|
addYear(prevYear)
|
|
}
|
|
|
|
return {
|
|
years, selectedYear, setSelectedYear, removeYear, loading,
|
|
incomingInvites, acceptInvite, declineInvite, plan, sharedCalendars,
|
|
showSettings, setShowSettings, deleteYear, setDeleteYear,
|
|
showMobileSidebar, setShowMobileSidebar,
|
|
handleAddNextYear, handleAddPrevYear,
|
|
}
|
|
}
|