Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

poc #44

Merged
merged 13 commits into from
Apr 2, 2024
5 changes: 1 addition & 4 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,7 @@
],
"no-console": "error",
"no-useless-escape": "off",
"linebreak-style": [
"warn",
"unix"
],
"linebreak-style": "off",
"quotes": [
"error",
"single"
Expand Down
4 changes: 3 additions & 1 deletion src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { TestBed } from '@angular/core/testing';
import { provideMockStore } from '@ngrx/store/testing';

import { DashboardComponent } from './dashboard/dashboard/dashboard.component';
import { DashboardComponent } from './layouts/dashboard/dashboard.component';

describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DashboardComponent],
providers: [provideMockStore({})],
}).compileComponents();
});

Expand Down
15 changes: 9 additions & 6 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { AuthGuard, redirectUnauthorizedTo } from '@angular/fire/auth-guard';
import { Routes } from '@angular/router';

import { DashboardComponent } from './dashboard/dashboard/dashboard.component';
import { InvestmentCalculatorComponent } from './dashboard/investment-calculator/investment-calculator.component';
import { TransferComponent } from './dashboard/transfer/transfer.component';
import { PendingRequestsComponent } from './layouts/advisor/pending-requests/pending-requests.component';
import { PreviousRequestsComponent } from './layouts/advisor/previous-requests/previous-requests.component';
import { DashboardComponent } from './layouts/dashboard/dashboard.component';
import { InvestmentCalculatorComponent } from './layouts/investment-calculator/investment-calculator.component';
import { ReportsComponent } from './layouts/reports/reports.component';
import { TransferComponent } from './layouts/transfer/transfer.component';
import { ProfileComponent } from './user/profile/profile.component';
import { UserLoginComponent } from './user/user-login/user-login.component';
import { UserRegisterComponent } from './user/user-register/user-register.component';
Expand Down Expand Up @@ -44,19 +47,19 @@ export const routes: Routes = [
},
{
path: 'reports',
component: DashboardComponent,
component: ReportsComponent,
canActivate: [AuthGuard],
data: { authGuardPipe: redirectUnauthorizedToLanding },
},
{
path: 'pending-requests',
component: DashboardComponent,
component: PendingRequestsComponent,
canActivate: [AuthGuard],
data: { authGuardPipe: redirectUnauthorizedToLanding },
},
{
path: 'previous-requests',
component: DashboardComponent,
component: PreviousRequestsComponent,
canActivate: [AuthGuard],
data: { authGuardPipe: redirectUnauthorizedToLanding },
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface IRequestAdvisor {
requestId: string;
userId: string;
userEmail: string;
advisorId: string;
advisorEmail: string;
accountBalance: number;
initialInvestment: number;
additionalInvestment: number;
frequencyOfInvestment: string;
isPending: boolean;
advisorConclusions: string;
score: number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<h1 mat-dialog-title>Review request - {{ userEmail }}</h1>
<div class="container">
<div mat-dialog-content>
<p class="mb-3">
Please provide your feedback on the review request from {{ userEmail }}. The user that requested the review will be able to see
your feedback.
</p>
<div class="row mb-3">
<div class="col-md-6">
<mat-card>
<mat-card-header>
<mat-card-title>Account Information</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-icon>account_balance</mat-icon>
Account Balance: {{ accountBalance }} RON
</mat-card-content>
</mat-card>
</div>
<div class="col-md-6">
<mat-card>
<mat-card-header>
<mat-card-title>Investment Information</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-icon>attach_money</mat-icon>
Initial Investment: {{ initialInvestment }} RON
</mat-card-content>
<mat-card-content>
<mat-icon>add_circle</mat-icon>
Additional Investment: {{ additionalInvestment }} RON
</mat-card-content>
<mat-card-content>
<mat-icon>alarm</mat-icon>
Frequency of Investment: {{ frequencyOfInvestment }}
</mat-card-content>
</mat-card>
</div>
</div>
<form [formGroup]="reviewForm" class="row">
<mat-form-field>
<mat-label>Advisor Conclusions</mat-label>
<textarea matInput formControlName="advisorConclusions" rows="5"></textarea>
<mat-error *ngIf="reviewForm.get('advisorConclusions')!.invalid">This field is required</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>Score</mat-label>
<mat-select formControlName="score">
<mat-option *ngFor="let score of [1, 2, 3, 4, 5]" [value]="score">{{ score }}</mat-option>
</mat-select>
<mat-error *ngIf="reviewForm.get('score')!.invalid">Please select a score</mat-error>
</mat-form-field>
</form>
</div>
</div>
<div mat-dialog-actions class="d-flex justify-content-end">
<button mat-button mat-dialog-close>Close</button>
<button mat-button color="primary" (click)="submitReview()" [disabled]="!reviewForm.valid">Send</button>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
mat-card-title {
margin-bottom: 0.5rem;
}

mat-card-content {
display: flex;
margin-right: auto;
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}

mat-card-content mat-icon {
margin-right: 5px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { NgForOf, NgIf } from '@angular/common';
import { Component, inject, Inject } from '@angular/core';
import { collection, doc, Firestore, updateDoc } from '@angular/fire/firestore';
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatButton } from '@angular/material/button';
import { MatCard, MatCardContent, MatCardHeader, MatCardTitle } from '@angular/material/card';
import {
MAT_DIALOG_DATA,
MatDialogActions,
MatDialogClose,
MatDialogContent,
MatDialogRef,
MatDialogTitle,
} from '@angular/material/dialog';
import { MatError, MatFormField, MatLabel } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
import { MatOption, MatSelect } from '@angular/material/select';

import { IRequestAdvisor } from '../../common/interface/advisor-request.interface';

@Component({
selector: 'app-pending-request-review-modal',
standalone: true,
imports: [
FormsModule,
MatButton,
MatDialogActions,
MatDialogTitle,
MatDialogContent,
MatLabel,
MatFormField,
MatSelect,
MatOption,
NgForOf,
ReactiveFormsModule,
MatInput,
NgIf,
MatDialogClose,
MatError,
MatCardHeader,
MatCard,
MatIcon,
MatCardContent,
MatCardTitle,
],
templateUrl: './pending-request-review-modal.component.html',
styleUrl: './pending-request-review-modal.component.scss',
})
export class PendingRequestReviewModalComponent {
firestore: Firestore = inject(Firestore);
reviewForm: FormGroup;
requestId: string;
userEmail: string;
accountBalance: number;
initialInvestment: number;
additionalInvestment: number;
frequencyOfInvestment: string;

constructor(
private dialogRef: MatDialogRef<PendingRequestReviewModalComponent>,
@Inject(MAT_DIALOG_DATA) private data: IRequestAdvisor,
private fb: FormBuilder,
) {
this.requestId = data.requestId;
this.userEmail = data.userEmail;
this.accountBalance = data.accountBalance;
this.initialInvestment = data.initialInvestment;
this.additionalInvestment = data.additionalInvestment;
this.frequencyOfInvestment = data.frequencyOfInvestment;

this.reviewForm = this.fb.group({
advisorConclusions: [data.advisorConclusions, Validators.required],
score: [data.score, Validators.required],
});
}

submitReview() {
if (this.reviewForm.valid) {
const collectionRef = collection(this.firestore, 'advisorRequests');
const docRef = doc(collectionRef, this.requestId);
updateDoc(docRef, {
isPending: false,
advisorConclusions: this.reviewForm.value.advisorConclusions,
score: this.reviewForm.value.score,
}).then(() => {
this.dialogRef.close(true);
});
this.dialogRef.close();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div *ngIf="pendingRequests" class="container m-5">
<div class="row">
<h2 class="request-header col-10">Pending advisory requests</h2>
</div>
<table class="request-table">
<thead>
<tr>
<th>Requester</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let request of pendingRequests" class="request-row">
<td>{{ request.userEmail }}</td>
<td>
<button class="btn btn-success" (click)="reviewRequest(request)">Review</button>
<button class="btn btn-danger ms-1" (click)="deleteRequest(request)">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.request-header {
font-size: 24px;
margin-bottom: 10px;
}

.request-table {
width: 100%;
border-collapse: collapse;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.request-table th,
.request-table td {
padding: 12px;
text-align: left;
}

.request-table th {
background-color: #f2f2f2;
font-weight: bold;
}

.request-row:nth-child(even) {
background-color: #f2f2f2;
}

.request-row:hover {
background-color: #ddd;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { NgForOf, NgIf } from '@angular/common';
import { Component, inject, OnInit } from '@angular/core';
import { collection, deleteDoc, doc, Firestore, onSnapshot, query, where } from '@angular/fire/firestore';
import { MatButton } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { Store } from '@ngrx/store';

import { PendingRequestReviewModalComponent } from './pending-request-review-modal/pending-request-review-modal.component';
import { IAppState } from '../../../common/interface/app-state.interface';
import { selectUser } from '../../../user/store/user.selectors';
import { IRequestAdvisor } from '../common/interface/advisor-request.interface';

@Component({
selector: 'app-pending-requests',
standalone: true,
imports: [NgIf, MatButton, NgForOf],
templateUrl: './pending-requests.component.html',
styleUrl: './pending-requests.component.scss',
})
export class PendingRequestsComponent implements OnInit {
store: Store<IAppState> = inject(Store);
firestore: Firestore = inject(Firestore);
userData$ = this.store.select(selectUser);
pendingRequests: IRequestAdvisor[] = [];
dialog: MatDialog = inject(MatDialog);

ngOnInit(): void {
this.userData$.subscribe(user => {
const advisorCollectionRef = collection(this.firestore, 'advisorRequests');
const advisorQuery = query(advisorCollectionRef, where('advisorId', '==', user.uid), where('isPending', '==', true));
onSnapshot(advisorQuery, snapshot => {
this.pendingRequests = [];
snapshot.forEach(doc => {
this.pendingRequests.push(doc.data() as IRequestAdvisor);
});
});
});
}

deleteRequest(request: IRequestAdvisor) {
const docRef = doc(this.firestore, 'advisorRequests', request.requestId);
deleteDoc(docRef).then();
}

reviewRequest(request: IRequestAdvisor) {
this.dialog.open(PendingRequestReviewModalComponent, {
data: request,
maxHeight: '80%',
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<div *ngIf="previousRequests" class="container m-5">
<div class="row">
<h2 class="request-header col-10">Already completed requests</h2>
</div>
<table class="request-table">
<thead>
<tr>
<th>Requester</th>
<th>Score</th>
<th>Conclusions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let request of previousRequests" class="request-row">
<td>{{ request.userEmail }}</td>
<td>{{ request.score }}</td>
<td>{{ request.advisorConclusions }}</td>
</tr>
</tbody>
</table>
</div>
Loading
Loading