mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 06:11:45 +00:00
refactoring: TypeScript migration, security fixes,
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import { useState, useRef } from 'react'
|
||||
import { useTripStore } from '../store/tripStore'
|
||||
import { useToast } from '../components/shared/Toast'
|
||||
import type { MergedItem, DayNotesMap, DayNote } from '../types'
|
||||
|
||||
interface NoteUiState {
|
||||
mode: 'add' | 'edit'
|
||||
noteId?: number
|
||||
text: string
|
||||
time: string
|
||||
icon: string
|
||||
sortOrder?: number
|
||||
}
|
||||
|
||||
interface NoteUiMap {
|
||||
[dayId: string]: NoteUiState
|
||||
}
|
||||
|
||||
export function useDayNotes(tripId: number | string) {
|
||||
const [noteUi, setNoteUi] = useState<NoteUiMap>({})
|
||||
const noteInputRef = useRef<HTMLInputElement | null>(null)
|
||||
const tripStore = useTripStore()
|
||||
const toast = useToast()
|
||||
const dayNotes: DayNotesMap = tripStore.dayNotes || {}
|
||||
|
||||
const openAddNote = (dayId: number, getMergedItems: (dayId: number) => MergedItem[], expandDay?: (dayId: number) => void) => {
|
||||
const merged = getMergedItems(dayId)
|
||||
const maxKey = merged.length > 0 ? Math.max(...merged.map((i) => i.sortKey)) : -1
|
||||
setNoteUi((prev) => ({ ...prev, [dayId]: { mode: 'add', text: '', time: '', icon: 'FileText', sortOrder: maxKey + 1 } }))
|
||||
expandDay?.(dayId)
|
||||
setTimeout(() => noteInputRef.current?.focus(), 50)
|
||||
}
|
||||
|
||||
const openEditNote = (dayId: number, note: DayNote) => {
|
||||
setNoteUi((prev) => ({ ...prev, [dayId]: { mode: 'edit', noteId: note.id, text: note.text, time: note.time || '', icon: note.icon || 'FileText' } }))
|
||||
setTimeout(() => noteInputRef.current?.focus(), 50)
|
||||
}
|
||||
|
||||
const cancelNote = (dayId: number) => {
|
||||
setNoteUi((prev) => { const n = { ...prev }; delete n[dayId]; return n })
|
||||
}
|
||||
|
||||
const saveNote = async (dayId: number) => {
|
||||
const ui = noteUi[dayId]
|
||||
if (!ui?.text?.trim()) return
|
||||
try {
|
||||
if (ui.mode === 'add') {
|
||||
await tripStore.addDayNote(tripId, dayId, { text: ui.text.trim(), time: ui.time || null, icon: ui.icon || 'FileText', sort_order: ui.sortOrder })
|
||||
} else {
|
||||
await tripStore.updateDayNote(tripId, dayId, ui.noteId!, { text: ui.text.trim(), time: ui.time || null, icon: ui.icon || 'FileText' })
|
||||
}
|
||||
cancelNote(dayId)
|
||||
} catch (err: unknown) { toast.error(err instanceof Error ? err.message : 'Unknown error') }
|
||||
}
|
||||
|
||||
const deleteNote = async (dayId: number, noteId: number) => {
|
||||
try { await tripStore.deleteDayNote(tripId, dayId, noteId) }
|
||||
catch (err: unknown) { toast.error(err instanceof Error ? err.message : 'Unknown error') }
|
||||
}
|
||||
|
||||
const moveNote = async (dayId: number, noteId: number, direction: 'up' | 'down', getMergedItems: (dayId: number) => MergedItem[]) => {
|
||||
const merged = getMergedItems(dayId)
|
||||
const idx = merged.findIndex((i) => i.type === 'note' && (i.data as DayNote).id === noteId)
|
||||
if (idx === -1) return
|
||||
let newSortOrder: number
|
||||
if (direction === 'up') {
|
||||
if (idx === 0) return
|
||||
newSortOrder = idx >= 2 ? (merged[idx - 2].sortKey + merged[idx - 1].sortKey) / 2 : merged[idx - 1].sortKey - 1
|
||||
} else {
|
||||
if (idx >= merged.length - 1) return
|
||||
newSortOrder = idx < merged.length - 2 ? (merged[idx + 1].sortKey + merged[idx + 2].sortKey) / 2 : merged[idx + 1].sortKey + 1
|
||||
}
|
||||
try { await tripStore.updateDayNote(tripId, dayId, noteId, { sort_order: newSortOrder }) }
|
||||
catch (err: unknown) { toast.error(err instanceof Error ? err.message : 'Unknown error') }
|
||||
}
|
||||
|
||||
return { noteUi, setNoteUi, noteInputRef, dayNotes, openAddNote, openEditNote, cancelNote, saveNote, deleteNote, moveNote }
|
||||
}
|
||||
Reference in New Issue
Block a user