Skip to content

Commit

Permalink
Ngoc (#2)
Browse files Browse the repository at this point in the history
* display passageTag and storyTag frequencies
Co-authored-by: sihambyte <[email protected]>
  • Loading branch information
rubynguyen1510 authored Feb 21, 2024
1 parent 7c17bcf commit 4a82438
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/components/tag/__mocks__/tag-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export const TagEditor: React.FC<TagEditorProps> = props => (
<button onClick={() => props.onChangeName('mock-new-name')}>
onChangeName
</button>
<span>{`${props.count} ${props.count > 1 ? 'passages' : 'passage'}`}</span>
</div>
);
9 changes: 9 additions & 0 deletions src/components/tag/__tests__/tag-editor.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import {TagEditor, TagEditorProps} from '../tag-editor';
describe('<TagEditor>', () => {
async function renderComponent(props?: Partial<TagEditorProps>) {
const tagName = lorem.word();
const mockCount = 1;
const result = render(
<TagEditor
allTags={[tagName]}
name={tagName}
count={mockCount}
onChangeColor={jest.fn()}
onChangeName={jest.fn()}
{...props}
Expand All @@ -25,6 +27,13 @@ describe('<TagEditor>', () => {
await renderComponent({name: 'test name'});
expect(screen.getByText('test name')).toBeInTheDocument();
});
it('displays the frequency of the tag', async() => {
await renderComponent({ count: 1});
expect(screen.getByText('1 passage')).toBeInTheDocument();

await renderComponent({ count: 2});
expect(screen.getByText('2 passages')).toBeInTheDocument();
})

it('calls the onChangeColor prop when the color is changed', async () => {
const onChangeColor = jest.fn();
Expand Down
6 changes: 5 additions & 1 deletion src/components/tag/tag-editor.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
.tag-editor {
display: grid;
grid-gap: var(--grid-size);
grid-template-columns: repeat(3, min-content);
grid-template-columns: repeat(4, min-content);
align-items: center;
}
.tag-count{
white-space: nowrap;
}

.tag-editor .tag-name {
Expand Down
4 changes: 3 additions & 1 deletion src/components/tag/tag-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ export interface TagEditorProps {
allTags: string[];
color?: Color;
name: string;
count: number;
onChangeColor: (color: Color) => void;
onChangeName: (name: string) => void;
}

export const TagEditor: React.FC<TagEditorProps> = props => {
const {allTags, color, name, onChangeColor, onChangeName} = props;
const {allTags, color, name, count, onChangeColor, onChangeName} = props;
const [newName, setNewName] = React.useState(name);
const {t} = useTranslation();

Expand Down Expand Up @@ -52,6 +53,7 @@ export const TagEditor: React.FC<TagEditorProps> = props => {
>
{t('common.color')}
</TextSelect>
<span className="tag-count">{`${count} ${count > 1 ? 'passages' : 'passage'}`}</span>
</div>
);
};
12 changes: 12 additions & 0 deletions src/dialogs/__tests__/passage-tags.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ describe('<PassageTagsDialog>', () => {
expect(screen.getByTestId('mock-tag-editor-mock-tag2')).toBeInTheDocument();
});

it ('shows correct tag frequencies for every passage tags', async () => {
const story = fakeStory(2);

story.passages[0].tags = ['mock-tag', 'mock-tag2'];
story.passages[1].tags = ['mock-tag'];

await renderComponent({storyId: story.id}, {stories: [story]})

expect(within(screen.getByTestId('mock-tag-editor-mock-tag')).getByText(`2 passages`)).toBeInTheDocument();
; expect(within(screen.getByTestId('mock-tag-editor-mock-tag2')).getByText(`1 passage`)).toBeInTheDocument();
});

it('dispatches a story action if a tag is renamed', async () => {
const dispatch = jest.fn();
const story = fakeStory(1);
Expand Down
17 changes: 17 additions & 0 deletions src/dialogs/__tests__/story-tags.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,23 @@ describe('<StoryTagsDialog>', () => {
expect(screen.getByTestId('mock-tag-editor-mock-tag2')).toBeInTheDocument();
});

it ('renders tag editor with correct count for each tag', async () => {
const story1 = fakeStory();
const story2 = fakeStory();

story1.tags = ['tag1', 'tag2'];
story2.tags = ['tag2', 'tag3'];

await renderComponent(
{},
{stories: [story1, story2]}
);

expect(within(screen.getByTestId('mock-tag-editor-tag1')).getByText(`1 passage`)).toBeInTheDocument();
; expect(within(screen.getByTestId('mock-tag-editor-tag2')).getByText(`2 passages`)).toBeInTheDocument();
expect(within(screen.getByTestId('mock-tag-editor-tag3')).getByText(`1 passage`)).toBeInTheDocument();
});

it('dispatches a story action if a tag is renamed', async () => {
const dispatch = jest.fn();
const story = fakeStory();
Expand Down
6 changes: 4 additions & 2 deletions src/dialogs/passage-tags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
setTagColor,
storyWithId,
renamePassageTag,
storyPassageTags
storyPassageTags,
passageTagFrequencies
} from '../store/stories';
import {useUndoableStoriesContext} from '../store/undoable-stories';
import {Color} from '../util/color';
Expand All @@ -24,7 +25,7 @@ export const PassageTagsDialog: React.FC<PassageTagsDialogProps> = props => {

const story = storyWithId(stories, storyId);
const tags = storyPassageTags(story);

const tagCountsInStory = passageTagFrequencies(story);
function handleChangeColor(tagName: string, color: Color) {
dispatch(
setTagColor(story, tagName, color),
Expand Down Expand Up @@ -54,6 +55,7 @@ export const PassageTagsDialog: React.FC<PassageTagsDialogProps> = props => {
color={story.tagColors[tag]}
key={tag}
name={tag}
count={tagCountsInStory[tag]}
onChangeColor={color => handleChangeColor(tag, color)}
onChangeName={newName => handleChangeTagName(tag, newName)}
/>
Expand Down
4 changes: 3 additions & 1 deletion src/dialogs/story-tags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {useTranslation} from 'react-i18next';
import {DialogCard} from '../components/container/dialog-card';
import {CardContent} from '../components/container/card';
import {DialogComponentProps} from './dialogs.types';
import {renameStoryTag, storyTags} from '../store/stories';
import {renameStoryTag, storyTags, storyTagFrequencies} from '../store/stories';
import {setPref, usePrefsContext} from '../store/prefs';
import {useUndoableStoriesContext} from '../store/undoable-stories';
import {Color} from '../util/color';
Expand All @@ -17,6 +17,7 @@ export const StoryTagsDialog: React.FC<StoryTagsDialogProps> = props => {
const {t} = useTranslation();

const tags = storyTags(stories);
const tagCountsInStories = storyTagFrequencies(stories);

function handleChangeColor(tagName: string, color: Color) {
prefsDispatch(
Expand All @@ -43,6 +44,7 @@ export const StoryTagsDialog: React.FC<StoryTagsDialogProps> = props => {
color={prefs.storyTagColors[tag]}
key={tag}
name={tag}
count={tagCountsInStories[tag]}
onChangeColor={color => handleChangeColor(tag, color)}
onChangeName={newName => handleChangeTagName(tag, newName)}
/>
Expand Down
53 changes: 52 additions & 1 deletion src/store/stories/__tests__/getters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
storyWithName,
storyTags,
passagesMatchingSearch,
passagesMatchingFuzzySearch
passagesMatchingFuzzySearch,
passageTagFrequencies,
storyTagFrequencies
} from '../getters';
import {Passage, Story} from '../stories.types';
import {fakePassage, fakeStory} from '../../../test-util';
Expand Down Expand Up @@ -275,6 +277,55 @@ describe('storyPassageTags()', () => {
});
});

describe('passageTagFrequencies()', () => {
it('returns an object with correct counts of frequencies of tags across all passages in a story', () =>{
const story = fakeStory(3);
story.passages[0].tags = ['tag1', 'tag2'];
story.passages[1].tags = ['tag2', 'tag3'];
story.passages[2].tags = ['tag1'];

const expectedTagFrequencies ={
tag1: 2,
tag2: 2,
tag3: 1,
};

expect(passageTagFrequencies(story)).toEqual(expectedTagFrequencies);
});

it('returns empty object if no tags present', () => {
const story = fakeStory(2);
const expectedTagFrequencies ={};

expect(passageTagFrequencies(story)).toEqual(expectedTagFrequencies);
})

});

describe('storyTagFrequencies()', () => {
it('returns correct frequencies of tags of all stories', () => {
const stories = [fakeStory(), fakeStory()];

stories[0].tags = ['c', 'a'];
stories[1].tags = ['a', 'b'];

const expectedStoryTagFrequencies ={
a: 2,
b: 1,
c: 1,
};

expect(storyTagFrequencies(stories)).toEqual(expectedStoryTagFrequencies);
});

it('returns empty object with no tags', () => {
const stories = [fakeStory(), fakeStory()];
const expectedStoryTagFrequencies = {};

expect(storyTagFrequencies(stories)).toEqual(expectedStoryTagFrequencies);
});
});

describe('storyTags()', () => {
it('returns a sorted array of unique tags across stories', () => {
const stories = [fakeStory(), fakeStory()];
Expand Down
30 changes: 30 additions & 0 deletions src/store/stories/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,22 @@ export function storyPassageTags(story: Story) {
).sort();
}

export function passageTagFrequencies(story: Story) {
const tagPassageCounts: { [key: string]: number } = {};

story.passages.forEach(passage => {
if (passage.tags) {
passage.tags.forEach(tag=>{
if (!tagPassageCounts[tag]) {
tagPassageCounts[tag] = 1;
} else {
tagPassageCounts[tag] += 1;
}
})};
});
return tagPassageCounts;
}

export function storyStats(story: Story) {
const links = story.passages.reduce<string[]>(
(links, passage) => [
Expand Down Expand Up @@ -196,6 +212,20 @@ export function storyTags(stories: Story[]) {
).sort();
}

export function storyTagFrequencies(stories: Story[]) {
const tagFrequencies: {[key: string]: number} = {};

stories.forEach(story => {
if (story.tags) {
story.tags.forEach(tag => {
tagFrequencies[tag] = (tagFrequencies[tag] || 0) + 1;
});
}
});

return tagFrequencies;
}

export function storyWithId(stories: Story[], storyId: string) {
const result = stories.find(s => s.id === storyId);

Expand Down

0 comments on commit 4a82438

Please sign in to comment.