Skip to content

Commit f99ddfe

Browse files
authored
Setup react-transition-group (#18)
* Install react-spring & clean up * Rename "repo" prop to "repoNotifications" * Replace react-spring with react-transition-group
1 parent 3509aaf commit f99ddfe

File tree

10 files changed

+163
-138
lines changed

10 files changed

+163
-138
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"react-final-form": "^6.3.3",
7272
"react-redux": "=7.1.3",
7373
"react-router-dom": "^5.1.2",
74+
"react-transition-group": "^4.3.0",
7475
"react-typist": "^2.0.5",
7576
"redux": "=4.0.5",
7677
"redux-storage": "=4.1.2",
@@ -88,6 +89,7 @@
8889
"@types/node": "^12.12.21",
8990
"@types/react": "^16.9.17",
9091
"@types/react-redux": "^7.1.5",
92+
"@types/react-transition-group": "^4.2.3",
9193
"@types/styled-components": "^4.4.1",
9294
"electron": "=7.1.9",
9395
"electron-packager": "=14.1.1",

src/js/actions/index.test.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -630,25 +630,6 @@ describe('actions/index.js', () => {
630630
});
631631
});
632632

633-
it('should search the notifications with a query', () => {
634-
const query = 'hello';
635-
636-
const expectedAction = {
637-
type: actions.SEARCH_NOTIFICATIONS,
638-
query,
639-
};
640-
641-
expect(actions.searchNotifications(query)).toEqual(expectedAction);
642-
});
643-
644-
it('should clear the search query', () => {
645-
const expectedAction = {
646-
type: actions.CLEAR_SEARCH,
647-
};
648-
649-
expect(actions.clearSearch()).toEqual(expectedAction);
650-
});
651-
652633
it('should update a setting for a user', () => {
653634
const setting = 'participating';
654635
const value = true;

src/js/actions/index.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -193,23 +193,6 @@ export function markRepoNotifications(repoSlug, hostname) {
193193
};
194194
}
195195

196-
// Search
197-
198-
export const SEARCH_NOTIFICATIONS = 'SEARCH_NOTIFICATIONS';
199-
export const CLEAR_SEARCH = 'CLEAR_SEARCH';
200-
export function searchNotifications(query) {
201-
return {
202-
type: SEARCH_NOTIFICATIONS,
203-
query: query,
204-
};
205-
}
206-
207-
export function clearSearch() {
208-
return {
209-
type: CLEAR_SEARCH,
210-
};
211-
}
212-
213196
// Settings
214197

215198
export const UPDATE_SETTING = 'UPDATE_SETTING';

src/js/app.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@ const GlobalStyle = createGlobalStyle`
102102
height: 2px;
103103
}
104104
}
105+
106+
.notification-exit {
107+
transform: translate3d(0px, 0, 0);
108+
opacity: 1;
109+
transition-duration: 250ms;
110+
transition-timing-function: cubic-bezier(0.175, 0.665, 0.32, 1), linear;
111+
112+
&.notification-exit-active {
113+
transform: translate3d(350px, 0, 0);
114+
opacity: 0;
115+
}
116+
}
105117
`;
106118

107119
const Wrapper = styled.div`
Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,55 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`components/repository.tsx should render itself & its children 1`] = `
4-
<div
5-
className="sc-bdVaJa dofWkW"
6-
>
4+
Array [
75
<div
8-
className="sc-bwzfXH gkcRsd"
6+
className="sc-bdVaJa dofWkW"
97
>
10-
<img
11-
className="sc-htpNat tFenb"
12-
src="https://avatars0.githubusercontent.com/u/6333409?v=3"
13-
/>
14-
<span
15-
onClick={[Function]}
8+
<div
9+
className="sc-bwzfXH gkcRsd"
1610
>
17-
manosim/gitify
18-
</span>
19-
</div>
20-
<div
21-
className="sc-bxivhb BLpai"
22-
>
23-
<button
24-
className="sc-ifAKCX eEESsB"
25-
onClick={[Function]}
11+
<img
12+
className="sc-htpNat tFenb"
13+
src="https://avatars0.githubusercontent.com/u/6333409?v=3"
14+
/>
15+
<span
16+
onClick={[Function]}
17+
>
18+
manosim/gitify
19+
</span>
20+
</div>
21+
<div
22+
className="sc-bxivhb BLpai"
2623
>
27-
<svg
28-
aria-hidden="false"
29-
aria-label="Mark Repository as Read"
30-
className="octicon"
31-
height={20}
32-
role="img"
33-
style={
34-
Object {
35-
"display": "inline-block",
36-
"fill": "currentColor",
37-
"userSelect": "none",
38-
"verticalAlign": "text-bottom",
39-
}
40-
}
41-
viewBox="0 0 12 16"
42-
width={15}
24+
<button
25+
className="sc-ifAKCX eEESsB"
26+
onClick={[Function]}
4327
>
44-
<path
45-
d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5L12 5z"
46-
fillRule="evenodd"
47-
/>
48-
</svg>
49-
</button>
50-
</div>
51-
</div>
28+
<svg
29+
aria-hidden="false"
30+
aria-label="Mark Repository as Read"
31+
className="octicon"
32+
height={20}
33+
role="img"
34+
style={
35+
Object {
36+
"display": "inline-block",
37+
"fill": "currentColor",
38+
"userSelect": "none",
39+
"verticalAlign": "text-bottom",
40+
}
41+
}
42+
viewBox="0 0 12 16"
43+
width={15}
44+
>
45+
<path
46+
d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5L12 5z"
47+
fillRule="evenodd"
48+
/>
49+
</svg>
50+
</button>
51+
</div>
52+
</div>,
53+
<div />,
54+
]
5255
`;

src/js/components/account-notifications.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ export const AccountNotifications = (props: IProps) => {
5454
<RepositoryNotifications
5555
key={repoSlug}
5656
hostname={hostname}
57-
repo={repoNotifications}
5857
repoName={repoSlug}
58+
repoNotifications={repoNotifications}
5959
/>
6060
);
6161
})}

src/js/components/notification.tsx

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -69,59 +69,57 @@ interface IProps {
6969
markNotification: (id: string, hostname: string) => void;
7070
}
7171

72-
export class NotificationItem extends React.Component<IProps, {}> {
73-
pressTitle() {
74-
this.openBrowser();
72+
export const NotificationItem: React.FC<IProps> = props => {
73+
const pressTitle = () => {
74+
openBrowser();
7575

76-
if (this.props.markOnClick) {
77-
this.markAsRead();
76+
if (props.markOnClick) {
77+
markAsRead();
7878
}
79-
}
79+
};
8080

81-
openBrowser() {
82-
const url = generateGitHubWebUrl(this.props.notification.subject.url);
81+
const openBrowser = () => {
82+
const url = generateGitHubWebUrl(props.notification.subject.url);
8383
shell.openExternal(url);
84-
}
84+
};
8585

86-
markAsRead() {
87-
const { hostname, notification } = this.props;
88-
this.props.markNotification(notification.id, hostname);
89-
}
86+
const markAsRead = () => {
87+
const { hostname, notification } = props;
88+
props.markNotification(notification.id, hostname);
89+
};
9090

91-
render() {
92-
const { notification } = this.props;
93-
const reason = formatReason(notification.reason);
94-
const typeIcon = getNotificationTypeIcon(notification.subject.type);
95-
const updatedAt = formatDistanceToNow(parseISO(notification.updated_at), {
96-
addSuffix: true,
97-
});
98-
99-
return (
100-
<Wrapper>
101-
<IconWrapper>
102-
<Octicon
103-
icon={getIconByName(typeIcon)}
104-
size={20}
105-
ariaLabel={notification.subject.type}
106-
/>
107-
</IconWrapper>
108-
<Main onClick={() => this.pressTitle()} role="main">
109-
<Title>{notification.subject.title}</Title>
110-
111-
<Details>
112-
<span title={reason.description}>{reason.type}</span> - Updated{' '}
113-
{updatedAt}
114-
</Details>
115-
</Main>
116-
<IconWrapper>
117-
<Button onClick={() => this.markAsRead()}>
118-
<Octicon icon={Check} size={20} ariaLabel="Mark as Read" />
119-
</Button>
120-
</IconWrapper>
121-
</Wrapper>
122-
);
123-
}
124-
}
91+
const { notification } = props;
92+
const reason = formatReason(notification.reason);
93+
const typeIcon = getNotificationTypeIcon(notification.subject.type);
94+
const updatedAt = formatDistanceToNow(parseISO(notification.updated_at), {
95+
addSuffix: true,
96+
});
97+
98+
return (
99+
<Wrapper>
100+
<IconWrapper>
101+
<Octicon
102+
icon={getIconByName(typeIcon)}
103+
size={20}
104+
ariaLabel={notification.subject.type}
105+
/>
106+
</IconWrapper>
107+
<Main onClick={() => pressTitle()} role="main">
108+
<Title>{notification.subject.title}</Title>
109+
110+
<Details>
111+
<span title={reason.description}>{reason.type}</span> - Updated{' '}
112+
{updatedAt}
113+
</Details>
114+
</Main>
115+
<IconWrapper>
116+
<Button onClick={() => markAsRead()}>
117+
<Octicon icon={Check} size={20} ariaLabel="Mark as Read" />
118+
</Button>
119+
</IconWrapper>
120+
</Wrapper>
121+
);
122+
};
125123

126124
export function mapStateToProps(state: AppState) {
127125
return {

src/js/components/repository.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ jest.mock('./notification');
1212
describe('components/repository.tsx', function() {
1313
const props = {
1414
hostname: 'github.com',
15-
repo: mockedGithubNotifications,
1615
repoName: 'manosim/gitify',
16+
repoNotifications: mockedGithubNotifications,
1717
markRepoNotifications: jest.fn(),
1818
};
1919

src/js/components/repository.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as React from 'react';
44
import styled from 'styled-components';
55
import { connect } from 'react-redux';
66
import Octicon, { Check } from '@primer/octicons-react';
7+
import { CSSTransition, TransitionGroup } from 'react-transition-group';
78

89
import { markRepoNotifications } from '../actions';
910
import { Notification } from '../../types/github';
@@ -53,25 +54,25 @@ const Button = styled.button`
5354

5455
interface IProps {
5556
hostname: string;
56-
repo: Notification[];
57+
repoNotifications: Notification[];
5758
repoName: string;
5859
markRepoNotifications: (repoSlug: string, hostname: string) => void;
5960
}
6061

61-
export const RepositoryNotifications = (props: IProps) => {
62+
export const RepositoryNotifications: React.FC<IProps> = props => {
6263
const openBrowser = () => {
63-
const url = props.repo[0].repository.html_url;
64+
const url = props.repoNotifications[0].repository.html_url;
6465
shell.openExternal(url);
6566
};
6667

6768
const markRepoAsRead = () => {
68-
const { hostname, repo } = props;
69-
const repoSlug = repo[0].repository.full_name;
69+
const { hostname, repoNotifications } = props;
70+
const repoSlug = repoNotifications[0].repository.full_name;
7071
props.markRepoNotifications(repoSlug, hostname);
7172
};
7273

73-
const { hostname, repo } = props;
74-
const avatarUrl = repo[0].repository.owner.avatar_url;
74+
const { hostname, repoNotifications } = props;
75+
const avatarUrl = repoNotifications[0].repository.owner.avatar_url;
7576

7677
return (
7778
<>
@@ -92,9 +93,17 @@ export const RepositoryNotifications = (props: IProps) => {
9293
</IconWrapper>
9394
</Wrapper>
9495

95-
{repo.map(obj => (
96-
<NotificationItem key={obj.id} hostname={hostname} notification={obj} />
97-
))}
96+
<TransitionGroup>
97+
{repoNotifications.map(obj => (
98+
<CSSTransition key={obj.id} timeout={250} classNames="notification">
99+
<NotificationItem
100+
key={obj.id}
101+
hostname={hostname}
102+
notification={obj}
103+
/>
104+
</CSSTransition>
105+
))}
106+
</TransitionGroup>
98107
</>
99108
);
100109
};

0 commit comments

Comments
 (0)