Skip to content

Commit

Permalink
Merge pull request #5 from johnnygerard:auth
Browse files Browse the repository at this point in the history
feat: basic email/password authentication
  • Loading branch information
johnnygerard committed May 24, 2024
2 parents 13e3eba + b809f31 commit ef16109
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
<h1>Deployment successful!</h1>
<a routerLink="/">Home</a>
<router-outlet />
3 changes: 2 additions & 1 deletion src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ChangeDetectionStrategy, Component } from "@angular/core";
import { RouterLink, RouterOutlet } from "@angular/router";

@Component({
selector: "app-root",
standalone: true,
imports: [],
imports: [RouterOutlet, RouterLink],
templateUrl: "./app.component.html",
styleUrl: "./app.component.scss",
changeDetection: ChangeDetectionStrategy.OnPush,
Expand Down
20 changes: 19 additions & 1 deletion src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
import { Routes } from "@angular/router";
import { HomeComponent } from "./pages/home/home.component";

export const routes: Routes = [];
export const routes: Routes = [
{
path: "",
pathMatch: "full",
component: HomeComponent,
},
{
path: "register",
loadComponent: () =>
import("./pages/registration/registration.component").then(
(module) => module.RegistrationComponent,
),
},
{
path: "**",
redirectTo: "",
},
];
30 changes: 30 additions & 0 deletions src/app/pages/home/home.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@if (session.isAuthenticated()) {
<h1>Hello {{ session.user()?.displayName }}!</h1>
<button (click)="logOut()">Log Out</button>
} @else {
<h1>Sorry, you are not logged in.</h1>
<form (ngSubmit)="logIn()" #form="ngForm">
<label>
<span>Email</span>
<input
type="email"
[(ngModel)]="email"
name="email"
autocomplete="email"
required
/>
</label>
<label>
<span>Password</span>
<input
type="password"
[(ngModel)]="password"
name="password"
autocomplete="current-password"
required
/>
</label>
<button type="submit" [disabled]="form.invalid">Log In</button>
</form>
<p>Don't have an account? <a routerLink="/register">Register</a></p>
}
3 changes: 3 additions & 0 deletions src/app/pages/home/home.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: block;
}
31 changes: 31 additions & 0 deletions src/app/pages/home/home.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
ChangeDetectionStrategy,
Component,
inject,
model,
} from "@angular/core";
import { SessionService } from "../../services/session.service";
import { FormsModule } from "@angular/forms";
import { RouterLink } from "@angular/router";

@Component({
selector: "app-home",
standalone: true,
imports: [FormsModule, RouterLink],
templateUrl: "./home.component.html",
styleUrl: "./home.component.scss",
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HomeComponent {
session = inject(SessionService);
email = model("");
password = model("");

logIn(): void {
this.session.logIn(this.email(), this.password());
}

logOut(): void {
this.session.logOut();
}
}
23 changes: 23 additions & 0 deletions src/app/pages/registration/registration.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<form (ngSubmit)="register()" #form="ngForm">
<label>
<span>Email</span>
<input
type="email"
[(ngModel)]="email"
name="email"
autocomplete="email"
required
/>
</label>
<label>
<span>New Password</span>
<input
type="password"
[(ngModel)]="password"
name="password"
autocomplete="new-password"
required
/>
</label>
<button type="submit" [disabled]="form.invalid">Register</button>
</form>
3 changes: 3 additions & 0 deletions src/app/pages/registration/registration.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: block;
}
26 changes: 26 additions & 0 deletions src/app/pages/registration/registration.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {
ChangeDetectionStrategy,
Component,
inject,
model,
} from "@angular/core";
import { RegistrationService } from "../../services/registration.service";
import { FormsModule } from "@angular/forms";

@Component({
selector: "app-registration",
standalone: true,
imports: [FormsModule],
templateUrl: "./registration.component.html",
styleUrl: "./registration.component.scss",
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RegistrationComponent {
#registrationService = inject(RegistrationService);
email = model("");
password = model("");

register(): void {
this.#registrationService.register(this.email(), this.password());
}
}
25 changes: 25 additions & 0 deletions src/app/services/registration.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Injectable, inject } from "@angular/core";
import { Auth, createUserWithEmailAndPassword } from "@angular/fire/auth";
import { SessionService } from "./session.service";
import { Router } from "@angular/router";

/**
* This service allows users to create a new account.
*/
@Injectable({
providedIn: "root",
})
export class RegistrationService {
#auth = inject(Auth);
#router = inject(Router);
#session = inject(SessionService); // Ensure the session service is initialized.

public async register(email: string, password: string): Promise<void> {
try {
await createUserWithEmailAndPassword(this.#auth, email, password);
this.#router.navigateByUrl("/");
} catch (error) {
console.error("Account creation failed:", error);
}
}
}
41 changes: 41 additions & 0 deletions src/app/services/session.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Injectable, computed, inject, signal } from "@angular/core";
import { Auth, signInWithEmailAndPassword } from "@angular/fire/auth";

/**
* This service allows users to create and destroy a session.
*/
@Injectable({
providedIn: "root",
})
export class SessionService {
#auth = inject(Auth);
#user = signal(this.#auth.currentUser);
public isAuthenticated = computed(() => this.#user() !== null);
public user = computed(() => this.#user());

constructor() {
this.#auth.onAuthStateChanged((user) => {
this.#user.set(user);
});
}

public async logIn(email: string, password: string): Promise<void> {
try {
if (this.#auth.currentUser !== null)
throw new Error("A user is already logged in.");
await signInWithEmailAndPassword(this.#auth, email, password);
} catch (error) {
console.error("Login attempt failed:", error);
}
}

public async logOut(): Promise<void> {
try {
if (this.#auth.currentUser === null)
throw new Error("No user is currently logged in.");
await this.#auth.signOut();
} catch (error) {
console.error("Logout attempt failed:", error);
}
}
}

0 comments on commit ef16109

Please sign in to comment.