How to integrate Stripe payment in Ionic 4 - stripe-payments

I am new in ionic framework and trying to integrate stripe in my app.
I did some research and found only this https://ionicframework.com/docs/native/stripe. It doesn't explain well enough. How can i implement the concept on .html file like to provide a user with a button to trigger the payment?
I also tried this https://fireship.io/lessons/stripe-elements-angular/ but got lost along the way.
checkout.page.ts
import { Component, OnInit, Input, HostListener } from '#angular/core';
// import { Stripe } from '#ionic-native/stripe/ngx';
import { AuthService } from '../services/auth.service';
import { FirebaseService } from '../services/firebase.service';
import { AngularFireFunctions } from '#angular/fire/functions';
import { Router } from '#angular/router';
import { Observable, of } from 'rxjs';
declare var Stripe;
#Component({
selector: 'app-rentals',
templateUrl: './rentals.page.html',
styleUrls: ['./rentals.page.scss'],
})
export class RentalsPage implements OnInit {
user$: Observable<User>;
constructor(
private router: Router,
// private stripe: Stripe,
private firebaseService: FirebaseService,
private auth: AuthService,
private functions: AngularFireFunctions
)
{
}
#Input() amount;
#Input() description;
handler: StripeCheckoutHandler;
confirmation: any;
loading = false;
ngOnInit() {
this.handler = StripeCheckout.configure({
key: 'pk_test_3PyCxdSZ21lC5Wg7lOs2gyF8',
image: '/assets/icon/favicon.png',
locale: 'auto',
source: async (source) => {
this.loading = true;
const user = await this.firebaseService.User();
const fun = this.functions.httpsCallable('stripeCreateCharge');
this.confirmation = await fun({ source: source.id, uid: user.uid, amount: this.amount }).toPromise();
this.loading = false;
}
});
}
// Open the checkout handler
async checkout(e) {
const user = await this.auth.getUser();
this.handler.open({
name: 'Fireship Store',
description: this.description,
amount: this.amount,
email: user.email,
});
e.preventDefault();
}
// Close on navigate
#HostListener('window:popstate')
onPopstate() {
this.handler.close();
}
}
checkout.page.html
<ion-card>
<ion-card-header>
<img *ngIf="!fileUrl" src="assets/1.jpeg"/>
<ion-card-subtitle>Bed Sitter</ion-card-subtitle>
<ion-input type="hidden" [(ngModel)]="id">{{ plan_Et8WWHlFFGNxym }}</ion-input>
<ion-card-title>KSH4,000.00 Monthly</ion-card-title>
</ion-card-header>
<ion-card-content>
bed sitter flat
</ion-card-content>
<ion-card-content>
<ion-input type="hidden" [(ngModel)]="amount">{{ 4000 }}</ion-input>
<ion-button slot="end" color="primary" (click)="checkout($event)">Pay 4000.00</ion-button>
</ion-card-content>
</ion-card>
auth.service.ts
import { Injectable } from '#angular/core';
import * as firebase from 'firebase/app';
import { FirebaseService } from './firebase.service';
import { AngularFireAuth } from '#angular/fire/auth';
import { Observable, of } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class AuthService {
user$: Observable<User>;
constructor(
private firebaseService: FirebaseService,
public afAuth: AngularFireAuth
){}
doRegister(value){
return new Promise<any>((resolve, reject) => {
firebase.auth().createUserWithEmailAndPassword(value.email, value.password)
.then(
res => resolve(res),
err => reject(err))
})
}
doLogin(value){
return new Promise<any>((resolve, reject) => {
firebase.auth().signInWithEmailAndPassword(value.email, value.password)
.then(
res => resolve(res),
err => reject(err))
})
}
doLogout(){
return new Promise((resolve, reject) => {
this.afAuth.auth.signOut()
.then(() => {
this.firebaseService.unsubscribeOnLogOut();
resolve();
}).catch((error) => {
console.log(error);
reject();
});
})
}
}
I expect the code to fetch subscription plans from stripe or as i have input manually on the code above, to post the payment with the stated plan to stripe.

Related

List is not updated for existing clients in socketIO

