Skip to content

Commit ef030df

Browse files
committed
feat(metrics): add reaction metric pill
Signed-off-by: Adam Setch <adam.setch@outlook.com>
1 parent 1666b5c commit ef030df

File tree

4 files changed

+94
-51
lines changed

4 files changed

+94
-51
lines changed

src/renderer/components/metrics/MetricGroup.tsx

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useAppContext } from '../../hooks/useAppContext';
1313
import { type GitifyNotification, IconColor } from '../../types';
1414

1515
import { getPullRequestReviewIcon } from '../../utils/icons';
16+
import { formatMetricDescription } from '../../utils/notifications/formatters';
1617
import { MetricPill } from './MetricPill';
1718

1819
export interface MetricGroupProps {
@@ -26,11 +27,11 @@ export const MetricGroup: FC<MetricGroupProps> = ({
2627

2728
const linkedIssues = notification.subject.linkedIssues ?? [];
2829
const hasLinkedIssues = linkedIssues.length > 0;
29-
const linkedIssuesPillDescription = hasLinkedIssues
30-
? `Linked to ${
31-
linkedIssues.length > 1 ? 'issues:' : 'issue'
32-
} ${linkedIssues.join(', ')}`
33-
: '';
30+
const linkedIssuesPillDescription = formatMetricDescription(
31+
linkedIssues.length,
32+
'issue',
33+
(count, noun) => `Linked to ${count} ${noun}: ${linkedIssues.join(', ')}`,
34+
);
3435

3536
const reactionCount = notification.subject.reactionsCount ?? 0;
3637
const reactionGroups = notification.subject.reactionGroups ?? [];
@@ -48,40 +49,41 @@ export const MetricGroup: FC<MetricGroupProps> = ({
4849
HEART: '❤️',
4950
};
5051

51-
const reactionPillDescription = hasReactions
52-
? `${reactionCount} ${
53-
reactionCount > 1 ? 'reactions' : 'reaction'
54-
}: ${reactionGroups
55-
.reduce((acc, rg) => {
56-
if (!rg.reactors.totalCount || rg.reactors.totalCount <= 0) {
57-
return acc;
58-
}
59-
52+
const reactionPillDescription = formatMetricDescription(
53+
reactionCount,
54+
'reaction',
55+
(count, noun) => {
56+
const formatted = reactionGroups
57+
.map((rg) => {
6058
const emoji = reactionEmojiMap[rg.content];
61-
if (!emoji) {
62-
return acc;
59+
if (!emoji || !rg.reactors.totalCount) {
60+
return '';
6361
}
6462

65-
acc.push(
66-
`${emoji} ${hasMultipleReactions ? rg.reactors.totalCount : ''}`.trim(),
67-
);
68-
return acc;
69-
}, [] as string[])
70-
.join(' ')}`
71-
: '';
63+
return `${emoji} ${hasMultipleReactions ? rg.reactors.totalCount : ''}`.trim();
64+
})
65+
.filter(Boolean)
66+
.join(' ');
67+
return `${count} ${noun}: ${formatted}`;
68+
},
69+
);
7270

7371
const commentCount = notification.subject.commentCount ?? 0;
7472
const hasComments = commentCount > 0;
75-
const commentsPillDescription = hasComments
76-
? `${notification.subject.commentCount} ${notification.subject.commentCount > 1 ? 'comments' : 'comment'}`
77-
: '';
73+
const commentsPillDescription = formatMetricDescription(
74+
commentCount,
75+
'comment',
76+
);
7877

7978
const labels = notification.subject.labels ?? [];
8079
const labelsCount = labels.length;
8180
const hasLabels = labelsCount > 0;
82-
const labelsPillDescription = hasLabels
83-
? `${labelsCount} ${labelsCount > 1 ? 'labels' : 'label'}: ${labels.map((label) => `🏷️ ${label}`).join(', ')}`
84-
: '';
81+
const labelsPillDescription = formatMetricDescription(
82+
labelsCount,
83+
'label',
84+
(count, noun) =>
85+
`${count} ${noun}: ${labels.map((label) => `🏷️ ${label}`).join(', ')}`,
86+
);
8587

8688
const milestone = notification.subject.milestone;
8789

src/renderer/components/metrics/__snapshots__/MetricGroup.test.tsx.snap

Lines changed: 22 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/renderer/utils/notifications/formatters.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { mockPartialGitifyNotification } from '../../__mocks__/notifications-moc
22

33
import {
44
formatForDisplay,
5+
formatMetricDescription,
56
formatNotificationNumber,
67
formatNotificationTitle,
78
formatNotificationType,
@@ -87,4 +88,26 @@ describe('renderer/utils/notifications/formatters.ts', () => {
8788
expect(formatNotificationTitle(notification)).toBe('Improve docs');
8889
});
8990
});
91+
92+
describe('formatMetricDescription', () => {
93+
it('return empty if no count', () => {
94+
expect(formatMetricDescription(null, 'bee')).toBe('');
95+
});
96+
97+
it('return singular if count is 1', () => {
98+
expect(formatMetricDescription(1, 'bee')).toBe('1 bee');
99+
});
100+
101+
it('return pluralized if count is more than 1', () => {
102+
expect(formatMetricDescription(2, 'bee')).toBe('2 bees');
103+
});
104+
105+
it('return with custom formatter', () => {
106+
expect(
107+
formatMetricDescription(2, 'bee', (_count, noun) => {
108+
return `Hi ${noun}`;
109+
}),
110+
).toBe('Hi bees');
111+
});
112+
});
90113
});

src/renderer/utils/notifications/formatters.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,21 @@ export function formatNotificationTitle(
9191

9292
return title;
9393
}
94+
95+
/**
96+
* Helper to format the metric description, determine singular or plural noun,
97+
* and apply a custom formatter if needed.
98+
*/
99+
export function formatMetricDescription(
100+
count: number,
101+
singular: string,
102+
formatter?: (count: number, noun: string) => string,
103+
) {
104+
if (!count) {
105+
return '';
106+
}
107+
108+
const noun = count === 1 ? singular : `${singular}s`;
109+
110+
return formatter ? formatter(count, noun) : `${count} ${noun}`;
111+
}

0 commit comments

Comments
 (0)