Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3c559fe
moved components to the core/components folder
rnastyuk Mar 3, 2025
8273b6a
added basic login component
rnastyuk Mar 3, 2025
01776c3
added auth service and auth store
rnastyuk Mar 3, 2025
d9ee0b6
removed login component, added sign-in and sign-up components
rnastyuk Mar 3, 2025
d0f43ba
removed redundant modifiers in auth service
rnastyuk Mar 4, 2025
23da6fa
chore(merge): main into 49
rnastyuk Mar 4, 2025
77d8953
chore(primeng-setup): basic design system configuration
rnastyuk Mar 7, 2025
866b053
Merge branch 'refs/heads/main' into chore/101-setup-primeng-design-sy…
rnastyuk Mar 7, 2025
fb38072
chore(primeng-setup): removed sign-in component
rnastyuk Mar 7, 2025
5731428
chore(primeng-setup): changed all private modifiers to '#'
rnastyuk Mar 7, 2025
1aa3a94
Merge branch 'refs/heads/main' into chore/101-setup-primeng-design-sy…
rnastyuk Mar 10, 2025
e15b309
feat(sign-up-design): create initial form layout
rnastyuk Mar 10, 2025
773cc6d
Merge branch 'main' into feat/49-design-sign-up-form
rnastyuk Mar 10, 2025
2e796bf
Merge branch 'refs/heads/main' into feat/49-design-sign-up-form
rnastyuk Mar 10, 2025
1ecfbbf
feat(sign-up-design): changed icons, finished form layout
rnastyuk Mar 10, 2025
0cf97d1
feat(sign-up-design): changed regexp, added autocomplete input attrib…
rnastyuk Mar 10, 2025
e89ae1e
feat(sign-up-design): removed console log
rnastyuk Mar 11, 2025
31c1d05
Merge remote-tracking branch 'origin/feat/49-design-sign-up-form' int…
rnastyuk Mar 11, 2025
ca54337
feat(sign-up-design): fixed some styles, added dynamic header button …
rnastyuk Mar 11, 2025
0d1b880
Merge branch 'refs/heads/main' into feat/49-design-sign-up-form
rnastyuk Mar 13, 2025
f72db40
feat(forgot-password-design): added forgot-password page layout
rnastyuk Mar 13, 2025
a7efe46
feat(forgot-password-design): resolved review comments
rnastyuk Mar 13, 2025
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ export const routes: Routes = [
(mod) => mod.SignUpComponent,
),
},
{
path: 'forgot-password',
loadComponent: () =>
import(
'./features/auth/forgot-password/forgot-password.component'
).then((mod) => mod.ForgotPasswordComponent),
},
{
path: 'reset-password',
loadComponent: () =>
import(
'./features/auth/reset-password/reset-password.component'
).then((mod) => mod.ResetPasswordComponent),
},
{
path: 'home',
loadComponent: () =>
Expand Down
2 changes: 0 additions & 2 deletions src/app/core/components/header/header.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
<a [routerLink]="authButtonLink()" class="p-button">{{ authButtonText() }}</a>

<p-button label="Donate" severity="contrast" />
6 changes: 0 additions & 6 deletions src/app/core/components/sidenav/sidenav.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@
[routerLinkActiveOptions]="{ exact: true }"
>
@if (item.icon) {
<!-- <img-->
<!-- [ngSrc]="item.icon"-->
<!-- [alt]="item.label + ' icon'"-->
<!-- width="20"-->
<!-- height="20"-->
<!-- />-->
<i [class]="'osf-icon-' + item.icon"></i>
}
<span>{{ item.label }}</span>
Expand Down
5 changes: 5 additions & 0 deletions src/app/core/components/sidenav/sidenav.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@ export class SidenavComponent {
label: 'Support',
icon: 'support',
},
{
path: '/donate',
label: 'Donate',
icon: 'donate',
},
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<section class="forgot-password-container">
<h2>Forgot Your Password?</h2>
<p>Enter your email address and we'll send a link to reset your password</p>

<form [formGroup]="forgotPasswordForm" (ngSubmit)="onSubmit()">
<label for="email">Email</label>
<input
class="email-input"
id="email"
type="email"
pInputText
formControlName="email"
placeholder="email@example.com"
autocomplete="off"
/>

<p-button
class="btn-full-width"
type="submit"
label="Reset Password"
[disabled]="!forgotPasswordForm.valid"
></p-button>
</form>

<div class="message-container">
@if (message()) {
<p-message
[severity]="message()?.severity"
closable="true"
[text]="message()?.content"
(onClose)="onCloseMessage()"
/>
}
</div>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@use "assets/styles/mixins" as mix;
@use "assets/styles/variables" as var;

:host {
@include mix.flex-center;
flex: 1;
background: url("/assets/images/auth-background.png") center no-repeat;
background-size: cover;

.forgot-password-container {
position: relative;
@include mix.flex-column;
color: var.$dark-blue-1;
max-width: 32rem;
flex: 1;
gap: 1.2rem;
padding: 2rem;
background: white;
border-radius: 0.6rem;
box-shadow: 0 2px 4px var.$grey-outline;

h2 {
text-align: center;
}

.email-input {
margin-bottom: 2.5rem;
}

.message-container {
width: 100%;
position: absolute;
bottom: -4.5rem;
left: 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ForgotPasswordComponent } from './forgot-password.component';

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

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

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

it('should create', () => {
expect(component).toBeTruthy();
});
});
49 changes: 49 additions & 0 deletions src/app/features/auth/forgot-password/forgot-password.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Component, inject, signal } from '@angular/core';
import { InputText } from 'primeng/inputtext';
import {
ReactiveFormsModule,
FormBuilder,
FormGroup,
Validators,
} from '@angular/forms';
import { Button } from 'primeng/button';
import { MessageInfo } from './message-info.model';
import { Message } from 'primeng/message';

