Inform user to fill account profile and channels (#4352)
* Add account-setup modal when login * Add channels-setup alert into my-channels, my-playlists and upload page Co-authored-by: Ms Kimsible <kimsible@users.noreply.github.com>
This commit is contained in:
parent
8729a87024
commit
7dca45f99d
|
@ -526,7 +526,7 @@
|
||||||
# Icons
|
# Icons
|
||||||
|
|
||||||
* [Feather Icons](https://feathericons.com) (MIT)
|
* [Feather Icons](https://feathericons.com) (MIT)
|
||||||
* `playlist add`, `history`, `subscriptions`, `miscellaneous-services.svg` by Material UI (Apache 2.0)
|
* `playlist add`, `history`, `subscriptions`, `miscellaneous-services.svg`, `tip` by Material UI (Apache 2.0)
|
||||||
* `support` by Chocobozzz (CC-BY)
|
* `support` by Chocobozzz (CC-BY)
|
||||||
* `language` by Aaron Jin (CC-BY)
|
* `language` by Aaron Jin (CC-BY)
|
||||||
* `video-language` by Rigel Kent (CC-BY)
|
* `video-language` by Rigel Kent (CC-BY)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
<span class="badge badge-secondary">{{ totalItems }}</span>
|
<span class="badge badge-secondary">{{ totalItems }}</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<my-channels-setup-message [hideLink]="true"></my-channels-setup-message>
|
||||||
|
|
||||||
<div class="video-channels-header d-flex justify-content-between">
|
<div class="video-channels-header d-flex justify-content-between">
|
||||||
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
|
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
<ng-container i18n>My playlists</ng-container> <span class="badge badge-secondary">{{ pagination.totalItems }}</span>
|
<ng-container i18n>My playlists</ng-container> <span class="badge badge-secondary">{{ pagination.totalItems }}</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<my-channels-setup-message></my-channels-setup-message>
|
||||||
|
|
||||||
<div class="video-playlists-header d-flex justify-content-between">
|
<div class="video-playlists-header d-flex justify-content-between">
|
||||||
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
|
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
<ng-container *ngIf="secondStepType === 'upload'" i18n>Upload {{ videoName }}</ng-container>
|
<ng-container *ngIf="secondStepType === 'upload'" i18n>Upload {{ videoName }}</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<my-channels-setup-message></my-channels-setup-message>
|
||||||
|
|
||||||
<div ngbNav #nav="ngbNav" class="nav-tabs video-add-nav" [activeId]="activeNav" (activeIdChange)="onNavChange($event)" [ngClass]="{ 'hide-nav': !!secondStepType }">
|
<div ngbNav #nav="ngbNav" class="nav-tabs video-add-nav" [activeId]="activeNav" (activeIdChange)="onNavChange($event)" [ngClass]="{ 'hide-nav': !!secondStepType }">
|
||||||
<ng-container ngbNavItem="upload">
|
<ng-container ngbNavItem="upload">
|
||||||
<a ngbNavLink>
|
<a ngbNavLink>
|
||||||
|
|
|
@ -60,9 +60,10 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-toast>
|
</p-toast>
|
||||||
|
|
||||||
<ng-template [ngIf]="isUserLoggedIn()">
|
<ng-container *ngIf="isUserLoggedIn()">
|
||||||
|
<my-account-setup-modal #accountSetupModal></my-account-setup-modal>
|
||||||
<my-welcome-modal #welcomeModal></my-welcome-modal>
|
<my-welcome-modal #welcomeModal></my-welcome-modal>
|
||||||
<my-instance-config-warning-modal #instanceConfigWarningModal></my-instance-config-warning-modal>
|
<my-instance-config-warning-modal #instanceConfigWarningModal></my-instance-config-warning-modal>
|
||||||
</ng-template>
|
</ng-container>
|
||||||
|
|
||||||
<my-custom-modal #customModal></my-custom-modal>
|
<my-custom-modal #customModal></my-custom-modal>
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { PluginService } from '@app/core/plugins/plugin.service'
|
||||||
import { CustomModalComponent } from '@app/modal/custom-modal.component'
|
import { CustomModalComponent } from '@app/modal/custom-modal.component'
|
||||||
import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
|
import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
|
||||||
import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
|
import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
|
||||||
|
import { AccountSetupModalComponent } from '@app/modal/account-setup-modal.component'
|
||||||
import { NgbConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { LoadingBarService } from '@ngx-loading-bar/core'
|
import { LoadingBarService } from '@ngx-loading-bar/core'
|
||||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
||||||
|
@ -37,6 +38,7 @@ import { InstanceService } from './shared/shared-instance'
|
||||||
export class AppComponent implements OnInit, AfterViewInit {
|
export class AppComponent implements OnInit, AfterViewInit {
|
||||||
private static BROADCAST_MESSAGE_KEY = 'app-broadcast-message-dismissed'
|
private static BROADCAST_MESSAGE_KEY = 'app-broadcast-message-dismissed'
|
||||||
|
|
||||||
|
@ViewChild('accountSetupModal') accountSetupModal: AccountSetupModalComponent
|
||||||
@ViewChild('welcomeModal') welcomeModal: WelcomeModalComponent
|
@ViewChild('welcomeModal') welcomeModal: WelcomeModalComponent
|
||||||
@ViewChild('instanceConfigWarningModal') instanceConfigWarningModal: InstanceConfigWarningModalComponent
|
@ViewChild('instanceConfigWarningModal') instanceConfigWarningModal: InstanceConfigWarningModalComponent
|
||||||
@ViewChild('customModal') customModal: CustomModalComponent
|
@ViewChild('customModal') customModal: CustomModalComponent
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { CustomModalComponent } from './modal/custom-modal.component'
|
||||||
import { InstanceConfigWarningModalComponent } from './modal/instance-config-warning-modal.component'
|
import { InstanceConfigWarningModalComponent } from './modal/instance-config-warning-modal.component'
|
||||||
import { QuickSettingsModalComponent } from './modal/quick-settings-modal.component'
|
import { QuickSettingsModalComponent } from './modal/quick-settings-modal.component'
|
||||||
import { WelcomeModalComponent } from './modal/welcome-modal.component'
|
import { WelcomeModalComponent } from './modal/welcome-modal.component'
|
||||||
|
import { AccountSetupModalComponent } from './modal/account-setup-modal.component'
|
||||||
import { SharedActorImageModule } from './shared/shared-actor-image/shared-actor-image.module'
|
import { SharedActorImageModule } from './shared/shared-actor-image/shared-actor-image.module'
|
||||||
import { SharedFormModule } from './shared/shared-forms'
|
import { SharedFormModule } from './shared/shared-forms'
|
||||||
import { SharedGlobalIconModule } from './shared/shared-icons'
|
import { SharedGlobalIconModule } from './shared/shared-icons'
|
||||||
|
@ -53,6 +54,7 @@ export function loadConfigFactory (server: ServerService, pluginService: PluginS
|
||||||
SuggestionComponent,
|
SuggestionComponent,
|
||||||
HighlightPipe,
|
HighlightPipe,
|
||||||
|
|
||||||
|
AccountSetupModalComponent,
|
||||||
CustomModalComponent,
|
CustomModalComponent,
|
||||||
WelcomeModalComponent,
|
WelcomeModalComponent,
|
||||||
InstanceConfigWarningModalComponent,
|
InstanceConfigWarningModalComponent,
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<ng-template #modal let-hide="close">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 i18n class="modal-title">Welcome to {{ instanceName }}, dear user!</h4>
|
||||||
|
<my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<img class="mascot" src="/client/assets/images/mascot/happy.svg" alt="mascot">
|
||||||
|
|
||||||
|
<div i18n class="subtitle">It's time to set up your account profile!</div>
|
||||||
|
|
||||||
|
<p i18n>Help moderators and other users to know <strong>who you are</strong> by:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li *ngIf="!hasAccountAvatar" i18n>Uploading an <strong>avatar</strong></li>
|
||||||
|
<li *ngIf="!hasAccountDescription" i18n>Writing a <strong>description</strong></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer inputs">
|
||||||
|
<input
|
||||||
|
type="button" role="button" i18n-value value="Remind me later" class="peertube-button grey-button"
|
||||||
|
(click)="hide()" (key.enter)="hide()"
|
||||||
|
>
|
||||||
|
|
||||||
|
<a i18n (click)="hide()" (key.enter)="hide()"
|
||||||
|
class="peertube-button-link orange-button" routerLink="/my-account"
|
||||||
|
rel="noopener noreferrer" ngbAutofocus>
|
||||||
|
Set up
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ng-template>
|
|
@ -0,0 +1,31 @@
|
||||||
|
@use '_mixins' as *;
|
||||||
|
@use '_variables' as *;
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
font-size: 15px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mascot-fw {
|
||||||
|
width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mascot {
|
||||||
|
@include margin-right(2rem);
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
min-width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-weight: $font-semibold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
|
||||||
|
import { AuthService, ServerService, User } from '@app/core'
|
||||||
|
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
import { HTMLServerConfig } from '@shared/models'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-account-setup-modal',
|
||||||
|
templateUrl: './account-setup-modal.component.html',
|
||||||
|
styleUrls: [ './account-setup-modal.component.scss' ]
|
||||||
|
})
|
||||||
|
export class AccountSetupModalComponent implements OnInit {
|
||||||
|
@ViewChild('modal', { static: true }) modal: ElementRef
|
||||||
|
|
||||||
|
user: User = null
|
||||||
|
ref: NgbModalRef = null
|
||||||
|
|
||||||
|
private serverConfig: HTMLServerConfig
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private authService: AuthService,
|
||||||
|
private modalService: NgbModal,
|
||||||
|
private serverService: ServerService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
get userInformationLoaded () {
|
||||||
|
return this.authService.userInformationLoaded
|
||||||
|
}
|
||||||
|
|
||||||
|
get instanceName () {
|
||||||
|
return this.serverConfig.instance.name
|
||||||
|
}
|
||||||
|
|
||||||
|
get isUserRoot () {
|
||||||
|
return this.user.username === 'root'
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasAccountAvatar () {
|
||||||
|
return !!this.user.account.avatar
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasAccountDescription () {
|
||||||
|
return !!this.user.account.description
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.serverConfig = this.serverService.getHTMLConfig()
|
||||||
|
this.user = this.authService.getUser()
|
||||||
|
|
||||||
|
this.authService.userInformationLoaded
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
if (this.isUserRoot) return false
|
||||||
|
if (this.hasAccountAvatar && this.hasAccountDescription) return false
|
||||||
|
|
||||||
|
this.show()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
show () {
|
||||||
|
if (this.ref) return false
|
||||||
|
|
||||||
|
this.ref = this.modalService.open(this.modal, {
|
||||||
|
centered: true,
|
||||||
|
backdrop: 'static',
|
||||||
|
keyboard: false,
|
||||||
|
size: 'md'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ const icons = {
|
||||||
'playlist-add': require('!!raw-loader?!../../../assets/images/misc/playlist-add.svg').default, // material ui
|
'playlist-add': require('!!raw-loader?!../../../assets/images/misc/playlist-add.svg').default, // material ui
|
||||||
follower: require('!!raw-loader?!../../../assets/images/misc/account-arrow-left.svg').default, // material ui
|
follower: require('!!raw-loader?!../../../assets/images/misc/account-arrow-left.svg').default, // material ui
|
||||||
following: require('!!raw-loader?!../../../assets/images/misc/account-arrow-right.svg').default, // material ui
|
following: require('!!raw-loader?!../../../assets/images/misc/account-arrow-right.svg').default, // material ui
|
||||||
|
tip: require('!!raw-loader?!../../../assets/images/misc/tip.svg').default, // material ui
|
||||||
flame: require('!!raw-loader?!../../../assets/images/misc/flame.svg').default,
|
flame: require('!!raw-loader?!../../../assets/images/misc/flame.svg').default,
|
||||||
local: require('!!raw-loader?!../../../assets/images/misc/local.svg').default,
|
local: require('!!raw-loader?!../../../assets/images/misc/local.svg').default,
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div *ngIf="hasChannelNotConfigured" class="channels-setup-message alert alert-info">
|
||||||
|
<my-global-icon iconName="tip"></my-global-icon>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div i18n>Some of your channels are not fully set up. Make them welcoming and explicit about what you publish by adding a <strong>banner</strong>, an <strong>avatar</strong> and a <strong>description</strong>.</div>
|
||||||
|
<a *ngIf="!hideLink" class="channels-settings-link" routerLink="/my-library/video-channels" i18n>Set up my channels</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,32 @@
|
||||||
|
@use '_variables' as *;
|
||||||
|
@use '_mixins' as *;
|
||||||
|
|
||||||
|
.channels-setup-message {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
my-global-icon {
|
||||||
|
width: 32px;
|
||||||
|
align-self: flex-start;
|
||||||
|
|
||||||
|
::ng-deep {
|
||||||
|
svg {
|
||||||
|
fill: #0c5460;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ div {
|
||||||
|
margin-left: 10px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
a.channels-settings-link {
|
||||||
|
@include peertube-button-link;
|
||||||
|
@include grey-button;
|
||||||
|
|
||||||
|
height: fit-content;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { Component, Input, OnInit } from '@angular/core'
|
||||||
|
import { AuthService, User } from '@app/core'
|
||||||
|
import { VideoChannel } from '@app/shared/shared-main'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-channels-setup-message',
|
||||||
|
templateUrl: './channels-setup-message.component.html',
|
||||||
|
styleUrls: [ './channels-setup-message.component.scss' ]
|
||||||
|
})
|
||||||
|
export class ChannelsSetupMessageComponent implements OnInit {
|
||||||
|
@Input() hideLink = false
|
||||||
|
|
||||||
|
user: User = null
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private authService: AuthService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
get userInformationLoaded () {
|
||||||
|
return this.authService.userInformationLoaded
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasChannelNotConfigured () {
|
||||||
|
return this.user.videoChannels
|
||||||
|
.filter((channel: VideoChannel) => (!channel.avatar || !channel.description))
|
||||||
|
.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.user = this.authService.getUser()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
export * from './channels-setup-message.component'
|
||||||
export * from './help.component'
|
export * from './help.component'
|
||||||
export * from './list-overflow.component'
|
export * from './list-overflow.component'
|
||||||
export * from './top-menu-dropdown.component'
|
export * from './top-menu-dropdown.component'
|
||||||
|
|
|
@ -34,7 +34,13 @@ import { CustomPageService } from './custom-page'
|
||||||
import { DateToggleComponent } from './date'
|
import { DateToggleComponent } from './date'
|
||||||
import { FeedComponent } from './feeds'
|
import { FeedComponent } from './feeds'
|
||||||
import { LoaderComponent, SmallLoaderComponent } from './loaders'
|
import { LoaderComponent, SmallLoaderComponent } from './loaders'
|
||||||
import { HelpComponent, ListOverflowComponent, SimpleSearchInputComponent, TopMenuDropdownComponent } from './misc'
|
import {
|
||||||
|
ChannelsSetupMessageComponent,
|
||||||
|
HelpComponent,
|
||||||
|
ListOverflowComponent,
|
||||||
|
SimpleSearchInputComponent,
|
||||||
|
TopMenuDropdownComponent
|
||||||
|
} from './misc'
|
||||||
import { PluginPlaceholderComponent } from './plugins'
|
import { PluginPlaceholderComponent } from './plugins'
|
||||||
import { ActorRedirectGuard } from './router'
|
import { ActorRedirectGuard } from './router'
|
||||||
import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users'
|
import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users'
|
||||||
|
@ -91,6 +97,7 @@ import { VideoChannelService } from './video-channel'
|
||||||
LoaderComponent,
|
LoaderComponent,
|
||||||
SmallLoaderComponent,
|
SmallLoaderComponent,
|
||||||
|
|
||||||
|
ChannelsSetupMessageComponent,
|
||||||
HelpComponent,
|
HelpComponent,
|
||||||
ListOverflowComponent,
|
ListOverflowComponent,
|
||||||
TopMenuDropdownComponent,
|
TopMenuDropdownComponent,
|
||||||
|
@ -146,6 +153,7 @@ import { VideoChannelService } from './video-channel'
|
||||||
LoaderComponent,
|
LoaderComponent,
|
||||||
SmallLoaderComponent,
|
SmallLoaderComponent,
|
||||||
|
|
||||||
|
ChannelsSetupMessageComponent,
|
||||||
HelpComponent,
|
HelpComponent,
|
||||||
ListOverflowComponent,
|
ListOverflowComponent,
|
||||||
TopMenuDropdownComponent,
|
TopMenuDropdownComponent,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><path d="M0,0h24v24H0V0z" fill="none"/></g><g><g><rect height="3" width="2" x="11" y="19"/><rect height="2" width="3" x="2" y="11"/><rect height="2" width="3" x="19" y="11"/><rect height="3" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -7.6665 17.8014)" width="1.99" x="16.66" y="16.66"/><rect height="1.99" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -10.9791 9.8041)" width="3" x="4.85" y="17.16"/><path d="M15,8.02V3H9v5.02C7.79,8.94,7,10.37,7,12c0,2.76,2.24,5,5,5s5-2.24,5-5C17,10.37,16.21,8.94,15,8.02z M11,5h2v2.1 C12.68,7.04,12.34,7,12,7s-0.68,0.04-1,0.1V5z"/></g></g></svg>
|
After Width: | Height: | Size: 726 B |
Loading…
Reference in New Issue