mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:01:09 +02:00
refactor(calendar): extract birthday popover logic into composable
Create useBirthdayPopover composable to eliminate duplicated birthday popover state and handlers across DayView, WeekView, and MonthView. Changes: - Add useBirthdayPopover.svelte.ts composable - Update DayView to use the composable - Update WeekView to use the composable - Update MonthView to use the composable - Export from composables/index.ts This removes ~40 lines of duplicated code across the three views. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e0ef15276d
commit
668957a30b
5 changed files with 76 additions and 66 deletions
|
|
@ -6,12 +6,9 @@
|
|||
import { searchStore } from '$lib/stores/search.svelte';
|
||||
import { todosStore, type Task } from '$lib/stores/todos.svelte';
|
||||
import { eventContextMenuStore } from '$lib/stores/eventContextMenu.svelte';
|
||||
import { birthdaysStore, type BirthdayEvent } from '$lib/stores/birthdays.svelte';
|
||||
import { birthdaysStore } from '$lib/stores/birthdays.svelte';
|
||||
import BirthdayPopover from '$lib/components/birthday/BirthdayPopover.svelte';
|
||||
import {
|
||||
useVisibleHours,
|
||||
useCurrentTimeIndicator,
|
||||
} from '$lib/composables/useVisibleHours.svelte';
|
||||
import { useVisibleHours, useCurrentTimeIndicator, useBirthdayPopover } from '$lib/composables';
|
||||
import { toDate } from '$lib/utils/eventDateHelpers';
|
||||
import { HOUR_HEIGHT_PX, SNAP_INTERVAL_MINUTES } from '$lib/utils/calendarConstants';
|
||||
import {
|
||||
|
|
@ -102,9 +99,8 @@
|
|||
|
||||
let blockAllDayEvents = $derived(allDayEvents.filter((e) => getEventDisplayMode(e) === 'block'));
|
||||
|
||||
// Birthday Popover State
|
||||
let selectedBirthday = $state<BirthdayEvent | null>(null);
|
||||
let birthdayPopoverPosition = $state<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||
// Birthday Popover (using composable)
|
||||
const birthdayPopover = useBirthdayPopover();
|
||||
|
||||
// Get birthdays for current day (if enabled in settings)
|
||||
let birthdays = $derived.by(() => {
|
||||
|
|
@ -112,18 +108,6 @@
|
|||
return birthdaysStore.getBirthdaysForDay(viewStore.currentDate);
|
||||
});
|
||||
|
||||
// Handle birthday click - show popover
|
||||
function handleBirthdayClick(birthday: BirthdayEvent, e: MouseEvent) {
|
||||
e.stopPropagation();
|
||||
selectedBirthday = birthday;
|
||||
birthdayPopoverPosition = { x: e.clientX, y: e.clientY };
|
||||
}
|
||||
|
||||
// Close birthday popover
|
||||
function closeBirthdayPopover() {
|
||||
selectedBirthday = null;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Drag & Drop State
|
||||
// ============================================================================
|
||||
|
|
@ -744,7 +728,7 @@
|
|||
{#each birthdays as birthday}
|
||||
<button
|
||||
class="all-day-event birthday-event"
|
||||
onclick={(e) => handleBirthdayClick(birthday, e)}
|
||||
onclick={(e) => birthdayPopover.handleBirthdayClick(birthday, e)}
|
||||
>
|
||||
🎂 {birthday.displayName}
|
||||
{#if settingsStore.showBirthdayAge && birthday.age > 0}
|
||||
|
|
@ -915,11 +899,11 @@
|
|||
<EventContextMenu onEdit={handleContextMenuEdit} />
|
||||
|
||||
<!-- Birthday Popover -->
|
||||
{#if selectedBirthday}
|
||||
{#if birthdayPopover.selectedBirthday}
|
||||
<BirthdayPopover
|
||||
birthday={selectedBirthday}
|
||||
position={birthdayPopoverPosition}
|
||||
onClose={closeBirthdayPopover}
|
||||
birthday={birthdayPopover.selectedBirthday}
|
||||
position={birthdayPopover.popoverPosition}
|
||||
onClose={birthdayPopover.closePopover}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
import { eventContextMenuStore } from '$lib/stores/eventContextMenu.svelte';
|
||||
import TodoDayCell from './TodoDayCell.svelte';
|
||||
import BirthdayPopover from '$lib/components/birthday/BirthdayPopover.svelte';
|
||||
import { useBirthdayPopover } from '$lib/composables';
|
||||
import { goto } from '$app/navigation';
|
||||
import {
|
||||
format,
|
||||
|
|
@ -267,23 +268,12 @@
|
|||
// ============================================================================
|
||||
// Birthday Functions
|
||||
// ============================================================================
|
||||
let selectedBirthday = $state<BirthdayEvent | null>(null);
|
||||
let birthdayPopoverPosition = $state<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||
const birthdayPopover = useBirthdayPopover();
|
||||
|
||||
function getBirthdaysForDay(day: Date): BirthdayEvent[] {
|
||||
if (!settingsStore.showBirthdays) return [];
|
||||
return birthdaysStore.getBirthdaysForDay(day);
|
||||
}
|
||||
|
||||
function handleBirthdayClick(birthday: BirthdayEvent, e: MouseEvent) {
|
||||
e.stopPropagation();
|
||||
selectedBirthday = birthday;
|
||||
birthdayPopoverPosition = { x: e.clientX, y: e.clientY };
|
||||
}
|
||||
|
||||
function closeBirthdayPopover() {
|
||||
selectedBirthday = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="month-view" style="--column-count: {columnCount}" bind:this={monthViewRef}>
|
||||
|
|
@ -368,7 +358,7 @@
|
|||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<div
|
||||
class="event-pill birthday-pill"
|
||||
onclick={(e) => handleBirthdayClick(birthday, e)}
|
||||
onclick={(e) => birthdayPopover.handleBirthdayClick(birthday, e)}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
|
|
@ -396,11 +386,11 @@
|
|||
</div>
|
||||
|
||||
<!-- Birthday Popover -->
|
||||
{#if selectedBirthday}
|
||||
{#if birthdayPopover.selectedBirthday}
|
||||
<BirthdayPopover
|
||||
birthday={selectedBirthday}
|
||||
position={birthdayPopoverPosition}
|
||||
onClose={closeBirthdayPopover}
|
||||
birthday={birthdayPopover.selectedBirthday}
|
||||
position={birthdayPopover.popoverPosition}
|
||||
onClose={birthdayPopover.closePopover}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@
|
|||
import { birthdaysStore, type BirthdayEvent } from '$lib/stores/birthdays.svelte';
|
||||
import { eventContextMenuStore } from '$lib/stores/eventContextMenu.svelte';
|
||||
import BirthdayPopover from '$lib/components/birthday/BirthdayPopover.svelte';
|
||||
import {
|
||||
useVisibleHours,
|
||||
useCurrentTimeIndicator,
|
||||
} from '$lib/composables/useVisibleHours.svelte';
|
||||
import { useVisibleHours, useCurrentTimeIndicator, useBirthdayPopover } from '$lib/composables';
|
||||
import { toDate } from '$lib/utils/eventDateHelpers';
|
||||
import { HOUR_HEIGHT_PX, SNAP_INTERVAL_MINUTES } from '$lib/utils/calendarConstants';
|
||||
import {
|
||||
|
|
@ -127,9 +124,8 @@
|
|||
// Reference to the days container for position calculations
|
||||
let daysContainerEl: HTMLDivElement;
|
||||
|
||||
// Birthday Popover State
|
||||
let selectedBirthday = $state<BirthdayEvent | null>(null);
|
||||
let birthdayPopoverPosition = $state<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||
// Birthday Popover (using composable)
|
||||
const birthdayPopover = useBirthdayPopover();
|
||||
|
||||
// Get birthdays for a day (if enabled in settings)
|
||||
function getBirthdaysForDay(day: Date): BirthdayEvent[] {
|
||||
|
|
@ -142,18 +138,6 @@
|
|||
settingsStore.showBirthdays && days.some((day) => getBirthdaysForDay(day).length > 0)
|
||||
);
|
||||
|
||||
// Handle birthday click - show popover
|
||||
function handleBirthdayClick(birthday: BirthdayEvent, e: MouseEvent) {
|
||||
e.stopPropagation();
|
||||
selectedBirthday = birthday;
|
||||
birthdayPopoverPosition = { x: e.clientX, y: e.clientY };
|
||||
}
|
||||
|
||||
// Close birthday popover
|
||||
function closeBirthdayPopover() {
|
||||
selectedBirthday = null;
|
||||
}
|
||||
|
||||
function getEventsForDay(day: Date): CalendarEvent[] {
|
||||
return getVisibleTimedEvents(
|
||||
eventsStore.getEventsForDay(day),
|
||||
|
|
@ -909,7 +893,7 @@
|
|||
{#each getBirthdaysForDay(day) as birthday}
|
||||
<button
|
||||
class="all-day-event birthday-event"
|
||||
onclick={(e) => handleBirthdayClick(birthday, e)}
|
||||
onclick={(e) => birthdayPopover.handleBirthdayClick(birthday, e)}
|
||||
>
|
||||
🎂 {birthday.displayName}
|
||||
{#if settingsStore.showBirthdayAge && birthday.age > 0}
|
||||
|
|
@ -1116,11 +1100,11 @@
|
|||
<EventContextMenu onEdit={handleContextMenuEdit} />
|
||||
|
||||
<!-- Birthday Popover -->
|
||||
{#if selectedBirthday}
|
||||
{#if birthdayPopover.selectedBirthday}
|
||||
<BirthdayPopover
|
||||
birthday={selectedBirthday}
|
||||
position={birthdayPopoverPosition}
|
||||
onClose={closeBirthdayPopover}
|
||||
birthday={birthdayPopover.selectedBirthday}
|
||||
position={birthdayPopover.popoverPosition}
|
||||
onClose={birthdayPopover.closePopover}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ export { useSidebarDrop, type SidebarDropConfig } from './useSidebarDrop.svelte'
|
|||
// Keyboard handling
|
||||
export { useCalendarKeyboard, type CancellableOperation } from './useCalendarKeyboard.svelte';
|
||||
|
||||
// Birthday popover management
|
||||
export { useBirthdayPopover } from './useBirthdayPopover.svelte';
|
||||
|
||||
// Legacy exports (kept for backwards compatibility, may be removed later)
|
||||
export { useDragDrop, type DragDropConfig, type DragState } from './useDragDrop.svelte';
|
||||
export { useResize, type ResizeConfig, type ResizeState } from './useResize.svelte';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Birthday Popover Composable
|
||||
* Manages birthday popover state and handlers for calendar views
|
||||
*/
|
||||
|
||||
import type { BirthdayEvent } from '$lib/api/birthdays';
|
||||
|
||||
export function useBirthdayPopover() {
|
||||
let selectedBirthday = $state<BirthdayEvent | null>(null);
|
||||
let popoverPosition = $state<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||
|
||||
/**
|
||||
* Handle click on a birthday indicator to show the popover
|
||||
*/
|
||||
function handleBirthdayClick(birthday: BirthdayEvent, e: MouseEvent) {
|
||||
e.stopPropagation();
|
||||
selectedBirthday = birthday;
|
||||
popoverPosition = { x: e.clientX, y: e.clientY };
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the birthday popover
|
||||
*/
|
||||
function closePopover() {
|
||||
selectedBirthday = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if popover is currently open
|
||||
*/
|
||||
function isOpen(): boolean {
|
||||
return selectedBirthday !== null;
|
||||
}
|
||||
|
||||
return {
|
||||
// State (reactive getters)
|
||||
get selectedBirthday() {
|
||||
return selectedBirthday;
|
||||
},
|
||||
get popoverPosition() {
|
||||
return popoverPosition;
|
||||
},
|
||||
|
||||
// Methods
|
||||
handleBirthdayClick,
|
||||
closePopover,
|
||||
isOpen,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue