• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jcubic / 10xDevs / 19313081289

12 Nov 2025 09:50PM UTC coverage: 62.491% (+0.5%) from 61.968%
19313081289

push

github

jcubic
fix unit test

300 of 499 branches covered (60.12%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

553 of 866 relevant lines covered (63.86%)

230.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.0
/src/components/notes/NotesContext.tsx
1
'use client';
2

3
import { createContext, useContext, useEffect, useCallback, type ReactNode } from 'react';
4
import { usePathname, useRouter } from 'next/navigation';
5
import type { NoteTreeNode } from '@/types/tree';
6
import type { SaveStatus } from '@/types/notes';
7
import { useNodeSelection } from '@/hooks/useNodeSelection';
8

9
interface NotesContextValue {
10
  notes: NoteTreeNode[];
11
  selectedNoteId: number | null;
12
  saveStatus: SaveStatus;
13
  setNotes: (notes: NoteTreeNode[] | ((prev: NoteTreeNode[]) => NoteTreeNode[])) => void;
14
  setSaveStatus: (status: SaveStatus) => void;
15
  updateNoteContent: (noteId: number, content: string) => void;
16
  updateNoteName: (noteId: number, name: string) => void;
17
  markNoteDirty: (noteId: number, dirty: boolean) => void;
18
  getSelectedNote: () => NoteTreeNode | null;
19
  getNote: (noteId: number) => NoteTreeNode | null;
20
  selectNote: (noteId: number | null) => void;
21
}
22

23
const NotesContext = createContext<NotesContextValue | undefined>(undefined);
36✔
24

25
export function useNotesContext() {
36✔
26
  const context = useContext(NotesContext);
3,170✔
27
  if (context === undefined) {
3,170!
28
    throw new Error('useNotesContext must be used within a NotesProvider');
×
29
  }
30
  return context;
3,170✔
31
}
32

33
interface NotesProviderProps {
34
  children: ReactNode;
35
  initialNotes?: NoteTreeNode[];
36
  initialSelectedNoteId?: number | null;
37
}
38

39
export function NotesProvider({
36✔
40
  children,
41
  initialNotes = [],
×
42
  initialSelectedNoteId = null
×
43
}: NotesProviderProps) {
44
  const pathname = usePathname();
1,024✔
45
  const router = useRouter();
1,024✔
46

47
  // Use the hook that manages all the state
48
  const {
49
    notes,
50
    selectedNoteId,
51
    saveStatus,
52
    setNotes,
53
    setSaveStatus,
54
    updateSelection,
55
    updateDirtyFlag,
56
    updateNoteContent,
57
    updateNoteName
58
  } = useNodeSelection(initialNotes, initialSelectedNoteId);
1,024✔
59

60
  // Sync notes state when initialNotes prop changes (e.g., after redirect)
61
  useEffect(() => {
1,024✔
62
    if (initialNotes.length > 0 && notes.length === 0) {
48✔
63
      setNotes(initialNotes);
3✔
64
    }
65
  }, [initialNotes, notes.length, setNotes]);
66

67
  const markNoteDirty = updateDirtyFlag;
1,024✔
68

69
  const getSelectedNote = useCallback((): NoteTreeNode | null => {
1,024✔
70
    if (!selectedNoteId) return null;
1,226✔
71
    return notes.find((note) => note.id === selectedNoteId) || null;
1,042!
72
  }, [notes, selectedNoteId]);
73

74
  const getNote = useCallback(
1,024✔
75
    (noteId: number): NoteTreeNode | null => {
76
      return notes.find((note) => note.id === noteId) || null;
946!
77
    },
78
    [notes]
79
  );
80

81
  // Note selection with Next.js router
82
  const selectNote = useCallback(
1,024✔
83
    (noteId: number | null) => {
84
      // Update state immediately
85
      updateSelection(noteId);
21✔
86

87
      // Navigate using Next.js router
88
      if (noteId === null) {
21!
89
        router.push('/');
×
90
      } else {
91
        router.push(`/note/${noteId}`);
21✔
92
      }
93
    },
94
    [updateSelection, router]
95
  );
96

97
  // Sync URL to state on URL changes
98
  useEffect(() => {
1,024✔
99
    const noteMatch = pathname.match(/\/note\/(\d+)/);
51✔
100
    const urlNoteId = noteMatch ? parseInt(noteMatch[1], 10) : null;
51✔
101

102
    if (urlNoteId !== null) {
51✔
103
      updateSelection(urlNoteId);
19✔
104
    }
105
  }, [pathname, updateSelection]);
106

107
  // Auto-select first note when at root with notes available
108
  useEffect(() => {
1,024✔
109
    if (pathname === '/' && notes.length > 0 && !selectedNoteId) {
418✔
110
      const firstNote = notes[0];
15✔
111
      router.push(`/note/${firstNote.id}`);
15✔
112
    }
113
  }, [pathname, notes, selectedNoteId, router]);
114

115
  const value: NotesContextValue = {
1,024✔
116
    notes,
117
    selectedNoteId,
118
    saveStatus,
119
    setNotes,
120
    setSaveStatus,
121
    updateNoteContent,
122
    updateNoteName,
123
    markNoteDirty,
124
    getSelectedNote,
125
    getNote,
126
    selectNote
127
  };
128

UNCOV
129
  return <NotesContext.Provider value={value}>{children}</NotesContext.Provider>;
×
130
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc