Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {NgModule} from "@angular/core";
import {RouterModule, Routes} from "@angular/router";
import {GameDataResolver} from "./core/resolvers/game-data.resolver";
import {UserResolver} from "./core/resolvers/user.resolver";

const rootRoutes: Routes = [
{
Expand All @@ -10,6 +11,13 @@ const rootRoutes: Routes = [
gameData: GameDataResolver
}
},
{
path: 'oauth',
loadChildren: () => import('./pages/oauth/oauth.module').then(m => m.OauthModule),
resolve: {
user: UserResolver
}
},
{
path: 'embed',
loadChildren: () => import('./pages/embedded/embedded.module').then(m => m.EmbeddedModule),
Expand All @@ -29,6 +37,7 @@ const rootRoutes: Routes = [
redirectTo: 'browser',
pathMatch: 'full'
},
{path: '**', redirectTo: 'browser'}
];

@NgModule({
Expand All @@ -41,4 +50,5 @@ const rootRoutes: Routes = [
RouterModule
]
})
export class AppRoutingModule {}
export class AppRoutingModule {
}
5 changes: 3 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import {ReactiveFormsModule} from "@angular/forms";
BrowserModule,
HttpClientModule,
AppRoutingModule,
ReactiveFormsModule
ReactiveFormsModule,
],
providers: [
communicationLayerServiceProvider
],
bootstrap: [AppComponent]
})
export class AppModule { }
export class AppModule {
}
16 changes: 16 additions & 0 deletions src/app/core/resolvers/user.resolver.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { UserResolver } from './user.resolver';

describe('UserResolver', () => {
let resolver: UserResolver;

beforeEach(() => {
TestBed.configureTestingModule({});
resolver = TestBed.inject(UserResolver);
});

it('should be created', () => {
expect(resolver).toBeTruthy();
});
});
18 changes: 18 additions & 0 deletions src/app/core/resolvers/user.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, Resolve, RouterStateSnapshot} from '@angular/router';
import {Observable} from 'rxjs';
import {User} from "../../modules/api/interfaces/user";
import {UserService} from "../../modules/user/services/user.service";
import {take} from "rxjs/operators";

@Injectable({
providedIn: 'root'
})
export class UserResolver implements Resolve<User | null> {
public constructor(private readonly userService: UserService) {
}

public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User | null> {
return this.userService.signedInUser$.pipe(take(1));
}
}
6 changes: 6 additions & 0 deletions src/app/modules/api/interfaces/oauth-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface OauthClient {
oauthProvider: string;
providerUserId: string;
providerUsername: string;
providerUserDiscriminator?: string;
}
5 changes: 4 additions & 1 deletion src/app/modules/api/interfaces/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {UserShort} from "./user-short";
import {OauthClient} from "./oauth-client";

export interface User extends UserShort {
uniqueToken: string,
email: string
email: string,
isOAuthUser: boolean,
oauthClients: OauthClient[]
}
40 changes: 24 additions & 16 deletions src/app/modules/api/services/api.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import {Injectable} from '@angular/core';
import {RotationCreate} from "../interfaces/rotation-create";
import {RotationUpdate} from "../interfaces/rotation-update";
import {Rotation} from "../interfaces/rotation";
Expand All @@ -9,23 +9,23 @@ import {User} from "../interfaces/user";
import {environment} from "../../../../environments/environment";
import {HttpClient} from "@angular/common/http";
import {Observable} from "rxjs";
import {map} from "rxjs/operators";