I am working on chat application, using socketIO
Whenever user signed in sucessfully, user is navigated to dashboard and list of current loggedin users will be displayed.
Whenever new user is signed in, existing user list is not getting updated.
Adding the necessary code here
events: backend
let verifyClaim = require("./tokenLib");
let socketio = require("socket.io");
let tokenLibs = require('./tokenLib');
let setService = (server) => {
let onlineUsers = [];
let io = socketio.listen(server);
let myio = io.of('')
myio.on('connection', (socket) => {
console.log(' emitting verify user');
socket.emit("verifyUser", "");
socket.on('set-user', (authToken) => {
console.log(authToken);
tokenLibs.verifyTokenWithoutSecret(authToken, (user, err,) => {
if (user) {
console.log(user);
let currentUser = user;
socket.userId = currentUser._id;
let fullName = `${currentUser.name}`
console.log(`${fullName} is online`);
socket.emit(currentUser._id, `${fullName} is online`)
let userObj = { userId: currentUser._id, name: fullName }
onlineUsers.push(userObj);
console.log(onlineUsers)
socket.emit('userlist', onlineUsers)
}
else {
socket.emit('auth-error', { status: 500, error: 'Please provide valid token ' })
}
})
})
socket.on('disconnect', () => {
console.log('user is disconnected');
let removeUserId = onlineUsers.map(function (user) { return user.userId }).indexOf(socket.userId)
onlineUsers.splice(removeUserId, 1)
console.log(onlineUsers)
})
})
}
module.exports = { setService: setService }
socket service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import * as io from 'socket.io-client';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class SocketService {
public prod = 'https://todolistbe.herokuapp.com/api/v1';
public dev = 'http://localhost:3001';
public baseUrl = this.dev;
private socket;
constructor(public http: HttpClient) {
this.socket=io('http://localhost:3001')
}
public verifyUser=()=>{
return Observable.create((observer)=>{
this.socket.on('verifyUser',(data)=>{
observer.next(data);
})
})
}
public setUser=(authToken)=>{
this.socket.emit("set-user",authToken)
}
public userList=()=>{
return Observable.create((observer)=>{
this.socket.on('userlist',(data)=>{
observer.next(data);
})
})
}
public welcomeUser=(userid)=>{
return Observable.create((observer)=>{
this.socket.on(userid,(data)=>{
observer.next(data);
})
})
}
public disconnectUser = () => {
return Observable.create((observer) => {
this.socket.on('disconnect', () => {
observer.next()
})
})
}
}
dashboard:
import { Component, OnInit } from '#angular/core';
import { ThemePalette } from '#angular/material/core';
import { SocketService } from '../../socket.service';
import { ToastrService } from 'ngx-toastr';
export interface Task {
name: string;
completed: boolean;
color: ThemePalette;
subtasks?: Task[];
}
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css'],
providers: [SocketService]
})
export class DashboardComponent implements OnInit {
public authToken: any = localStorage.getItem('authToken');
public userList: any = [];
public userNotification;
allComplete: boolean = false;
ngOnInit(): void {
this.verifyUserConfirmation();
this.getOnlineUsers();
}
public verifyUserConfirmation: any = () => {
this.SocketService.verifyUser().subscribe((data) => {
console.log(this.authToken)
this.SocketService.setUser(this.authToken);
this.getOnlineUsers();
})
}
selected = 'option2';
toggleNavbar() {
console.log('toggled' + this.isMenuOpened);
this.isMenuOpened = !this.isMenuOpened;
}
getOnlineUsers() {
// this.SocketService.welcomeUser(localStorage.getItem('id')).subscribe((data)=>{
// this.userNotification=data;
// console.log("hi:"+this.userNotification)
// })
this.SocketService.userList().subscribe((user) => {
this.userList = [];
for (let x in user) {
let tmp = { 'user': x, 'name': user[x] }
this.userList.push(tmp);
}
console.log(this.userList)
})
}
}
Whenever you want to emit an event with all other users, we should use myio.emit instead of socket.io.
Issue is resolved when i made necessary changed in my backend events library

I am getting multiple calls from angular to the Post API in Node

