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
10 changes: 5 additions & 5 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { SidenavComponent } from '@osf/sidenav/sidenav.component';
import { SidenavComponent } from '@core/components/sidenav/sidenav.component';
import { RouterOutlet } from '@angular/router';
import { HeaderComponent } from '@osf/header/header.component';
import { MainContentComponent } from '@osf/main-content/main-content.component';
import { FooterComponent } from '@osf/footer/footer.component';
import { TopnavComponent } from '@osf/topnav/topnav.component';
import { HeaderComponent } from '@core/components/header/header.component';
import { MainContentComponent } from '@core/components/main-content/main-content.component';
import { FooterComponent } from '@core/components/footer/footer.component';
import { TopnavComponent } from '@core/components/topnav/topnav.component';
import { IS_PORTRAIT } from '@shared/utils/breakpoints.tokens';
import { toSignal } from '@angular/core/rxjs-interop';

Expand Down
8 changes: 8 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { NgModule } from '@angular/core';
import { NgxsModule } from '@ngxs/store';
import { AuthState } from '@core/store/auth';

@NgModule({
imports: [NgxsModule.forRoot([AuthState])],
})
export class AppModule {}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<main class="content-body">
<span>main-content works!</span>
<p>main-content works!</p>
</main>
9 changes: 9 additions & 0 deletions src/app/core/store/auth/auth.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export class SetAuthToken {
static readonly type = '[Auth] Set Auth Token';

constructor(public accessToken: string) {}
}

export class ClearAuth {
static readonly type = '[Auth] Clear Auth';
}
4 changes: 4 additions & 0 deletions src/app/core/store/auth/auth.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface AuthStateModel {
accessToken: string | null;
isAuthenticated: boolean;
}
15 changes: 15 additions & 0 deletions src/app/core/store/auth/auth.selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Selector } from '@ngxs/store';
import { AuthState } from './auth.state';
import { AuthStateModel } from './auth.model';

export class AuthSelectors {
@Selector([AuthState])
static isAuthenticated(state: AuthStateModel): boolean {
return state.isAuthenticated;
}

@Selector([AuthState])
static getAuthToken(state: AuthStateModel): string | null {
return state.accessToken;
}
}
30 changes: 30 additions & 0 deletions src/app/core/store/auth/auth.state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Injectable } from '@angular/core';
import { State, Action, StateContext } from '@ngxs/store';
import { AuthStateModel } from './auth.model';
import { SetAuthToken, ClearAuth } from './auth.actions';

@State<AuthStateModel>({
name: 'auth',
defaults: {
accessToken: null,
isAuthenticated: false,
},
})
@Injectable()
export class AuthState {
@Action(SetAuthToken)
setAuthToken(ctx: StateContext<AuthStateModel>, action: SetAuthToken) {
ctx.patchState({
accessToken: action.accessToken,
isAuthenticated: true,
});
}

@Action(ClearAuth)
clearAuth(ctx: StateContext<AuthStateModel>) {
ctx.patchState({
accessToken: null,
isAuthenticated: false,
});
}
}
4 changes: 4 additions & 0 deletions src/app/core/store/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './auth.actions';
export * from './auth.model';
export * from './auth.selectors';
export * from './auth.state';
8 changes: 8 additions & 0 deletions src/app/features/auth/auth.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface LoginCredentials {
email: string;
password: string;
}

export interface AuthResponse {
accessToken: string;
}
54 changes: 54 additions & 0 deletions src/app/features/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Store } from '@ngxs/store';
import { firstValueFrom } from 'rxjs';
import { LoginCredentials, AuthResponse } from './auth.entity';
import { SetAuthToken, ClearAuth } from '@core/store/auth';

@Injectable({
providedIn: 'root',
})
export class AuthService {
private readonly API_URL = 'VALID_API_URL';
private readonly AUTH_TOKEN_KEY = '';

private readonly http: HttpClient = inject(HttpClient);
private readonly store: Store = inject(Store);

//TODO: rewrite/refactor methods according to the API
async login(credentials: LoginCredentials): Promise<void> {
try {
const response = await firstValueFrom(
this.http.post<AuthResponse>(`${this.API_URL}/auth/login`, credentials),
);

if (response.accessToken) {
this.setAuthToken(response.accessToken);
this.store.dispatch(new SetAuthToken(response.accessToken));
}
} catch (error) {
console.error('Login failed:', error);
throw error;
}
}

logout(): void {
localStorage.removeItem(this.AUTH_TOKEN_KEY);
this.store.dispatch(new ClearAuth());
}

getAuthToken(): string | null {
return localStorage.getItem(this.AUTH_TOKEN_KEY);
}

private setAuthToken(token: string): void {
localStorage.setItem(this.AUTH_TOKEN_KEY, token);
}

private checkInitialAuthState(): void {
const token: string | null = this.getAuthToken();
if (token) {
this.store.dispatch(new SetAuthToken(token));
}
}
}
1 change: 1 addition & 0 deletions src/app/features/auth/sign-in/sign-in.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>sign-in works!</p>
Empty file.
22 changes: 22 additions & 0 deletions src/app/features/auth/sign-in/sign-in.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { SignInComponent } from './sign-in.component';

describe('SignInComponent', () => {
let component: SignInComponent;
let fixture: ComponentFixture<SignInComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SignInComponent],
}).compileComponents();

fixture = TestBed.createComponent(SignInComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
9 changes: 9 additions & 0 deletions src/app/features/auth/sign-in/sign-in.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Component } from '@angular/core';

@Component({
selector: 'osf-sign-in',
imports: [],
templateUrl: './sign-in.component.html',
styleUrl: './sign-in.component.scss',
})
export class SignInComponent {}
1 change: 1 addition & 0 deletions src/app/features/auth/sign-up/sign-up.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>sign-up works!</p>
Empty file.
22 changes: 22 additions & 0 deletions src/app/features/auth/sign-up/sign-up.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { SignUpComponent } from './sign-up.component';

describe('SignUpComponent', () => {
let component: SignUpComponent;
let fixture: ComponentFixture<SignUpComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SignUpComponent],
}).compileComponents();

fixture = TestBed.createComponent(SignUpComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
9 changes: 9 additions & 0 deletions src/app/features/auth/sign-up/sign-up.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Component } from '@angular/core';

@Component({
selector: 'osf-sign-up',
imports: [],
templateUrl: './sign-up.component.html',
styleUrl: './sign-up.component.scss',
})
export class SignUpComponent {}