1
1
import React , { useRef , useCallback } from 'react' ;
2
- import styled from 'styled-components' ;
3
- import { SearchIcon2 } from '../../static/svg' ;
2
+ import styled , { css } from 'styled-components' ;
3
+ import { NotificationIcon , SearchIcon3 } from '../../static/svg' ;
4
4
import RoundButton from '../common/RoundButton' ;
5
5
import MainResponsive from '../main/MainResponsive' ;
6
6
import useHeader from './hooks/useHeader' ;
@@ -11,19 +11,21 @@ import { Link } from 'react-router-dom';
11
11
import media from '../../lib/styles/media' ;
12
12
import HeaderLogo from './HeaderLogo' ;
13
13
import { themedPalette } from '../../lib/styles/themes' ;
14
- import ThemeToggleButton from './ThemeToggleButton' ;
15
- import { useSelector } from 'react-redux' ;
16
- import { RootState } from '../../modules' ;
14
+ import VLink from '../common/VLink' ;
15
+ import { useDispatch } from 'react-redux' ;
16
+ import { showAuthModal } from '../../modules/core' ;
17
+ import { useQuery } from '@apollo/react-hooks' ;
18
+ import { NOTIFICATION_COUNT } from '../../lib/graphql/notification' ;
17
19
18
20
export type MainHeaderProps = { } ;
19
21
20
22
function Header ( props : MainHeaderProps ) {
23
+ const dispatch = useDispatch ( ) ;
24
+ const { data : notificationCountData } = useQuery ( NOTIFICATION_COUNT ) ;
25
+
21
26
const { user, onLoginClick, onLogout, customHeader } = useHeader ( ) ;
22
27
const [ userMenu , toggleUserMenu ] = useToggle ( false ) ;
23
28
const ref = useRef < HTMLDivElement > ( null ) ;
24
- const themeReady = useSelector (
25
- ( state : RootState ) => state . darkMode . systemTheme !== 'not-ready' ,
26
- ) ;
27
29
28
30
const onOutsideClick = useCallback (
29
31
( e : React . MouseEvent ) => {
@@ -34,6 +36,15 @@ function Header(props: MainHeaderProps) {
34
36
[ toggleUserMenu ] ,
35
37
) ;
36
38
39
+ const onClickNotification = ( event : React . MouseEvent < HTMLAnchorElement > ) => {
40
+ if ( ! user ) {
41
+ event . preventDefault ( ) ;
42
+ dispatch ( showAuthModal ( 'LOGIN' ) ) ;
43
+ return ;
44
+ }
45
+ } ;
46
+
47
+ const notificationCount = notificationCountData ?. notificationCount ?? 0 ;
37
48
const urlForSearch = customHeader . custom
38
49
? `/search?username=${ customHeader . username } `
39
50
: '/search' ;
@@ -46,44 +57,48 @@ function Header(props: MainHeaderProps) {
46
57
userLogo = { customHeader . userLogo }
47
58
username = { customHeader . username }
48
59
/>
60
+ < Right >
61
+ < NotificationButton to = "/notifications" onClick = { onClickNotification } >
62
+ { user && notificationCount !== 0 && (
63
+ < NotificationCounter
64
+ isSingle = { Math . floor ( notificationCount / 10 ) === 0 }
65
+ >
66
+ { Math . min ( 99 , notificationCount ) }
67
+ </ NotificationCounter >
68
+ ) }
69
+ < NotificationIcon />
70
+ </ NotificationButton >
71
+ < SearchButton to = { urlForSearch } >
72
+ < SearchIcon3 />
73
+ </ SearchButton >
74
+ { user ? (
75
+ < >
76
+ < RoundButton
77
+ border
78
+ color = "darkGray"
79
+ style = { { marginRight : '1.25rem' } }
80
+ to = "/write"
81
+ className = "write-button"
82
+ >
83
+ 새 글 작성
84
+ </ RoundButton >
49
85
50
- { user ? (
51
- < Right >
52
- { themeReady && < ThemeToggleButton /> }
53
- < SearchButton to = { urlForSearch } >
54
- < SearchIcon2 />
55
- </ SearchButton >
56
- < RoundButton
57
- border
58
- color = "darkGray"
59
- style = { { marginRight : '1.25rem' } }
60
- to = "/write"
61
- className = "write-button"
62
- >
63
- 새 글 작성
64
- </ RoundButton >
65
-
66
- < div ref = { ref } >
67
- < HeaderUserIcon user = { user } onClick = { toggleUserMenu } />
68
- </ div >
69
- < HeaderUserMenu
70
- onClose = { onOutsideClick }
71
- onLogout = { onLogout }
72
- username = { user . username }
73
- visible = { userMenu }
74
- />
75
- </ Right >
76
- ) : (
77
- < Right >
78
- { themeReady && < ThemeToggleButton /> }
79
- < SearchButton to = { urlForSearch } >
80
- < SearchIcon2 />
81
- </ SearchButton >
86
+ < div ref = { ref } >
87
+ < HeaderUserIcon user = { user } onClick = { toggleUserMenu } />
88
+ </ div >
89
+ < HeaderUserMenu
90
+ onClose = { onOutsideClick }
91
+ onLogout = { onLogout }
92
+ username = { user . username }
93
+ visible = { userMenu }
94
+ />
95
+ </ >
96
+ ) : (
82
97
< RoundButton color = "darkGray" onClick = { onLoginClick } >
83
98
로그인
84
99
</ RoundButton >
85
- </ Right >
86
- ) }
100
+ ) }
101
+ </ Right >
87
102
</ Inner >
88
103
</ Block >
89
104
) ;
@@ -114,12 +129,53 @@ const SearchButton = styled(Link)`
114
129
background: ${ themedPalette . slight_layer } ;
115
130
}
116
131
svg {
117
- width: 1.125rem ;
118
- height: 1.125rem ;
132
+ width: 24px ;
133
+ height: 24px ;
119
134
}
120
135
margin-right: 0.5rem;
121
136
` ;
122
137
138
+ const NotificationButton = styled ( VLink ) `
139
+ position: relative;
140
+ display: flex;
141
+ align-items: center;
142
+ justify-content: center;
143
+ background: transparent;
144
+ border: none;
145
+ width: 2.5rem;
146
+ height: 2.5rem;
147
+ outline: none;
148
+ border-radius: 50%;
149
+ color: ${ themedPalette . text1 } ;
150
+ cursor: pointer;
151
+ margin-right: 4px;
152
+ &:hover {
153
+ background: ${ themedPalette . slight_layer } ;
154
+ }
155
+ svg {
156
+ width: 24px;
157
+ height: 24px;
158
+ }
159
+ ` ;
160
+
161
+ const NotificationCounter = styled . div < { isSingle : boolean } > `
162
+ position: absolute;
163
+ top: 3px;
164
+ right: -3px;
165
+ padding: 1px 4px;
166
+ font-weight: 500;
167
+ font-size: 11px;
168
+ background-color: var(--primary1);
169
+ color: var(--button-text);
170
+ border-radius: 100px;
171
+
172
+ ${ ( props ) =>
173
+ props . isSingle &&
174
+ css `
175
+ right: 4px;
176
+ ` }
177
+ ` ;
178
+
123
179
const Inner = styled ( MainResponsive ) `
124
180
height: 100%;
125
181
display: flex;
0 commit comments