@Component({
selector: 'osf-forgot-password',
standalone: true,
imports: [InputText, ReactiveFormsModule, Button, Message],
templateUrl: './forgot-password.component.html',
styleUrl: './forgot-password.component.scss',
})
export class ForgotPasswordComponent {
forgotPasswordForm: FormGroup;
message = signal<null | MessageInfo>(null);
private fb = inject(FormBuilder);

constructor() {
this.forgotPasswordForm = this.fb.group({
email: ['', [Validators.required, Validators.email]],
});
}

onSubmit(): void {
// TODO: Implement password reset logic
if (this.forgotPasswordForm.valid) {
this.message.set({
severity: 'success',
content: 'Thanks. Check your email to reset your password.',
});

// this.message.set({
// severity: 'error',
// content: 'Email not found.',
// });
}
}

onCloseMessage(): void {
this.message.set(null);
}
}
4 changes: 4 additions & 0 deletions src/app/features/auth/forgot-password/message-info.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface MessageInfo {
severity: 'error' | 'warn' | 'success';
content: string;
}
60 changes: 60 additions & 0 deletions src/app/features/auth/reset-password/reset-password.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@if (!isFormSubmitted()) {
<section class="reset-password-container">
<h2>Reset Password</h2>

<form [formGroup]="resetPasswordForm" (ngSubmit)="onSubmit()">
<div class="field">
<label for="password">New Password</label>
<p-password
id="password"
formControlName="password"
[toggleMask]="true"
[feedback]="false"
autocomplete="new-password"
></p-password>

<osf-password-input-hint
[isError]="
resetPasswordForm.get('password')?.errors &&
resetPasswordForm.get('password')?.touched
"
/>
</div>

<div class="field">
<label for="confirmPassword">Confirm New Password</label>
<p-password
id="confirmPassword"
formControlName="confirmPassword"
[toggleMask]="true"
[feedback]="false"
autocomplete="new-password"
></p-password>
@if (
resetPasswordForm.get("confirmPassword")?.errors?.[
"passwordMismatch"
] && resetPasswordForm.get("confirmPassword")?.touched
) {
<small class="text-danger">Passwords must match</small>
}
</div>

<p-button
class="btn-full-width"
type="submit"
label="Reset Password"
[disabled]="!resetPasswordForm.valid"
></p-button>
</form>
</section>
} @else {
<section class="message-container">
<h2>Thank You!</h2>
<p class="message-text">You have successfully reset your password</p>
<p-button
class="btn-full-width"
label="Back to Sign In"
[routerLink]="['/sign-up']"
/>
</section>
}
50 changes: 50 additions & 0 deletions src/app/features/auth/reset-password/reset-password.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@use "assets/styles/mixins" as mix;
@use "assets/styles/variables" as var;

:host {
@include mix.flex-center;
flex: 1;
background: url("/assets/images/auth-background.png") center no-repeat;
background-size: cover;

.reset-password-container,
.message-container {
@include mix.flex-column;
color: var.$dark-blue-1;
max-width: 32rem;
flex: 1;
gap: 1.2rem;
padding: 2rem;
background: white;
border-radius: 0.6rem;
box-shadow: 0 2px 4px var.$grey-outline;

h2,
.message-text {
text-align: center;
}

.message-text {
margin-bottom: 1.5rem;
}

form {
@include mix.flex-column;
flex: 1;

.field {
margin-bottom: 1rem;

.text-danger {
color: var.$red-1;
font-weight: 600;
}
}

small {
color: var.$pr-blue-1;
font-weight: 600;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ResetPasswordComponent } from './reset-password.component';

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

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

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

it('should create', () => {
expect(component).toBeTruthy();
});
});
61 changes: 61 additions & 0 deletions src/app/features/auth/reset-password/reset-password.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Component, inject, OnInit, signal } from '@angular/core';
import { Button } from 'primeng/button';
import {
FormBuilder,
FormGroup,
ReactiveFormsModule,
Validators,
} from '@angular/forms';
import { Password } from 'primeng/password';
import { RouterLink } from '@angular/router';
import {
PASSWORD_REGEX,
passwordMatchValidator,
} from '../sign-up/sign-up.helper';
import { PasswordInputHintComponent } from '@shared/components/password-input-hint/password-input-hint.component';

@Component({
selector: 'osf-reset-password',
standalone: true,
imports: [
Button,
Password,
ReactiveFormsModule,
RouterLink,
PasswordInputHintComponent,
],
templateUrl: './reset-password.component.html',
styleUrl: './reset-password.component.scss',
})
export class ResetPasswordComponent implements OnInit {
private fb = inject(FormBuilder);
passwordRegex: RegExp = PASSWORD_REGEX;
resetPasswordForm: FormGroup = new FormGroup({});
isFormSubmitted = signal(false);

ngOnInit(): void {
this.initializeForm();
}

private initializeForm(): void {
this.resetPasswordForm = this.fb.group(
{
password: [
'',
[Validators.required, Validators.pattern(this.passwordRegex)],
],
confirmPassword: ['', Validators.required],
},
{
validators: passwordMatchValidator(),
},
);
}

onSubmit(): void {
if (this.resetPasswordForm.valid) {
// TODO: Implement password reset logic
this.isFormSubmitted.set(true);
}
}
}
Loading