-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(journal): add provider pattern for journal context (#38)
* feat(journal): add provider pattern for journal context - Create JournalContext with type definitions - Implement JournalProvider for managing journal state - Add `useJournal` hook for accessing context - Includes tests for provider and hook functionality - Add JournalProvider to layout.tsx * Apply suggestions from code review Co-authored-by: Ryan James Meneses <[email protected]> * feat(journal): add journalTitle state and update tests - Added `journalTitle` and `setJournalTitle` to the Journal context - Updated the provider to handle `journalTitle` - Enhanced tests to include validation for `journalTitle` functionality * docs: fix TypeDoc errors Conform TypeDoc styles to evolving team standards to improve readability of code. - Remove extra whitespace. - Tightend up comments to span across less lines. - Reduce some verbiage. - Place docs for interface params above interface declaration. refactor: directly set values in `JournalContext.Provider`. Remove unnecessary assignment of new variable used in one place. --------- Co-authored-by: Ryan James Meneses <[email protected]> Co-authored-by: Ryan James Meneses <[email protected]>
- Loading branch information
1 parent
a01a4a5
commit 53d9b9c
Showing
5 changed files
with
167 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { createContext } from 'react'; | ||
|
||
/** | ||
* The context type for the Journal. | ||
* @typeParam journalId - The currently active journal's ID. | ||
* @typeParam setJournalId - A function to update the journal ID. | ||
* @typeParam journalTitle - The currently active journal's title. | ||
* @typeParam setJournalTitle - A function to update the journal title. | ||
*/ | ||
export interface JournalContextType { | ||
journalId: string; | ||
setJournalId: (id: string) => void; | ||
journalTitle: string; | ||
setJournalTitle: (title: string) => void; | ||
} | ||
|
||
/** | ||
* The React Context for the Journal feature providing access to the | ||
* `journalId` and `setJournalId` functions. | ||
*/ | ||
export const JournalContext = createContext<JournalContextType | undefined>( | ||
undefined | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
'use client'; | ||
import React, { useState } from 'react'; | ||
import { JournalContext } from './JournalContext'; | ||
|
||
/** | ||
* Props for the `JournalProvider` component. | ||
* @typeParam children - The child components that will have access to the | ||
* Journal context. | ||
*/ | ||
interface JournalProviderProps { | ||
children: React.ReactNode; | ||
} | ||
|
||
/** | ||
* The `JournalProvider` component wraps its children with a `JournalContext` | ||
* providing access to the journal id, title, and their respective | ||
* setter functions. | ||
* @param children - The child components to wrap with the Journal context. | ||
*/ | ||
export const JournalProvider: React.FC<JournalProviderProps> = ({ | ||
children, | ||
}) => { | ||
const [journalId, setJournalId] = useState<string>(''); | ||
const [journalTitle, setJournalTitle] = useState<string>(''); | ||
|
||
return ( | ||
<JournalContext.Provider | ||
value={ | ||
{ | ||
journalId, | ||
setJournalId, | ||
journalTitle, | ||
setJournalTitle, | ||
} | ||
}> | ||
{children} | ||
</JournalContext.Provider> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { JournalContext } from './JournalContext'; | ||
import { useContext } from 'react'; | ||
|
||
/** | ||
* Custom hook to access the Journal context within a `JournalProvider`. | ||
* @returns The `journalId` and `setJournalId` from the `JournalContext`. | ||
* @throws An error if used outside a `JournalProvider`. | ||
*/ | ||
export const useJournal = () => { | ||
const context = useContext(JournalContext); | ||
|
||
if (!context) { | ||
throw new Error('useJournal must be used within a JournalProvider'); | ||
} | ||
|
||
return context; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { fireEvent, render, screen } from '@testing-library/react'; | ||
import { JournalProvider } from '../../src/contexts/JournalProvider'; | ||
import React from 'react'; | ||
import { useJournal } from '../../src/contexts/useJournal'; | ||
|
||
const ContextConsumerComponent: React.FC = () => { | ||
const { journalId, setJournalId, journalTitle, setJournalTitle } = | ||
useJournal(); | ||
|
||
return ( | ||
<div> | ||
<p data-testid="journal-id">{journalId}</p> | ||
<button | ||
onClick={() => setJournalId('updated-journal-id')} | ||
data-testid="update-id-button" | ||
> | ||
Update Journal ID | ||
</button> | ||
<p data-testid="journal-title">{journalTitle}</p> | ||
<button | ||
onClick={() => setJournalTitle('updated-journal-title')} | ||
data-testid="update-title-button" | ||
> | ||
Update Journal Title | ||
</button> | ||
</div> | ||
); | ||
}; | ||
|
||
describe('JournalContext', () => { | ||
it('throws an error when useJournal is used outside JournalProvider', () => { | ||
const consoleError = jest | ||
.spyOn(console, 'error') | ||
.mockImplementation(() => {}); | ||
|
||
const InvalidComponent = () => { | ||
try { | ||
useJournal(); | ||
} catch (error) { | ||
throw error; | ||
} | ||
return null; | ||
}; | ||
|
||
expect(() => render(<InvalidComponent />)).toThrow( | ||
'useJournal must be used within a JournalProvider' | ||
); | ||
|
||
consoleError.mockRestore(); | ||
}); | ||
|
||
it('provides journalId and updates it correctly using context', () => { | ||
render( | ||
<JournalProvider> | ||
<ContextConsumerComponent /> | ||
</JournalProvider> | ||
); | ||
|
||
const journalIdElement = screen.getByTestId('journal-id'); | ||
expect(journalIdElement.textContent).toBe(''); | ||
|
||
const updateIdButton = screen.getByTestId('update-id-button'); | ||
fireEvent.click(updateIdButton); | ||
|
||
expect(journalIdElement.textContent).toBe('updated-journal-id'); | ||
}); | ||
|
||
it('provides journalTitle and updates it correctly using context', () => { | ||
render( | ||
<JournalProvider> | ||
<ContextConsumerComponent /> | ||
</JournalProvider> | ||
); | ||
|
||
// Test journalTitle | ||
const journalTitleElement = screen.getByTestId('journal-title'); | ||
expect(journalTitleElement.textContent).toBe(''); | ||
|
||
const updateTitleButton = screen.getByTestId('update-title-button'); | ||
fireEvent.click(updateTitleButton); | ||
|
||
expect(journalTitleElement.textContent).toBe('updated-journal-title'); | ||
}); | ||
}); |