I am trying to write a file from the data from the database but I'm getting multiple calls from the angular causing multiple entries of the same data.How can I stop that? And also it is causing to override write file after some time.
I am not getting what exactly should I do. I have tried subscribing thing in service in angular but it was of no help.
component.ts
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { FormGroup, FormBuilder, Validators } from '#angular/forms';
import { NgbModalRef, NgbModal } from '#ng-bootstrap/ng-bootstrap';
import { ToastrService } from 'ngx-toastr';
import { CountryService } from './country.service';
import { ConfigService } from '../config.service';
#Component({
selector: 'app-country',
templateUrl: './country.component.html',
styleUrls: ['./country.component.scss'],
encapsulation: ViewEncapsulation.None,
providers: []
})
export class CountryComponent implements OnInit {
public modalRef: NgbModalRef;
public form: FormGroup;
public selectedCountry;
public countries;
constructor(public fb: FormBuilder, public toastrService: ToastrService,
public modalService: NgbModal, public configService: ConfigService,
public countryService: CountryService) {
}
ngOnInit() {
this.form = this.fb.group({
country: [null, Validators.compose([Validators.required])],
});
this.getCountries();
}
public getCountries() {
this.countryService.getCountries((data) => {
this.countries = data.countries;
}, (err) => { });
}
public selectCountry(country) {
this.countryService.selectCountry(country, (resp) => {
}, (err) => { });
}
}
service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { ConfigService } from '../config.service';
import { ToastrService } from 'ngx-toastr';
#Injectable({
providedIn: 'root'
})
export class CountryService {
private setHeaders() {
const headers = new HttpHeaders({
'content-type': 'application/json',
});
return headers;
}
constructor(private configService: ConfigService, public http: HttpClient, public toastrService: ToastrService) { }
selectCountry(country: any, callback, errCallback) {
const options = {
headers: this.setHeaders(),
};
this.http.post(this.configService.url + '/selectedCountry', country, options).subscribe((resp: any) => {
callback(resp);
}, err => {
errCallback(err);
});
}
getCountries(callback, errCallback) {
const options = {
headers: this.setHeaders(),
};
this.http.get(this.configService.url + '/countries', options).subscribe((resp: any) => {
callback(resp.msg);
}, err => {
errCallback(err);
});
}
}
I want the call to be sent only once, not twice
Btw. - Please consider adding the NGRX lib in your app.
An angular-service is considered as a data holder. So make there an instance variable.
It could look like:
export class Service{
private countries;
...
public getCountries(){
return this.countries;
}
public loadCountries(){
this.http.get("url").subscribe(countries => this.countries = countries);
}
}
Then in your component class, you just get the countries.
export class Component{
public coutries;
...
public ngOnInit(){
this.countryService.getCountries(countries => this.countries=coutries);
}
}
And last but not least - load the countries in your AppComponent.
export class AppComponent{
...
public ngOnInit(){
this.countryService.loadCountries();
}
}
Need all your code if you can do a stackblitz, and like Mateusz said its better to handle state with ngrx if you dont want to call twice to backend or a simple approach its something like this https://stackblitz.com/edit/angular-biv6cw.
Change your service method like:
add interface:
export interface Country{
id: number;
name: string;
}
Change your method:
getCountries(): Observable<Country> {
return this.httpClient
.get('pass api url here')
.pipe(
map((body: any) => body),
catchError(error => of(error))
);
}
In your component:
ngOnInit() {
this.countryService.getCountries().subscribe(
(result: Countries) => {
this.countries = result;
},
err => {
log.debug('get countries error', err);
}
);
}
}
Try this:
// Somewhere on init
let postRequestCount = 0;
// More stuff …
// Just before doing the POST request inside the `selectCountry` method
if(postRequestCount < 1) {
http.post(); // TODO : Replace with the actual `post` method
}
postRequestCount++;

TypeError: token.split is not a function

