Browse Source

Add tabs

pull/2396/head
Thomas 2 years ago
parent
commit
269629be0a
  1. 10
      apps/client/src/app/components/user-account-access/user-account-access.html
  2. 1
      apps/client/src/app/components/user-account-membership/user-account-membership.component.ts
  3. 29
      apps/client/src/app/components/user-account-membership/user-account-membership.html
  4. 44
      apps/client/src/app/components/user-account-settings/user-account-settings.html
  5. 20
      apps/client/src/app/pages/user-account/user-account-page-routing.module.ts
  6. 40
      apps/client/src/app/pages/user-account/user-account-page.component.ts
  7. 39
      apps/client/src/app/pages/user-account/user-account-page.html
  8. 8
      apps/client/src/app/pages/user-account/user-account-page.module.ts
  9. 4
      apps/client/src/app/pages/user-account/user-account-page.scss

10
apps/client/src/app/components/user-account-access/user-account-access.html

@ -1,19 +1,17 @@
<div class="container"> <div class="container">
<div class="row"> <h1
<div class="col"> class="align-items-center d-none d-sm-flex h3 justify-content-center mb-3 text-center"
<h2 class="align-items-center d-flex h3 justify-content-center mb-3"> >
<span i18n>Granted Access</span> <span i18n>Granted Access</span>
<gf-premium-indicator <gf-premium-indicator
*ngIf="user?.subscription?.type === 'Basic'" *ngIf="user?.subscription?.type === 'Basic'"
class="ml-1" class="ml-1"
></gf-premium-indicator> ></gf-premium-indicator>
</h2> </h1>
<gf-access-table <gf-access-table
[accesses]="accesses" [accesses]="accesses"
[hasPermissionToCreateAccess]="hasPermissionToCreateAccess" [hasPermissionToCreateAccess]="hasPermissionToCreateAccess"
[showActions]="hasPermissionToDeleteAccess" [showActions]="hasPermissionToDeleteAccess"
(accessDeleted)="onDeleteAccess($event)" (accessDeleted)="onDeleteAccess($event)"
></gf-access-table> ></gf-access-table>
</div>
</div>
</div> </div>

1
apps/client/src/app/components/user-account-membership/user-account-membership.component.ts

