]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/menu/menu.component.ts
Instance homepage support (#4007)
[github/Chocobozzz/PeerTube.git] / client / src / app / menu / menu.component.ts
CommitLineData
67ed6552 1import { HotkeysService } from 'angular2-hotkeys'
dfe3f7b7
K
2import * as debug from 'debug'
3import { switchMap } from 'rxjs/operators'
27f4a1ec 4import { ViewportScroller } from '@angular/common'
8afc19a6 5import { Component, OnInit, ViewChild } from '@angular/core'
30d55e75 6import { Router } from '@angular/router'
2539932e
C
7import {
8 AuthService,
9 AuthStatus,
10 AuthUser,
11 MenuLink,
12 MenuService,
13 RedirectService,
14 ScreenService,
15 ServerService,
16 UserService
17} from '@app/core'
27f4a1ec 18import { scrollToTop } from '@app/helpers'
8afc19a6 19import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
d3217560 20import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
43a3d281 21import { PeertubeModalService } from '@app/shared/shared-main/peertube-modal/peertube-modal.service'
27f4a1ec
C
22import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
23import { ServerConfig, UserRight, VideoConstant } from '@shared/models'
602eb142 24
dfe3f7b7
K
25const logger = debug('peertube:menu:MenuComponent')
26
602eb142
C
27@Component({
28 selector: 'my-menu',
383bfc83 29 templateUrl: './menu.component.html',
dfe3f7b7 30 styleUrls: ['./menu.component.scss']
602eb142
C
31})
32export class MenuComponent implements OnInit {
f36da21e 33 @ViewChild('languageChooserModal', { static: true }) languageChooserModal: LanguageChooserComponent
d3217560 34 @ViewChild('quickSettingsModal', { static: true }) quickSettingsModal: QuickSettingsModalComponent
51a83970 35 @ViewChild('dropdown') dropdown: NgbDropdown
8afc19a6 36
dfe3f7b7 37 user: AuthUser
df98563e 38 isLoggedIn: boolean
d3217560 39
954605a8 40 userHasAdminAccess = false
4a216666 41 helpVisible = false
954605a8 42
111fdc26 43 videoLanguages: string[] = []
68f6c87a
C
44 nsfwPolicy: string
45
68f6c87a 46 currentInterfaceLanguage: string
111fdc26 47
2539932e
C
48 commonMenuLinks: MenuLink[] = []
49
111fdc26 50 private languages: VideoConstant<string>[] = []
ba430d75 51 private serverConfig: ServerConfig
dfe3f7b7 52 private routesPerRight: { [role in UserRight]?: string } = {
954605a8 53 [UserRight.MANAGE_USERS]: '/admin/users',
4610bc5b 54 [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
d95d1559 55 [UserRight.MANAGE_ABUSES]: '/admin/moderation/abuses',
3487330d 56 [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/moderation/video-blocks',
ad76628b
C
57 [UserRight.MANAGE_JOBS]: '/admin/jobs',
58 [UserRight.MANAGE_CONFIGURATION]: '/admin/config'
954605a8 59 }
602eb142
C
60
61 constructor (
f3081d64 62 private viewportScroller: ViewportScroller,
602eb142 63 private authService: AuthService,
d3217560 64 private userService: UserService,
db7af09b 65 private serverService: ServerService,
8c985ef5 66 private redirectService: RedirectService,
d3217560 67 private hotkeysService: HotkeysService,
30d55e75
K
68 private screenService: ScreenService,
69 private menuService: MenuService,
43a3d281 70 private modalService: PeertubeModalService,
30d55e75 71 private router: Router
27f4a1ec 72 ) { }
51a83970
K
73
74 get isInMobileView () {
75 return this.screenService.isInMobileView()
76 }
77
78 get dropdownContainer () {
27f4a1ec
C
79 if (this.isInMobileView) return null
80
81 return 'body' as 'body'
51a83970
K
82 }
83
84 get language () {
85 return this.languageChooserModal.getCurrentLanguage()
86 }
ca4b1594 87
17119e4a
C
88 get instanceName () {
89 return this.serverConfig.instance.name
90 }
91
df98563e 92 ngOnInit () {
ba430d75
C
93 this.serverConfig = this.serverService.getTmpConfig()
94 this.serverService.getConfig()
2539932e
C
95 .subscribe(config => {
96 this.serverConfig = config
97 this.buildMenuLinks()
98 })
ba430d75 99
df98563e 100 this.isLoggedIn = this.authService.isLoggedIn()
dfe3f7b7
K
101 if (this.isLoggedIn === true) {
102 this.user = this.authService.getUser()
68f6c87a
C
103
104 this.computeNSFWPolicy()
dfe3f7b7
K
105 this.computeVideosLink()
106 }
107
108 this.computeAdminAccess()
602eb142 109
68f6c87a
C
110 this.currentInterfaceLanguage = this.languageChooserModal.getCurrentLanguage()
111
602eb142
C
112 this.authService.loginChangedSource.subscribe(
113 status => {
114 if (status === AuthStatus.LoggedIn) {
df98563e 115 this.isLoggedIn = true
b33f657c 116 this.user = this.authService.getUser()
dfe3f7b7
K
117
118 this.computeAdminAccess()
119 this.computeVideosLink()
120
121 logger('Logged in.')
602eb142 122 } else if (status === AuthStatus.LoggedOut) {
df98563e 123 this.isLoggedIn = false
b33f657c 124 this.user = undefined
dfe3f7b7
K
125
126 this.computeAdminAccess()
127
128 logger('Logged out.')
602eb142 129 } else {
df98563e 130 console.error('Unknown auth status: ' + status)
602eb142
C
131 }
132 }
df98563e 133 )
4a216666 134
111fdc26 135 this.hotkeysService.cheatSheetToggle
dfe3f7b7 136 .subscribe(isOpen => this.helpVisible = isOpen)
111fdc26
C
137
138 this.serverService.getVideoLanguages()
dfe3f7b7
K
139 .subscribe(languages => {
140 this.languages = languages
d3217560 141
dfe3f7b7
K
142 this.authService.userInformationLoaded
143 .subscribe(() => this.buildUserLanguages())
144 })
43a3d281 145
146 this.modalService.openQuickSettingsSubject
147 .subscribe(() => this.openQuickSettings())
d3217560
RK
148 }
149
291e8d3e 150 isRegistrationAllowed () {
ba430d75 151 return this.serverConfig.signup.allowed &&
dfe3f7b7 152 this.serverConfig.signup.allowedForCurrentIP
a184c71b
C
153 }
154
954605a8
C
155 getFirstAdminRightAvailable () {
156 const user = this.authService.getUser()
157 if (!user) return undefined
158
159 const adminRights = [
160 UserRight.MANAGE_USERS,
4610bc5b 161 UserRight.MANAGE_SERVER_FOLLOW,
d95d1559 162 UserRight.MANAGE_ABUSES,
3487330d 163 UserRight.MANAGE_VIDEO_BLACKLIST,
ad76628b
C
164 UserRight.MANAGE_JOBS,
165 UserRight.MANAGE_CONFIGURATION
954605a8
C
166 ]
167
168 for (const adminRight of adminRights) {
169 if (user.hasRight(adminRight)) {
170 return adminRight
171 }
172 }
173
174 return undefined
175 }
176
177 getFirstAdminRouteAvailable () {
178 const right = this.getFirstAdminRightAvailable()
179
180 return this.routesPerRight[right]
602eb142
C
181 }
182
b33f657c
C
183 logout (event: Event) {
184 event.preventDefault()
185
df98563e 186 this.authService.logout()
602eb142 187 // Redirect to home page
b1d40cff 188 this.redirectService.redirectToHomepage()
602eb142 189 }
954605a8 190
8afc19a6
C
191 openLanguageChooser () {
192 this.languageChooserModal.show()
193 }
194
4a216666
RK
195 openHotkeysCheatSheet () {
196 this.hotkeysService.cheatSheetToggle.next(!this.helpVisible)
197 }
198
d3217560
RK
199 openQuickSettings () {
200 this.quickSettingsModal.show()
201 }
202
203 toggleUseP2P () {
204 if (!this.user) return
205 this.user.webTorrentEnabled = !this.user.webTorrentEnabled
111fdc26
C
206
207 this.userService.updateMyProfile({ webTorrentEnabled: this.user.webTorrentEnabled })
dfe3f7b7 208 .subscribe(() => this.authService.refreshUserInformation())
d3217560
RK
209 }
210
8ada87ac 211 langForLocale (localeId: string) {
66357162 212 if (localeId === '_unknown') return $localize`Unknown`
bb3933ef 213
111fdc26
C
214 return this.languages.find(lang => lang.id === localeId).label
215 }
216
f3081d64 217 onActiveLinkScrollToAnchor (link: HTMLAnchorElement) {
30d55e75
K
218 const linkURL = link.getAttribute('href')
219 const linkHash = link.getAttribute('fragment')
220
221 // On same url without fragment restore top scroll position
222 if (!linkHash && this.router.url.includes(linkURL)) {
f3081d64 223 scrollToTop('smooth')
30d55e75
K
224 }
225
226 // On same url with fragment restore anchor scroll position
227 if (linkHash && this.router.url === linkURL) {
f3081d64 228 this.viewportScroller.scrollToAnchor(linkHash)
30d55e75
K
229 }
230
231 if (this.screenService.isInSmallView()) {
232 this.menuService.toggleMenu()
233 }
234 }
235
51a83970
K
236 // Lock menu scroll when menu scroll to avoid fleeing / detached dropdown
237 onMenuScrollEvent () {
238 document.querySelector('menu').scrollTo(0, 0)
239 }
240
241 onDropdownOpenChange (opened: boolean) {
242 if (this.screenService.isInMobileView()) return
243
244 // Close dropdown when window scroll to avoid dropdown quick jump for re-position
245 const onWindowScroll = () => {
56f08761 246 this.dropdown?.close()
51a83970
K
247 window.removeEventListener('scroll', onWindowScroll)
248 }
249
250 if (opened) {
251 window.addEventListener('scroll', onWindowScroll)
252 document.querySelector('menu').scrollTo(0, 0) // Reset menu scroll to easy lock
253 document.querySelector('menu').addEventListener('scroll', this.onMenuScrollEvent)
254 } else {
255 document.querySelector('menu').removeEventListener('scroll', this.onMenuScrollEvent)
256 }
257 }
258
2539932e
C
259 private buildMenuLinks () {
260 this.commonMenuLinks = this.menuService.buildCommonLinks(this.serverConfig)
261 }
262
111fdc26
C
263 private buildUserLanguages () {
264 if (!this.user) {
265 this.videoLanguages = []
266 return
267 }
268
269 if (!this.user.videoLanguages) {
66357162 270 this.videoLanguages = [$localize`any language`]
111fdc26
C
271 return
272 }
273
274 this.videoLanguages = this.user.videoLanguages
dfe3f7b7
K
275 .map(locale => this.langForLocale(locale))
276 .map(value => value === undefined ? '?' : value)
d3217560
RK
277 }
278
dfe3f7b7 279 private computeAdminAccess () {
954605a8
C
280 const right = this.getFirstAdminRightAvailable()
281
282 this.userHasAdminAccess = right !== undefined
283 }
dfe3f7b7
K
284
285 private computeVideosLink () {
286 this.authService.userInformationLoaded
287 .pipe(
288 switchMap(() => this.user.computeCanSeeVideosLink(this.userService.getMyVideoQuotaUsed()))
289 ).subscribe(res => {
290 if (res === true) logger('User can see videos link.')
291 else logger('User cannot see videos link.')
292 })
293 }
68f6c87a
C
294
295 private computeNSFWPolicy () {
296 if (!this.user) {
297 this.nsfwPolicy = null
298 return
299 }
300
301 switch (this.user.nsfwPolicy) {
302 case 'do_not_list':
303 this.nsfwPolicy = $localize`hide`
304 break
305
306 case 'blur':
307 this.nsfwPolicy = $localize`blur`
308 break
309
310 case 'display':
311 this.nsfwPolicy = $localize`display`
312 break
313 }
314 }
602eb142 315}