I Have get some error while login which is not expected but i try to solve it from 2 days but i cannot. I am using Nodejs for the api and angular 7 for the frontend
i have posted some of the code with the error
please help me to solve this
THANK YOU SO MUCH IN ADVANCE
auth.service.ts
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
import "rxjs/Rx";
import { JwtHelperService } from "#auth0/angular-jwt";
import "core-js/es7/reflect";
import { HttpClient } from "#angular/common/http";
const jwt = new JwtHelperService();
#Injectable()
export class AuthService {
private decodedToken;
constructor(private http: HttpClient) {}
public register(userData: any): Observable<any> {
return this.http.post("/api/v1/users/register", userData);
}
public login(userData: any): Observable<any> {
return this.http.post("/api/v1/users/auth", userData).map(token => {
//debugger;
return this.saveToken(token);
});
}
private saveToken(token): string {
//debugger;
this.decodedToken = jwt.decodeToken(token);
localStorage.setItem("bwm_auth", token.token);
localStorage.setItem("bwm_meta", JSON.stringify(this.decodedToken));
return token;
}
}
login.component.ts
import { Component, OnInit } from "#angular/core";
import { Router, ActivatedRoute } from "#angular/router";
import { AuthService } from "../shared/auth.service";
import { FormBuilder, FormGroup, Validators } from "#angular/forms";
#Component({
selector: "bwm-login",
templateUrl: "./login.component.html",
styleUrls: ["./login.component.scss"]
})
export class LoginComponent implements OnInit {
loginForm: FormGroup;
mistake: any[] = [];
notifyMessage: string = "";
constructor(
private fb: FormBuilder,
private auth: AuthService,
private router: Router,
private route: ActivatedRoute
) {}
ngOnInit() {
this.initForm();
this.route.params.subscribe(params => {
if (params["registered"] == "success") {
//debugger;
this.notifyMessage =
"You have been successfully registered you can login now";
}
});
}
initForm() {
this.loginForm = this.fb.group({
email: [
"",
[
Validators.required,
Validators.pattern(
"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*$"
)
]
],
password: ["", Validators.required]
});
}
isInvalidForm(fieldName): boolean {
return (
this.loginForm.controls[fieldName].invalid &&
(this.loginForm.controls[fieldName].dirty ||
this.loginForm.controls[fieldName].touched)
);
}
isRequiredForm(fieldName): boolean {
return this.loginForm.controls[fieldName].errors.required;
}
login() {
// debugger;
//console.log(this.loginForm.value);
this.auth.login(this.loginForm.value).subscribe(
token => {
//debugger;
this.router.navigate(["/rentals"]);
},
errorResponse => {
// debugger;
console.log(errorResponse);
// this.mistake = errorResponse.error.errors;
//this.mistake = errorResponse.error;
}
);
}
}
error in browser
TypeError: token.split is not a function
at JwtHelperService.push../node_modules/#auth0/angular-jwt/src/jwthelper.service.js.JwtHelperService.decodeToken (jwthelper.service.js:70)
at AuthService.push../src/app/auth/shared/auth.service.ts.AuthService.saveToken (auth.service.ts:26)
at MapSubscriber.project (auth.service.ts:20)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:35)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:41)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterSubscriber._next (filter.js:38)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber.notifyNext (mergeMap.js:84)
error in browser
As it seems the token that is returned from server is not string type
public login(userData: any): Observable<any> {
return this.http.post("/api/v1/users/auth", userData).map(token => {
//debugger;
return this.saveToken(token);
});
}
try to check it what is returned from server

call a web service , by an action button with angular , from nodeJS server ,

