feat: frontend send
This commit is contained in:
@@ -41,6 +41,7 @@ export class ScreenLogin {
|
|||||||
this.router.navigateByUrl(returnUrl);
|
this.router.navigateByUrl(returnUrl);
|
||||||
},
|
},
|
||||||
error: (err) => {
|
error: (err) => {
|
||||||
|
//FIXME error message displaying delayed, display message from server response
|
||||||
this.error = err.error?.message || 'Login failed. Please try again.';
|
this.error = err.error?.message || 'Login failed. Please try again.';
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
<!-- Note Field -->
|
<!-- Note Field -->
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label class="form-label">Note (Optional)</label>
|
<label class="form-label">Note (Optional)</label>
|
||||||
<textarea class="form-control" rows="2" [(ngModel)]="note"></textarea>
|
<textarea class="form-control" rows="2" [(ngModel)]="reference"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { APIService } from '../../services/api';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-screen-send',
|
selector: 'app-screen-send',
|
||||||
@@ -10,16 +11,27 @@ import { FormsModule } from '@angular/forms';
|
|||||||
export class ScreenSend {
|
export class ScreenSend {
|
||||||
amount: number = 0;
|
amount: number = 0;
|
||||||
recipient: string = '';
|
recipient: string = '';
|
||||||
note: string = '';
|
reference: string = '';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private api: APIService,
|
||||||
|
){}
|
||||||
|
|
||||||
sendMoney() {
|
sendMoney() {
|
||||||
console.log('Sending:', this.amount, 'to', this.recipient);
|
this.api.send(this.amount, this.recipient, this.reference).subscribe({
|
||||||
// Add your logic here (e.g., API call)
|
next:()=> {
|
||||||
|
this.cancel()
|
||||||
|
//TODO show success message
|
||||||
|
},
|
||||||
|
error:()=> {
|
||||||
|
//TODO show error message
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.amount = 0;
|
this.amount = 0;
|
||||||
this.recipient = '';
|
this.recipient = '';
|
||||||
this.note = '';
|
this.reference = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { BehaviorSubject, catchError, map, Observable, of, tap } from 'rxjs';
|
import { BehaviorSubject, catchError, map, Observable, of, tap } from 'rxjs';
|
||||||
import Transaction from '@model/transaction'
|
import Transaction from '@model/transaction'
|
||||||
|
import { SendRequest, SendResponse } from '@message/Send';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
@@ -13,9 +14,6 @@ export class APIService {
|
|||||||
|
|
||||||
constructor(private http: HttpClient){}
|
constructor(private http: HttpClient){}
|
||||||
|
|
||||||
getTransactions(): Observable<Transaction[]>{
|
|
||||||
return this.http.get<Transaction[]>(`${this.apiUrl}/transactions`);
|
|
||||||
}
|
|
||||||
login(username: string, password: string): Observable<any>{
|
login(username: string, password: string): Observable<any>{
|
||||||
return this.http.post(`${this.apiUrl}/auth/login`,{ 'username': username, 'password': password});
|
return this.http.post(`${this.apiUrl}/auth/login`,{ 'username': username, 'password': password});
|
||||||
}
|
}
|
||||||
@@ -23,7 +21,7 @@ export class APIService {
|
|||||||
return this.http.post(`${this.apiUrl}/auth/logout`, {});
|
return this.http.post(`${this.apiUrl}/auth/logout`, {});
|
||||||
}
|
}
|
||||||
checkAuthStatus(): Observable<boolean> {
|
checkAuthStatus(): Observable<boolean> {
|
||||||
return this.http.get(`${this.apiUrl}/auth/status`, { withCredentials: true}).pipe(
|
return this.http.get(`${this.apiUrl}/auth/status`).pipe(
|
||||||
map(() => true),
|
map(() => true),
|
||||||
catchError(() => of(false)),
|
catchError(() => of(false)),
|
||||||
tap({
|
tap({
|
||||||
@@ -32,4 +30,11 @@ export class APIService {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
getTransactions(): Observable<Transaction[]>{
|
||||||
|
return this.http.get<Transaction[]>(`${this.apiUrl}/transactions`);
|
||||||
|
}
|
||||||
|
send(amount: number, recipientID: string, reference: string = ""): Observable<SendResponse>{
|
||||||
|
let request: SendRequest = {amount, recipientID, reference};
|
||||||
|
return this.http.post<SendResponse>(`${this.apiUrl}/send`, request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const authGuard: CanActivateFn = (route, state) => {
|
|||||||
const api = inject(APIService);
|
const api = inject(APIService);
|
||||||
const router = inject(Router);
|
const router = inject(Router);
|
||||||
|
|
||||||
//TODO check for cookie
|
//FIXME always redirected to login after page load
|
||||||
return api.isAuthenticated$.pipe(
|
return api.isAuthenticated$.pipe(
|
||||||
map((isAuthenticated) => {
|
map((isAuthenticated) => {
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
|
|||||||
9
server/src/messages/Login.ts
Normal file
9
server/src/messages/Login.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export class LoginRequest{
|
||||||
|
constructor(
|
||||||
|
username: string,
|
||||||
|
password: string
|
||||||
|
){}
|
||||||
|
}
|
||||||
|
export class LoginResponse{
|
||||||
|
constructor(){}
|
||||||
|
}
|
||||||
@@ -2,6 +2,9 @@ import express from 'express';
|
|||||||
import { logger } from '../util/logging';
|
import { logger } from '../util/logging';
|
||||||
import User from '../model/user';
|
import User from '../model/user';
|
||||||
import { getJWT, requireAuth } from '../util/auth';
|
import { getJWT, requireAuth } from '../util/auth';
|
||||||
|
import { LoginRequest } from '@message/Login';
|
||||||
|
import { SendRequest, SendResponse } from '@message/Send';
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@@ -26,7 +29,7 @@ router.post('/login', async (req, res) => {
|
|||||||
res.json({ message: 'Logged in successfully' });
|
res.json({ message: 'Logged in successfully' });
|
||||||
}catch (err) {
|
}catch (err) {
|
||||||
logger.error('Failed to authenticate:', err);
|
logger.error('Failed to authenticate:', err);
|
||||||
res.status(500).json({ error: 'Failed to authenticate' });
|
res.status(500).json({ message: 'Failed to authenticate' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ const router = express.Router();
|
|||||||
|
|
||||||
router.get('/', requireAuth, async (req, res) => {
|
router.get('/', requireAuth, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const transactions = await Transaction.findAll({ limit: 10 });
|
const transactions = await Transaction.findAll({
|
||||||
|
limit: 100,
|
||||||
|
order: [['date', 'DESC']]
|
||||||
|
});
|
||||||
res.json(transactions);
|
res.json(transactions);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Failed to fetch transactions:', err);
|
logger.error('Failed to fetch transactions:', err);
|
||||||
|
|||||||
Reference in New Issue
Block a user