]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/app/menu/menu.component.ts
Instance homepage support (#4007)
[github/Chocobozzz/PeerTube.git] / client / src / app / menu / menu.component.ts
1 import { HotkeysService } from 'angular2-hotkeys'
2 import * as debug from 'debug'
3 import { switchMap } from 'rxjs/operators'
4 import { ViewportScroller } from '@angular/common'
5 import { Component, OnInit, ViewChild } from '@angular/core'
6 import { Router } from '@angular/router'
7 import {
8 AuthService,
9 AuthStatus,
10 AuthUser,
11 MenuLink,
12 MenuService,
13 RedirectService,
14 ScreenService,
15 ServerService,
16 UserService
17 } from '@app/core'
18 import { scrollToTop } from '@app/helpers'
19 import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
20 import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
21 import { PeertubeModalService } from '@app/shared/shared-main/peertube-modal/peertube-modal.service'
22 import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
23 import { ServerConfig, UserRight, VideoConstant } from '@shared/models'
24
25 const logger = debug('peertube:menu:MenuComponent')
26
27 @Component({
28 selector: 'my-menu',
29 templateUrl: './menu.component.html',
30 styleUrls: ['./menu.component.scss']
31 })
32 export class MenuComponent implements OnInit {
33 @ViewChild('languageChooserModal', { static: true }) languageChooserModal: LanguageChooserComponent
34 @ViewChild('quickSettingsModal', { static: true }) quickSettingsModal: QuickSettingsModalComponent
35 @ViewChild('dropdown') dropdown: NgbDropdown
36
37 user: AuthUser
38 isLoggedIn: boolean
39
40 userHasAdminAccess = false
41 helpVisible = false
42
43 videoLanguages: string[] = []
44 nsfwPolicy: string
45
46 currentInterfaceLanguage: string
47
48 commonMenuLinks: MenuLink[] = []
49
50 private languages: VideoConstant<string>[] = []
51 private serverConfig: ServerConfig
52 private routesPerRight: { [role in UserRight]?: string } = {
53 [UserRight.MANAGE_USERS]: '/admin/users',
54 [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
55 [UserRight.MANAGE_ABUSES]: '/admin/moderation/abuses',
56 [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/moderation/video-blocks',
57 [UserRight.MANAGE_JOBS]: '/admin/jobs',
58 [UserRight.MANAGE_CONFIGURATION]: '/admin/config'
59 }
60
61 constructor (
62 private viewportScroller: ViewportScroller,
63 private authService: AuthService,
64 private userService: UserService,
65 private serverService: ServerService,
66 private redirectService: RedirectService,
67 private hotkeysService: HotkeysService,
68 private screenService: ScreenService,
69 private menuService: MenuService,
70 private modalService: PeertubeModalService,
71 private router: Router
72 ) { }
73
74 get isInMobileView () {
75 return this.screenService.isInMobileView()
76 }
77
78 get dropdownContainer () {
79 if (this.isInMobileView) return null
80
81 return 'body' as 'body'
82 }
83
84 get language () {
85 return this.languageChooserModal.getCurrentLanguage()
86 }
87
88 get instanceName () {
89 return this.serverConfig.instance.name
90 }
91
92 ngOnInit () {
93 this.serverConfig = this.serverService.getTmpConfig()
94 this.serverService.getConfig()
95 .subscribe(config => {
96 this.serverConfig = config
97 this.buildMenuLinks()
98 })
99
100 this.isLoggedIn = this.authService.isLoggedIn()
101 if (this.isLoggedIn === true) {
102 this.user = this.authService.getUser()
103
104 this.computeNSFWPolicy()
105 this.computeVideosLink()
106 }
107
108 this.computeAdminAccess()
109
110 this.currentInterfaceLanguage = this.languageChooserModal.getCurrentLanguage()
111
112 this.authService.loginChangedSource.subscribe(
113 status => {
114 if (status === AuthStatus.LoggedIn) {
115 this.isLoggedIn = true
116 this.user = this.authService.getUser()
117
118 this.computeAdminAccess()
119 this.computeVideosLink()
120
121 logger('Logged in.')
122 } else if (status === AuthStatus.LoggedOut) {
123 this.isLoggedIn = false
124 this.user = undefined
125
126 this.computeAdminAccess()
127
128 logger('Logged out.')
129 } else {
130 console.error('Unknown auth status: ' + status)
131 }
132 }
133 )
134
135 this.hotkeysService.cheatSheetToggle
136 .subscribe(isOpen => this.helpVisible = isOpen)
137
138 this.serverService.getVideoLanguages()
139 .subscribe(languages => {
140 this.languages = languages
141
142 this.authService.userInformationLoaded
143 .subscribe(() => this.buildUserLanguages())
144 })
145
146 this.modalService.openQuickSettingsSubject
147 .subscribe(() => this.openQuickSettings())
148 }
149
150 isRegistrationAllowed () {
151 return this.serverConfig.signup.allowed &&
152 this.serverConfig.signup.allowedForCurrentIP
153 }
154
155 getFirstAdminRightAvailable () {
156 const user = this.authService.getUser()
157 if (!user) return undefined
158
159 const adminRights = [
160 UserRight.MANAGE_USERS,
161 UserRight.MANAGE_SERVER_FOLLOW,
162 UserRight.MANAGE_ABUSES,
163 UserRight.MANAGE_VIDEO_BLACKLIST,
164 UserRight.MANAGE_JOBS,
165 UserRight.MANAGE_CONFIGURATION
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]
181 }
182
183 logout (event: Event) {
184 event.preventDefault()
185
186 this.authService.logout()
187 // Redirect to home page
188 this.redirectService.redirectToHomepage()
189 }
190
191 openLanguageChooser () {
192 this.languageChooserModal.show()
193 }
194
195 openHotkeysCheatSheet () {
196 this.hotkeysService.cheatSheetToggle.next(!this.helpVisible)
197 }
198
199 openQuickSettings () {
200 this.quickSettingsModal.show()
201 }
202
203 toggleUseP2P () {
204 if (!this.user) return
205 this.user.webTorrentEnabled = !this.user.webTorrentEnabled
206
207 this.userService.updateMyProfile({ webTorrentEnabled: this.user.webTorrentEnabled })
208 .subscribe(() => this.authService.refreshUserInformation())
209 }
210
211 langForLocale (localeId: string) {
212 if (localeId === '_unknown') return $localize`Unknown`
213
214 return this.languages.find(lang => lang.id === localeId).label
215 }
216
217 onActiveLinkScrollToAnchor (link: HTMLAnchorElement) {
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)) {
223 scrollToTop('smooth')
224 }
225
226 // On same url with fragment restore anchor scroll position
227 if (linkHash && this.router.url === linkURL) {
228 this.viewportScroller.scrollToAnchor(linkHash)
229 }
230
231 if (this.screenService.isInSmallView()) {
232 this.menuService.toggleMenu()
233 }
234 }
235
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 = () => {
246 this.dropdown?.close()
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
259 private buildMenuLinks () {
260 this.commonMenuLinks = this.menuService.buildCommonLinks(this.serverConfig)
261 }
262
263 private buildUserLanguages () {
264 if (!this.user) {
265 this.videoLanguages = []
266 return
267 }
268
269 if (!this.user.videoLanguages) {
270 this.videoLanguages = [$localize`any language`]
271 return
272 }
273
274 this.videoLanguages = this.user.videoLanguages
275 .map(locale => this.langForLocale(locale))
276 .map(value => value === undefined ? '?' : value)
277 }
278
279 private computeAdminAccess () {
280 const right = this.getFirstAdminRightAvailable()
281
282 this.userHasAdminAccess = right !== undefined
283 }
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 }
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 }
315 }