want to call a rest API from a nodeJS server with a click of a button in my project angular to add a user in the database, the api in the server is connected to my mysql database , just i wonna invoke the api rest of add ou update ou delete from the button in my project angular . I am new to this I dont know how to proceed.
thank you
import { Component } from '#angular/core';
import { LocalDataSource } from 'ng2-smart-table';
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { SmartTableData } from '../../../#core/data/smart-table';
//import { EmailValidator } from '#angular/forms';
#Injectable()
export class ConfigService {
constructor(private http: HttpClient) { }
}
#Component({
selector: 'ngx-smart-table',
templateUrl: './smart-table.component.html',
styles: [`
nb-card {
transform: translate3d(0, 0, 0);
}
`],
})
#Injectable()
export class Configuration {
public server = 'http://localhost:3000/';
public apiUrl = 'api/';
public serverWithApiUrl = this.server + this.apiUrl;
}
export class SmartTableComponent {
settings = {
add: {
addButtonContent: '<i class="nb-plus"></i>',
createButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
actionButonContent:'<i (click)="makeServiceCall($event)"><i/>',
},
edit: {
editButtonContent: '<i class="nb-edit"></i>',
saveButtonContent: '<i class="nb-checkmark"></i>',
cancelButtonContent: '<i class="nb-close"></i>',
actionButonContent:'<i (click)="onEditConfirm($event)"></i>'
},
delete: {
deleteButtonContent: '<i class="nb-trash"></i>',
confirmDelete: true,
actionButonContent:'<i (click)="onDeleteConfirm($event)"></i>'
},
columns: {
id: {
title: 'ID',
type: 'number',
},
firstName: {
title: ' Name',
type: 'string',
},
email: {
title: 'E-mail',
type: 'string',
},
password: {
title: 'password',
type: 'password',
},
},
};
source: LocalDataSource = new LocalDataSource();
constructor(private service: SmartTableData) {
const data = this.service.getData();
this.source.load(data);
}
onDeleteConfirm(event): void {
if (window.confirm('Are you sure you want to delete?')) {
event.confirm.resolve();
} else {
event.confirm.reject();
}
}
}
and this is my app.js (server)
var express = require('express');
var router = express.Router();
var user=require('../model/user');
router.get('/:id?',function(req,res,next){
if(req.params.id){
user.getUserById(req.params.id,function(err,rows){
if(err)
{
res.json(err);
}
else{
res.json(rows);
}
});
}
else{
user.getAllUsers(function(err,rows){
if(err)
{
res.json(err);
}
else
{
res.json(rows);
}
});
}
});
router.post('/',function(req,res,next){
user.addUser(req.body,function(err,count){
if(err)
{
res.json(err);
}
else{
res.json(req.body);
}
});
});
router.delete('/:id',function(req,res,next){
user.deleteUser(req.params.id,function(err,count){
if(err)
{
res.json(err);
}
else
{
res.json(count);
}
});
});
router.put('/:id',function(req,res,next){
user.updateUser(req.params.id,req.body,function(err,rows){
if(err)
{
res.json(err);
}
else
{
res.json(rows);
}
});
});
module.exports=router;
To make a call you need to add the HttpClientModule in your app.module.ts as import.
Then inject the Http client it wherever you want to use it:
constructor(private http: HttpClient){}
to use it just do:
this.http.get(<<url>>) //for get request
this.http.post(<<url>>,obj) //for post request
this returns an observable from which you can map the results and catch errors using Rxjs operators. for eg
addUser(user){ //called on button click
this.http.post(yourUrl,Json.Stringify(user)).pipe(
map((res)=>{
//do something with response
return 'sucess'
}),
catchError(err => {
//handleError
}
).subscribe(); // dont forget to subscribe
}
if you want to learn more : https://angular.io/guide/http
and for rxjs: https://www.learnrxjs.io/
Assume that the data that needs to be sent to the server is being passed to the function as the "data" parameter. Add "HttpClientModule" to the main app module or to your custom module if any as follows. Custom service has been imported in the app module or import it in your module accordingly.
app.module.ts
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { HttpClientModule } from '#angular/common/http';
import { CustomService } from 'location-of-custom-service';
#NgModule({
imports: [
CommonModule,
FormsModule,
HttpClientModule
],
declarations: [],
providers: [CustomService]
})
export class AppModule { }
Create a service file as follows.
custom.service.ts
import { Injectable } from '#angular/core';
import { Router } from '#angular/router';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
#Injectable({
providedIn: 'root'
})
export class CustomService {
public server = 'http://localhost:3000/';
public apiUrl = 'api/';
public serverWithApiUrl = this.server + this.apiUrl;
private fetchDataURL = this.serverWithApiUrl + 'fetchSomeData';
private addDataURL = this.serverWithApiUrl + 'addSomeData'
constructor(private _http: HttpClient) { }
// Fetch data
fetchData(id): Observable<any> {
this.fetchDataURL = this.fetchDataURL + "/" + id;
return this._http.get<any>(this.fetchDataURL, httpOptions)
.pipe(
retry(1),
catchError(this.handleError)
);
}
// Add data
addData(data): Observable<any> {
return this._http.post<any>(this.addDataURL, data, httpOptions);
}
// Error handler - you can customize this accordingly
handleError(error) {
let errorMessage = '';
if (error.error instanceof ErrorEvent) {
// client-side error
errorMessage = `Error: ${error.error.message}`;
} else {
// server-side error
errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
return throwError(errorMessage);
}
}
Your existing component has been modified so as to have the new additions as follows.
smarttable.component.ts
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { FormControl, FormGroup, Validators } from '#angular/forms';
import { CustomService } from './custom-service-location';
#Component({
selector: 'ngx-smart-table',
templateUrl: './smart-table.component.html'
})
export class SmartTableComponent implements OnInit {
constructor(private customService: CustomService) {}
fechedData: any;
// you existing codes goes here
// Add data - assume the data that needs to be sent to the server is as "data"
makeServiceCall(data) {
this.customService.addData(data)
.subscribe((data) => {
console.log(data);
// your logic after data addition goes here
},
(error) => {
// logic to handle error accordingly
});
}
// Fetch data
getData(id) {
this.customService.fetchData(id)
.subscribe((data) => {
console.log(data);
this.fechedData = data;
// your logic after data fetch goes here
},
(error) => {
// logic to handle error accordingly
});
}
}
I hope the above helps.