@ -34,6 +34,7 @@ export class UserAccountMembershipComponent implements OnDestroy, OnInit {
public hasPermissionToUpdateUserSettings: boolean; public hasPermissionToUpdateUserSettings: boolean;
public price: number; public price: number;
public priceId: string; public priceId: string;
public routerLinkPricing = ['/' + $localize`pricing`];
public snackBarRef: MatSnackBarRef<TextOnlySnackBar>; public snackBarRef: MatSnackBarRef<TextOnlySnackBar>;
public trySubscriptionMail = public trySubscriptionMail =
'mailto:hi@ghostfol.io?Subject=Ghostfolio Premium Trial&body=Hello%0D%0DI am interested in Ghostfolio Premium. Can you please send me a coupon code to try it for some time?%0D%0DKind regards'; 'mailto:hi@ghostfol.io?Subject=Ghostfolio Premium Trial&body=Hello%0D%0DI am interested in Ghostfolio Premium. Can you please send me a coupon code to try it for some time?%0D%0DKind regards';

29
apps/client/src/app/components/user-account-membership/user-account-membership.html

@ -1,16 +1,9 @@
<div class="container"> <div class="container">
<h1 class="d-none d-sm-block h3 mb-3 text-center" i18n>Membership</h1>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<h2 class="h3 mb-3 text-center" i18n>Membership</h2> <div class="d-flex">
</div> <div class="mx-auto">
</div>
<div *ngIf="user?.settings" class="mb-5 row">
<div class="col">
<mat-card appearance="outlined" class="mb-3">
<mat-card-content>
<div *ngIf="user?.subscription" class="d-flex py-1">
<div class="pr-1 w-50" i18n>Membership</div>
<div class="pl-1 w-50">
<div class="align-items-center d-flex mb-1"> <div class="align-items-center d-flex mb-1">
<a [routerLink]="routerLinkPricing" <a [routerLink]="routerLinkPricing"
>{{ user?.subscription?.type }}</a >{{ user?.subscription?.type }}</a
@ -28,19 +21,11 @@
<ng-container <ng-container
*ngIf="hasPermissionForSubscription && hasPermissionToUpdateUserSettings" *ngIf="hasPermissionForSubscription && hasPermissionToUpdateUserSettings"
> >
<button <button color="primary" mat-flat-button (click)="onCheckout()">
color="primary" <ng-container *ngIf="user.subscription.offer === 'default'" i18n
mat-flat-button
(click)="onCheckout()"
>
<ng-container
*ngIf="user.subscription.offer === 'default'"
i18n
>Upgrade</ng-container >Upgrade</ng-container
> >
<ng-container <ng-container *ngIf="user.subscription.offer === 'renewal'" i18n
*ngIf="user.subscription.offer === 'renewal'"
i18n
>Renew</ng-container >Renew</ng-container
> >
</button> </button>
@ -79,8 +64,6 @@
</div> </div>
</div> </div>
</div> </div>
</mat-card-content>
</mat-card>
</div> </div>
</div> </div>
</div> </div>

44
apps/client/src/app/components/user-account-settings/user-account-settings.html

@ -1,19 +1,13 @@
<div class="container"> <div class="container">
<h1 class="d-none d-sm-block h3 mb-3 text-center" i18n>Settings</h1>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<h2 class="h3 mb-3 text-center" i18n>Settings</h2> <div class="align-items-center d-flex py-1">
</div>
</div>
<div *ngIf="user?.settings" class="mb-5 row">
<div class="col">
<mat-card appearance="outlined" class="mb-3">
<mat-card-content>
<div class="align-items-center d-flex mt-4 py-1">
<div class="pr-1 w-50"> <div class="pr-1 w-50">
<div i18n>Presenter View</div> <div i18n>Presenter View</div>
<div class="hint-text text-muted" i18n> <div class="hint-text text-muted" i18n>
Protection for sensitive information like absolute performances Protection for sensitive information like absolute performances and
and quantity values quantity values
</div> </div>
</div> </div>
<div class="pl-1 w-50"> <div class="pl-1 w-50">
@ -32,10 +26,7 @@
<ng-container i18n>Base Currency</ng-container> <ng-container i18n>Base Currency</ng-container>
</div> </div>
<div class="pl-1 w-50"> <div class="pl-1 w-50">
<mat-form-field <mat-form-field appearance="outline" class="w-100 without-hint">
appearance="outline"
class="w-100 without-hint"
>
<mat-select <mat-select
name="baseCurrency" name="baseCurrency"
[disabled]="!hasPermissionToUpdateUserSettings" [disabled]="!hasPermissionToUpdateUserSettings"
@ -56,10 +47,7 @@
<div i18n>Language</div> <div i18n>Language</div>
</div> </div>
<div class="pl-1 w-50"> <div class="pl-1 w-50">
<mat-form-field <mat-form-field appearance="outline" class="w-100 without-hint">
appearance="outline"
class="w-100 without-hint"
>
<mat-select <mat-select
name="language" name="language"
[disabled]="!hasPermissionToUpdateUserSettings" [disabled]="!hasPermissionToUpdateUserSettings"
@ -105,10 +93,7 @@
</div> </div>
</div> </div>
<div class="pl-1 w-50"> <div class="pl-1 w-50">
<mat-form-field <mat-form-field appearance="outline" class="w-100 without-hint">
appearance="outline"
class="w-100 without-hint"
>
<mat-select <mat-select
name="locale" name="locale"
[disabled]="!hasPermissionToUpdateUserSettings" [disabled]="!hasPermissionToUpdateUserSettings"
@ -116,9 +101,7 @@
(selectionChange)="onChangeUserSetting('locale', $event.value)" (selectionChange)="onChangeUserSetting('locale', $event.value)"
> >
<mat-option [value]="null"></mat-option> <mat-option [value]="null"></mat-option>
<mat-option <mat-option *ngFor="let locale of locales" [value]="locale"
*ngFor="let locale of locales"
[value]="locale"
>{{ locale }}</mat-option >{{ locale }}</mat-option
> >
</mat-select> </mat-select>
@ -130,10 +113,7 @@
<ng-container i18n>Appearance</ng-container> <ng-container i18n>Appearance</ng-container>
</div> </div>
<div class="pl-1 w-50"> <div class="pl-1 w-50">
<mat-form-field <mat-form-field appearance="outline" class="w-100 without-hint">
appearance="outline"
class="w-100 without-hint"
>
<mat-select <mat-select
class="with-placeholder-as-option" class="with-placeholder-as-option"
name="colorScheme" name="colorScheme"
@ -170,9 +150,7 @@
<div class="align-items-center d-flex mt-4 py-1"> <div class="align-items-center d-flex mt-4 py-1">
<div class="pr-1 w-50"> <div class="pr-1 w-50">
<div i18n>Biometric Authentication</div> <div i18n>Biometric Authentication</div>
<div class="hint-text text-muted" i18n> <div class="hint-text text-muted" i18n>Sign in with fingerprint</div>
Sign in with fingerprint
</div>
</div> </div>
<div class="pl-1 w-50"> <div class="pl-1 w-50">
<mat-checkbox <mat-checkbox
@ -214,8 +192,6 @@
</button> </button>
</div> </div>
</div> </div>
</mat-card-content>
</mat-card>
</div> </div>
</div> </div>
</div> </div>

20
apps/client/src/app/pages/user-account/user-account-page-routing.module.ts

@ -1,5 +1,8 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { UserAccountAccessComponent } from '@ghostfolio/client/components/user-account-access/user-account-access.component';
import { UserAccountMembershipComponent } from '@ghostfolio/client/components/user-account-membership/user-account-membership.component';
import { UserAccountSettingsComponent } from '@ghostfolio/client/components/user-account-settings/user-account-settings.component';
import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { UserAccountPageComponent } from './user-account-page.component'; import { UserAccountPageComponent } from './user-account-page.component';
@ -7,6 +10,23 @@ import { UserAccountPageComponent } from './user-account-page.component';
const routes: Routes = [ const routes: Routes = [
{ {
canActivate: [AuthGuard], canActivate: [AuthGuard],
children: [
{
path: '',
component: UserAccountSettingsComponent,
title: $localize`Settings`
},
{
path: 'membership',
component: UserAccountMembershipComponent,
title: $localize`Membership`
},
{
path: 'access',
component: UserAccountAccessComponent,
title: $localize`Access`
}
],
component: UserAccountPageComponent, component: UserAccountPageComponent,
path: '', path: '',
title: $localize`My Ghostfolio` title: $localize`My Ghostfolio`

40
apps/client/src/app/pages/user-account/user-account-page.component.ts

@ -1,30 +1,60 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { User } from '@ghostfolio/common/interfaces'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject, takeUntil } from 'rxjs'; import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
host: { class: 'page' }, host: { class: 'page has-tabs' },
selector: 'gf-user-account-page', selector: 'gf-user-account-page',
styleUrls: ['./user-account-page.scss'], styleUrls: ['./user-account-page.scss'],
templateUrl: './user-account-page.html' templateUrl: './user-account-page.html'
}) })
export class UserAccountPageComponent implements OnDestroy, OnInit { export class UserAccountPageComponent implements OnDestroy, OnInit {
public deviceType: string;
public tabs: TabConfiguration[] = [];
public user: User; public user: User;
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
public constructor(private userService: UserService) { public constructor(
private changeDetectorRef: ChangeDetectorRef,
private deviceService: DeviceDetectorService,
private userService: UserService
) {
this.userService.stateChanged this.userService.stateChanged
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe((state) => { .subscribe((state) => {
if (state?.user) { if (state?.user) {
this.user = state.user; this.user = state.user;
this.tabs = [
{
iconName: 'cog-outline',
label: $localize`Settings`,
path: ['/account']
},
{
iconName: 'diamond-outline',
label: $localize`Membership`,
path: ['/account/membership'],
showCondition: !!this.user?.subscription
},
{
iconName: 'share-social-outline',
label: $localize`Access`,
path: ['/account', 'access']
}
];
this.changeDetectorRef.markForCheck();
} }
}); });
} }
public ngOnInit() {} public ngOnInit() {
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
}
public ngOnDestroy() { public ngOnDestroy() {
this.unsubscribeSubject.next(); this.unsubscribeSubject.next();

39
apps/client/src/app/pages/user-account/user-account-page.html

@ -1,10 +1,29 @@
<div class="container"> <mat-tab-nav-panel #tabPanel class="flex-grow-1 overflow-auto">
<div class="row"> <router-outlet></router-outlet>
<div class="col"> </mat-tab-nav-panel>
<h2 class="h3 mb-3 text-center" i18n>Account</h2>
<gf-user-account-membership *ngIf="user?.subscription" /> <nav
<gf-user-account-settings /> mat-align-tabs="center"
<gf-user-account-access /> mat-tab-nav-bar
</div> [disablePagination]="true"
</div> [tabPanel]="tabPanel"
</div> >
<ng-container *ngFor="let tab of tabs">
<a
#rla="routerLinkActive"
*ngIf="tab.showCondition !== false"
class="px-3"
mat-tab-link
routerLinkActive
[active]="rla.isActive"
[routerLink]="tab.path"
[routerLinkActiveOptions]="{ exact: true }"
>
<ion-icon
[name]="tab.iconName"
[size]="deviceType === 'mobile' ? 'large': 'small'"
></ion-icon>
<div class="d-none d-sm-block ml-2">{{ tab.label }}</div>
</a>
</ng-container>
</nav>

8
apps/client/src/app/pages/user-account/user-account-page.module.ts

@ -1,11 +1,12 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { MatTabsModule } from '@angular/material/tabs';
import { GfUserAccountAccessModule } from '@ghostfolio/client/components/user-account-access/user-account-access.module';
import { GfUserAccountMembershipModule } from '@ghostfolio/client/components/user-account-membership/user-account-membership.module';
import { GfUserAccountSettingsModule } from '@ghostfolio/client/components/user-account-settings/user-account-settings.module';
import { UserAccountPageRoutingModule } from './user-account-page-routing.module'; import { UserAccountPageRoutingModule } from './user-account-page-routing.module';
import { UserAccountPageComponent } from './user-account-page.component'; import { UserAccountPageComponent } from './user-account-page.component';
import { GfUserAccountSettingsModule } from '@ghostfolio/client/components/user-account-settings/user-account-settings.module';
import { GfUserAccountAccessModule } from '@ghostfolio/client/components/user-account-access/user-account-access.module';
import { GfUserAccountMembershipModule } from '@ghostfolio/client/components/user-account-membership/user-account-membership.module';
@NgModule({ @NgModule({
declarations: [UserAccountPageComponent], declarations: [UserAccountPageComponent],
@ -14,6 +15,7 @@ import { GfUserAccountMembershipModule } from '@ghostfolio/client/components/use
GfUserAccountAccessModule, GfUserAccountAccessModule,
GfUserAccountMembershipModule, GfUserAccountMembershipModule,
GfUserAccountSettingsModule, GfUserAccountSettingsModule,
MatTabsModule,
UserAccountPageRoutingModule UserAccountPageRoutingModule
] ]
}) })

4
apps/client/src/app/pages/user-account/user-account-page.scss

@ -1,5 +1,9 @@
@import 'apps/client/src/styles/ghostfolio-style';
:host { :host {
color: rgb(var(--dark-primary-text));
} }
:host-context(.is-dark-theme) { :host-context(.is-dark-theme) {
color: rgb(var(--light-primary-text));
} }

Loading…
Cancel
Save