@Injectable({
providedIn: 'root'
})
export class ApiService {
private readonly API_BASE_URL = environment.apiBaseUrl;

public constructor(private readonly httpClient: HttpClient) {}
public constructor(private readonly httpClient: HttpClient) {
}

// AUTH
signIn(email: string, password: string): Observable<User> {
return this.request('/auth/login', 'POST', JSON.stringify({ email, password })) as Observable<User>;
return this.request('/auth/login', 'POST', JSON.stringify({email, password})) as Observable<User>;
}

signUp(email: string, username: string, password: string) {
return this.request('/auth/signup', 'POST', JSON.stringify({ email, password, username }));
return this.request('/auth/signup', 'POST', JSON.stringify({email, password, username}));
}

me(): Observable<User> {
Expand Down Expand Up @@ -80,7 +80,7 @@ export class ApiService {

const paramString = paramArray.length ? `?${paramArray.join('&')}` : '';

return this.request(`/rotation/${ paramString }`, 'GET') as Observable<PaginatedResponse<Rotation>>;
return this.request(`/rotation/${paramString}`, 'GET') as Observable<PaginatedResponse<Rotation>>;
}

// USER
Expand All @@ -92,6 +92,14 @@ export class ApiService {
return this.request('/user/rotations', 'GET') as Observable<PaginatedResponse<Rotation>>;
}

usernameTaken(username: string): Observable<boolean> {
return this.request(`/user/name-taken/${username}`, 'GET') as Observable<boolean>;
}

changeUsername(username: string): Observable<User> {
return this.request(`/user/name`, 'POST', {username}) as Observable<User>;
}

// Token
userTokenFavourites(token: string): Observable<PaginatedResponse<Rotation>> {
return this.request(`/token/${token}/favourites`, 'GET') as Observable<PaginatedResponse<Rotation>>;
Expand All @@ -101,17 +109,17 @@ export class ApiService {
return this.request(`/token/${token}/rotations`, 'GET') as Observable<PaginatedResponse<Rotation>>;
}

private request(url: string, method: 'POST' | 'PATCH' | 'GET' | 'DELETE', body?: string) {
private request(url: string, method: 'POST' | 'PATCH' | 'GET' | 'DELETE', body?: string | Record<string, unknown>) {
return this.httpClient.request(
method,
`${this.API_BASE_URL}${url}`,
{
headers: {
'Content-Type': 'application/json'
},
withCredentials: true,
body
}
method,
`${this.API_BASE_URL}${url}`,
{
headers: {
'Content-Type': 'application/json'
},
withCredentials: true,
body
}
);
}
}
10 changes: 5 additions & 5 deletions src/app/modules/toolbar/toolbar.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<rh-class-job-selection
[classJobs]="classJobs$ | async"
[currentClassJob]="currentClassJob$ | async"
(selectClassJob)="selectClassJob($event)">
[classJobs]="classJobs$ | async"
[currentClassJob]="currentClassJob$ | async"
(selectClassJob)="selectClassJob($event)">
</rh-class-job-selection>

<a class="rh-toolbar__button button" (click)="toggleDialog.emit(rotationHeroDialogConfiguration)">Rotation Hero</a>
Expand All @@ -19,9 +19,9 @@
<button class="rh-toolbar__user-menu button"
*ngIf="user$ | async"
(click)="isUserPanelVisible = !isUserPanelVisible">
{{ (user$ | async)?.username }}
{{ (displayedUserName$ | async) }}
</button>

<rh-profile
*ngIf="isUserPanelVisible && (user$ | async)"
[user]="user$ | async"></rh-profile>
[user]="(user$ | async)!"></rh-profile>
7 changes: 4 additions & 3 deletions src/app/modules/toolbar/toolbar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ export class ToolbarComponent {
public readonly classJobs$ = this.gameDataService.classJobs$;
public readonly currentClassJob$ = this.appStateService.currentClassJob$
public readonly user$ = this.userService.signedInUser$;
public readonly displayedUserName$ = this.userService.displayedUserName$;

constructor(
public readonly gameDataService: GameDataService,
private readonly appStateService: AppStateService,
private readonly userService: UserService
public readonly gameDataService: GameDataService,
private readonly appStateService: AppStateService,
private readonly userService: UserService
) {
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<p>
ID:<br />
ID:<br/>
{{ user?.id }}
</p>
<p>
Username:<br />
Username:<br/>
{{ user?.username }}
</p>
<p>
ACT Overlay URL:<br />
<p *ngIf="user?.uniqueToken">
ACT Overlay URL:<br/>
{{ user?.uniqueToken }}
</p>

Expand Down
7 changes: 4 additions & 3 deletions src/app/modules/user/components/profile/profile.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Component, OnInit, ChangeDetectionStrategy, Input} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {UserService} from "../../services/user.service";
import {User} from "../../../api/interfaces/user";

Expand All @@ -10,9 +10,10 @@ import {User} from "../../../api/interfaces/user";
})
export class ProfileComponent {

@Input() user: User | null = null;
@Input() user!: User;

constructor(private readonly userService: UserService) { }
constructor(private readonly userService: UserService) {
}

logout() {
this.userService.signOutSubject$.next();
Expand Down
21 changes: 18 additions & 3 deletions src/app/modules/user/components/sign-in/sign-in.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,28 @@ <h2 class="rh-sign-in__title">Sign In</h2>
(ngSubmit)="onSubmit(signInFormGroup.value)">
<div class="rh-sign-in__input-container">
<label class="rh-sign-in__input-label">Email</label>
<input class="rh-sign-in__input" type="email" formControlName="email" />
<input class="rh-sign-in__input" type="email" formControlName="email"/>
</div>
<div class="rh-sign-in__input-container">
<label class="rh-sign-in__input-label">Password</label>
<input class="rh-sign-in__input" type="password" formControlName="password" />
<input class="rh-sign-in__input" type="password" formControlName="password"/>
</div>
<button
class="rh-sign-in__button"
[disabled]="!signInFormGroup.valid">Sign in</button>
[disabled]="!signInFormGroup.valid">Sign in
</button>
</form>

<div class="rh-sign-in__separator">
<span>OR</span>
</div>

<p class="rh-sign-in__social-auth-label">Sign in with...</p>

<button
class="rh-sign-in__social-button "
*ngFor="let provider of oauthProviders"
[ngClass]="'rh-sign-in__social-button--' + provider.className"
(click)="signInWithProvider(provider)">
<span class="rh-sign-in__social-button-label">{{provider.name}}</span>
</button>
61 changes: 58 additions & 3 deletions src/app/modules/user/components/sign-in/sign-in.component.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
:host { display: block; }
:host {
display: block;
}

.rh-sign-in {
&__title {
Expand All @@ -22,10 +24,10 @@
&__input {
display: block;
color: white;
background: rgba(255,255,255,0.1);
background: rgba(255, 255, 255, 0.1);
border: 0;
outline: 0;
border-bottom: 2px solid rgba(255,255,255,0.2);
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
line-height: 1.5;
width: 100%;
padding: 6px 8px;
Expand All @@ -48,4 +50,57 @@
border-color: gray;
}
}

&__separator {
background: linear-gradient(to right, transparent, white, transparent) no-repeat center center;
background-size: 100% 1px;
color: white;
text-align: center;
margin: 8px 0;

span {
display: inline-block;
background: #323232;
font-size: 12px;
padding: 0 6px;
}
}

&__social-button {
cursor: pointer;
font-size: inherit;
width: 100%;
border: 0;
padding: 0;
text-align: left;
display: flex;
align-items: stretch;

&::before {
content: '';
display: block;
width: 40px;
}

&--discord {
background: #8c9eff;
color: white;

&::before {
background: white url("/assets/images/social/discord.png") no-repeat center center;
background-size: 75%;
}
}
}

&__social-button-label {
padding: 8px 12px;
font-size: 16px;
font-weight: 700;
}

&__social-auth-label {
color: white;
font-size: 12px;
}
}
Loading