How to implement a profile?

I have a token based authorization. Authorization happens well there are no errors. But now need to somehow display the data of an authorized user. Please tell me how to properly implement the profile on the client (Angular 6)?
I have this server:
controller:
const db = require('../config/db.config.js')
const User = db.user
const errorHandler = require('../utils/errorHandler')
module.exports.getProfile = async function(req, res) {
try {
await User.findOne({ id: req.user.id}, (user) => {
res.json({
success: true,
user: user,
message: "Successful"
})
})
}catch(e) {
errorHandler(req, e)
}
}
routes:
const express = require('express')
const router = express.Router()
const controller = require('../controllers/user')
const passport = require('passport')
router.get('/profile', passport.authenticate('jwt', {session: false}), controller.getProfile)
module.exports = router
passport:
const JwtStrategy = require('passport-jwt').Strategy
const ExtractJwt = require('passport-jwt').ExtractJwt
const db = require('../config/db.config.js')
const User = db.user
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.SECRET_OR_KEY
}
module.exports = passport => {
passport.use(
new JwtStrategy(options, async (payload, done) => {
try {
const user = await User.findById(payload.userId).toJSON('username id')
if (user) {
done(null, user)
} else {
done(null, false)
}
} catch(e) {
console.log(e)
}
})
)
}
And here is a part of the client:
app-components:
import { Component, OnInit } from '#angular/core';
import { AuthService } from './shared/services/auth.service';
#Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>'
})
export class AppComponent implements OnInit {
constructor(private auth: AuthService) {
}
ngOnInit() {
const potentialToken = localStorage.getItem('auth-token')
if (potentialToken !== null) {
this.auth.setToken(potentialToken)
}
}
}
auth.service:
import { Injectable, Optional } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { Router, ActivatedRoute } from "#angular/router";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
import { User } from "../interfaces";
#Injectable({
providedIn: 'root'
})
export class AuthService {
private token = null;
constructor(
private http: HttpClient,
#Optional() private _activatedRoute: ActivatedRoute,
#Optional() private _router: Router
) {}
login(user: User): Observable<{token: string}> {
return this.http.post<{token: string}>('/api/auth/login', user)
.pipe(
tap(
({token}) => {
localStorage.setItem('auth-token', token)
this.setToken(token)
}
)
)
}
setToken(token: string) {
this.token = token
}
getToken(): string {
return this.token
}
isAuthenticated(): boolean {
return !!this.token
}
logout() {
this.setToken(null)
localStorage.clear()
}
}
token.interceptor.ts:
import { Injectable } from "#angular/core";
import { AuthService } from "../services/auth.service";
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from "#angular/common/http";
import { Observable, throwError } from "rxjs";
import { catchError } from "rxjs/operators";
import { Router } from "#angular/router";
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private auth: AuthService, private router: Router){
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.auth.isAuthenticated()) {
req = req.clone({
setHeaders: {
Authorization: this.auth.getToken()
}
})
}
return next.handle(req).pipe(
catchError(
(error: HttpErrorResponse) => this.handleAuthError(error)
)
)
}
private handleAuthError(error: HttpErrorResponse): Observable<any> {
if (error.status === 401) {
this.router.navigate(['/sign_in']), {
queryParams: {
sessionFailed: true
}
}
}
return throwError(error)
}
}
What need to implement on the client to display user data. Tell me please, I'm new.
You just need to create a Service class called UserService which will keep the information related to logged in user.
Whenever login action is performed successfully, just get the user details and fill it in UserService class.
user.service.ts
export class UserService {
private currentUser$: new BehaviorSubject<User>; //<-- check your user type
constructor(private http: Http) { }
getCurrentUser() {
this.currentUser$;
}
setCurrentUser(user:User){
this.currentUser$.next(user); //update the current user
}
}
This service class will give the Observable and you can use it any component or service class.

Resources