Related
I have been following https://github.com/goldbergyoni/nodebestpractices to learn more about nodejs best practices.
I have the following middleware that I implemented:
import { NextFunction, Request, Response } from "express";
import { BAD_REQUEST_ERROR_TYPES } from "../constants";
import { BadRequestError } from "./../error-handling";
const isAccountActive = (req: Request, res: Response, next: NextFunction) => {
if (req.session?.user?.isEmailVerified) {
next();
} else {
next(new BadRequestError(BAD_REQUEST_ERROR_TYPES.ACCOUNT_NOT_ACTIVE));
}
};
export default isAccountActive;
This is the test that I wrote for it:
describe("isAccountActive Middleware", () => {
describe("Recieving a request", () => {
test("When the request has a userUUID set in the session, it calls the next function without throwing a Bad Request Account Not Active error", async () => {
// Arrange
const req = {
method: "GET",
url: "/user/42",
session: {
user: {
userUUID: "some-string",
},
},
} as unknown as Request;
const res = jest.fn as unknown as Response;
const next = jest.fn;
// Act
await isAccountActive(req, res, next);
// Assert
expect(next).toBeCalledTimes(1);
expect(next).toBeCalledWith(
new BadRequestError(BAD_REQUEST_ERROR_TYPES.ACCOUNT_NOT_ACTIVE)
);
});
});
});
That is implementation number 3 for that test. I also tried using sinon, and node-mocks-http.
When I run the test command, I get the following error regardless of any implementation:
My app builds and runs fine; so I am not quite sure why jest would be throwing this error when the actuall server code itself is being compiled and run without any issues.
For reference, my config.ts:
import { isFullRedisURL } from "./helpers";
import { z } from "zod";
import { REDIS_URL_ERROR } from "./constants";
import { StartupError } from "./error-handling";
const input = {
environment: process.env.NODE_ENV,
basePort: process.env.BASE_PORT,
redisUrl: process.env.REDIS_URL,
redisPassword: process.env.REDIS_PASSWORD,
databaseUrl: process.env.DATABASE_URL,
sessionSecret: process.env.SESSION_SECRET,
};
const configSchema = z.object({
environment: z.string(),
basePort: z.coerce.number().positive().int(),
redisUrl: z
.string()
.refine((val) => isFullRedisURL(val), { message: REDIS_URL_ERROR }),
redisPassword: z.string(),
databaseUrl: z.string(),
sessionSecret: z.string().min(8),
});
let parsedInput;
try {
parsedInput = configSchema.parse(input);
} catch (e) {
throw new StartupError("Config validation error", e);
}
export const config = parsedInput;
export type Config = z.infer<typeof configSchema>;
my error-handling/error-handling-middleware.ts
import { COMMON_ERRORS, STATUS_CODES } from "../constants";
import { NextFunction, Request, Response } from "express";
import errorHandler from "./errorHandler";
import { config } from "../config";
const errorHandlingMiddleware = async (
// eslint-disable-next-line #typescript-eslint/no-explicit-any
error: any,
req: Request,
res: Response,
next: NextFunction
) => {
if (error && typeof error === "object") {
if (error.isTrusted === undefined || error.isTrusted === null) {
error.isTrusted = true; // Error during a specific request is usually not fatal and should not lead to process exit
}
}
errorHandler.handleError(error);
const { environment } = config;
const result = {
status: error?.httpStatus || STATUS_CODES.InternalServerError,
name: error?.name || COMMON_ERRORS.InternalServerError,
message: error?.message || "Sorry, something went wrong.",
details: error?.details,
stacktrace: environment === "development" ? error?.stacktrace : undefined,
};
res
.status(error?.httpStatus || STATUS_CODES.InternalServerError)
.send(result);
};
export default errorHandlingMiddleware;
the StartupError class:
import { FieldError } from "__shared/types";
import {
COMMON_ERRORS,
BAD_REQUEST_ERROR_MESSAGES,
BAD_REQUEST_ERROR_TYPES,
STATUS_CODES,
} from "../constants";
export class ApplicationError extends Error {
constructor(
public name: string,
public message: string,
public httpStatus: STATUS_CODES = STATUS_CODES.InternalServerError,
public isTrusted: boolean = true,
public isOperational: boolean = true,
public details?: FieldError[],
public stacktrace?: unknown
) {
super(message); // 'Error' breaks prototype chain here
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
this.name = name;
this.httpStatus = httpStatus;
this.isOperational = isOperational;
this.isTrusted = isTrusted;
this.details = details;
this.stacktrace = stacktrace;
Error.captureStackTrace(this, this.constructor);
}
}
export class BadRequestError extends ApplicationError {
constructor(type: keyof typeof BAD_REQUEST_ERROR_TYPES) {
super(
COMMON_ERRORS.BadRequestError,
BAD_REQUEST_ERROR_MESSAGES[type],
STATUS_CODES.BadRequest,
true,
true
);
}
}
export class StartupError extends ApplicationError {
constructor(reason: string, error: unknown) {
super(
COMMON_ERRORS.StartupError,
`Start up failed: (${reason}) `,
STATUS_CODES.InternalServerError,
false,
true,
undefined,
error
);
}
}
My post request and list all request are working fine, but I have problem getting my delete request to work. I have tested in Postman, but still have error. I think my delete url is fine, I can console log and see the item id been selected and show at the end of the url when making the request, I don't know what 's wrong.
delete.component.ts
deleteItem(): void {
console.log(this.currentItem._id);
alert("You had redeemed free food "+this.currentItem.itemToDonate);
this.charityService.deleteItem(this.currentItem._id).subscribe(
() => console.log("All of this food item has been redeemed"),
(err) => console.log(err)
)
}
charity.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { identifierModuleUrl } from '#angular/compiler';
//import { DonateComponent } from '../donate/donate.component';
const AUTH_API = 'http://localhost:3000/api/auth/donate';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json'})
};
#Injectable({
providedIn: 'root'
})
//post new donates to the database, list all items on the beneficiary page
//update quantity after redeem, delete item if the quantity is 0
export class CharityService {
constructor(private http: HttpClient) { }
donate(itemToDonate: string, quantity: number): Observable<any> {
return this.http.post(AUTH_API, {
itemToDonate, quantity
}, httpOptions);
}
listItem(): Observable<any> {
return this.http.get(AUTH_API, {});
}
receive(id: string): Observable<any> {
return this.http.put(`${AUTH_API}/update/${id}`, httpOptions)
.pipe(
catchError((err, caught) => {
console.error(err);
throw err;
})
);
}
getItem(id: string): Observable<any> {
return this.http.get(`${AUTH_API}/${id}`);
}
deleteItem(id: string): Observable<any> {
return this.http.delete(`${AUTH_API}/${id}`)
}
}
route.js
const controller_donate = require("../controllers/donate.controller");
const controller_receive = require("../controllers/receive.controller");
const controller_list = require("../controllers/list.controller");
const controller_delete = require("../controllers/delete.controller");
module.exports = function(app) {
app.use(function(req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"x-access-token, Origin, Content-Type, Accept"
);
next();
});
app.post("/api/auth/donate", controller_donate.donate);
app.get("/api/auth/donate", controller_list.donations);
app.put("/api/auth/donate/update/:id", controller_receive.receive);
app.delete("/api/auth/donate/:id", controller_delete.delete);
};
delete.controller.js
const db = require("../models");
const Donate = db.donate;
const { donate } = require("../models");
exports.delete = (req, res) => {
const id = req.params.id;
donate.findByIdAndRemove(id)
.then(data => {
if (!data) {
res.status(404).send({ message: "Cannot delete item" });
} else {
res.status(200).send("This item is been redeemed");
}
})
}
I have the following Angular and Node JS as follows
Interceptor
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
import { AuthService } from "../Services/auth.service";
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService : AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
//console.log(this.authService.getAuthToken())
const authToken = this.authService.getAuthToken();
const authRequest = req.clone({
headers: req.headers.set("Authorization", authToken)
});
console.log("authRequest");
return next.handle(authRequest);
}
}
service
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { api_url } from '../Models/global-url.model';
import { LoginModel } from '../Models/login_details.model';
import { ResponseFromServer } from '../Models/response.model';
#Injectable({
providedIn: 'root'
})
export class AuthService {
private token : string;
//Password is asish for all users
constructor(private http: HttpClient) { }
checkUserLogin(loginDetails: LoginModel) {
console.log(loginDetails);
this.http.post<{response: any}>(api_url+"login/loginUser", loginDetails).subscribe((result: ResponseFromServer) => {
console.log(result.token);
this.token = result.token;
console.log(this.token);
});
}
getAuthToken() {
return this.token;
}
}
User Defined Middleware in Node JS :-
const jwt = require('jsonwebtoken');
const s_token = require('../tokens/auth-token');
//const authFunction = (req, res, next) => {
module.exports = (req, res, next) => {
console.log(req);
var message = '';
try {
const token = req.headers.authorization;
console.log(token);
jwt.verify(token, s_token);
next();
} catch (err) {
message = "Auth Failed";
console.log(err); //JsonWebTokenError: Error jwt must be provided => user is not logged in
res.status(401).json(message);
// res.json(message); //Check the error message that occurs in browser console, while using this without status
}
}
login.js in Node Router :-
router.post('/loginUser', async (req, res, next) => {
const loginDetails = req.body;
console.log(loginDetails);
var { userId, stored_password,userEmailId,token,status_code } = '';
var message = '';
var response = '';
//console.log(loginDetails);
query = `SELECT * FROM tbl_users WHERE (tum_email = $1 OR tum_mobile = $1)`;
params = [loginDetails.username];
// await db.query(query, params, (err, result) => {
// if(err) {
// console.log(err);
// response = 'f0';
// message = "Internal Server Error. Please reload the page and try again.";
// } else if(result.rows.length) {
// //console.log(result.rows.length);
// userId = result.rows[0].tum_email;
// password = result.rows[0].tum_password;
// response = 's1';
// message = "";
// } else {
// response = 'f1';
// message = "User with the given user id does not exist. Please register here";
// }
// });
try {
const result = await db.query(query, params);
if(result.rowCount == 0 ) {
response = 'f1';
message = "User with the given user id does not exist. Please register here";
} else {
userId = result.rows[0].tum_id;
userEmailId = result.rows[0].tum_id;
stored_password = result.rows[0].tum_password;
try {
if ((await argon2.verify(stored_password, loginDetails.password))) {
//password matches
response = 'success';
const session_data = {
userId: userId,
email: userEmailId
}
token = jwt.sign(session_data, s_token, {expiresIn:'1hr'});
//console.log(token);
} else {
response = 'f2';
message = "Entered password is wrong. Please enter the correct password, or reset it";
}
} catch (err) {
console.log(err);
response = 'f0';
message = "Internal Server Error. Please reload the page and try again, or contact an Administrator";
}
}
} catch (err) {
console.log(err);
response = 'f0';
message = "Internal Server Error. Please reload the page and try again, or contact an Administrator";
}
const json_object = {
token: token,
response: response,
message:message
}
if(token != '') {
status_code = 200;
} else {
status_code = 401;
}
res.status(status_code).json(json_object);
//console.log("response ="+response+" & message = "+ message);
});
login.component.ts
import { Component, OnInit } from '#angular/core';
import { NgForm } from '#angular/forms';
import { AuthData } from 'src/app/Models/auth_data.model';
import { LoginModel } from 'src/app/Models/login_details.model';
import { ResponseFromServer } from 'src/app/Models/response.model';
import { AuthService } from 'src/app/Services/auth.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
isSubmitted = false;
isValid = true;
isLoading = false;
response_from_server = new ResponseFromServer();
constructor(private authService: AuthService) {
}
ngOnInit(): void {
this.response_from_server.response = 's1';
}
loginUser(loginData: NgForm) {
this.isSubmitted = true;
if(loginData.invalid) {
this.isValid = false;
//console.log("Validation Errors");
return;
}
const loginDetails : LoginModel = {
username : loginData.value.username,
password: loginData.value.password
}
this.authService.checkUserLogin(loginDetails);
}
}
Whenever I try to login , the error TypeError: Cannot read properties of undefined (reading 'length') is thrown.
The data is not even sent to the server side. It is stuck before return next.handle(authRequest);.
I tried console.log() almost everywhere to see where I am getting the mistake, and to which part, the data movement is getting done. Looks like the email and password are not even going through, to the Node JS server. Using console.log(result.token) in login.service.ts does not have any value.
Where am I going wrong ?
The problem is most likely happening because your trying to add the Authorization header before the user is logged-in.
In that situation authToken is undefined and you are assigning it to the header anyways.
You could solve it just adding a guard in your intercept method to first check if you have an authToken before attaching it to the request.
intercept(req: HttpRequest<any>, next: HttpHandler) {
const authToken = this.authService.getAuthToken();
if(!authToken) { // <--- not logged-in skip adding the header
return next.handle(req);
}
const authRequest = req.clone({
headers: req.headers.set("Authorization", authToken)
});
return next.handle(authRequest);
}
Cheers
it's my first time making questions on stackoverflow :).
So I'm developing a test / learning application to learn how to use NestJS and Vue.
I am was currently trying to implement several server-side unit tests (using Jest). When trying to create a testingmodule from my UsersService I get the error below on running "npm test users.service.spec"
Nest can't resolve dependencies of the UsersService (?,
ConfigService). Please make sure that the argument at index [0] is
available in the _RootTestModule context.
at Injector.lookupComponentInExports (../node_modules/#nestjs/core/injector/injector.js:183:19)
I am not sure if I am incorrectly instantiating the test model, or misconceived the injection of config.service, the code itself works, but may be implemented incorrectly.
Does anyone have any ideas how to solve this problem?
Git link: https://github.com/Lindul/FuelTracker_NestJs_MySql_Vue.git
users.service.spec.ts
import { Test } from '#nestjs/testing';
import { UsersService } from './users.service';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { ConfigService } from '../shared/config/config.service';
describe('User Service Tests', () => {
let loginTeste: UserLoginRegRequestDto = {
login: 'LoginJestTeste',
password: 'PassJestTeste',
}
const userMock: UserDto = {
id: 1,
login: 'hugombsantos',
password: 'wefewkfnwekfnwekjnf',
isActive: true,
needChangePass: false,
userType: 0,
};
const dataFindAllMock: UserDto[] = [{
id: 1,
login: 'hugombsantos',
password: 'wefewkfnwekfnwekjnf',
isActive: true,
needChangePass: false,
userType: 0,
}, {
id: 2,
login: 'user2',
password: 'sdgsdgdsgsdgsgsdg',
isActive: true,
needChangePass: false,
userType: 0,
}];
let service: UsersService;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
ConfigService,
UsersService,
],
}).compile();
service = module.get<UsersService>(UsersService);
});
it('UsersService está defenido', () => {
expect(service).toBeDefined();
});
});
user.service.ts
import { Injectable, Inject, HttpException, HttpStatus } from '#nestjs/common';
import { Users } from '../models/users.schema';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { UserLoginResponseDto } from './dto/user-login-response.dto';
import { sign } from 'jsonwebtoken';
import { ConfigService } from '../shared/config/config.service';
import { JwtPayload } from './auth/jwt-payload.model';
import { ErroMessageDto } from '../shared/config/dto/erro-message.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import bcrypt = require('bcrypt-nodejs');
const SALT_FACTOR = 8;
#Injectable()
export class UsersService {
constructor(
#Inject('UsersRepository') private usersRepository: typeof Users,
private readonly configService: ConfigService,
) { }
/* istanbul ignore next */
async findAll(): Promise<UserDto[]> {
const users = await this.usersRepository.findAll<Users>();
return users.map(user => {
return new UserDto(user);
});
}
/* istanbul ignore next */
async findUser(id: number): Promise<Users> {
const user = await this.usersRepository.findOne<Users>({
where: { id },
});
return user;
}
/* istanbul ignore next */
async findUserformLogin(login: string): Promise<UserDto> {
return await this.usersRepository.findOne<Users>({
where: { login },
});
}
/* istanbul ignore next */
async findUserforLogin(id: number, login: string): Promise<Users> {
return await this.usersRepository.findOne<Users>({
where: { id, login },
});
}
/* istanbul ignore next */
async creatUserOnDb(createUser: UserLoginRegRequestDto): Promise<Users> {
try {
const user = new Users();
user.login = createUser.login;
user.password = await this.hashPass(createUser.password);
return await user.save();
} catch (err) {
if (err.original.code === 'ER_DUP_ENTRY') {
throw new HttpException(
new ErroMessageDto(
HttpStatus.CONFLICT,
`Login '${err.errors[0].value}' already exists`),
HttpStatus.CONFLICT,
);
}
throw new HttpException(
new ErroMessageDto(
HttpStatus.INTERNAL_SERVER_ERROR,
err),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
/* istanbul ignore next */
async updateUserOnDb(user: Users): Promise<Users> {
try {
return await user.save();
} catch (err) {
if (err.original.code === 'ER_DUP_ENTRY') {
throw new HttpException(
new ErroMessageDto(
HttpStatus.CONFLICT,
`Login '${err.errors[0].value}' already exists`),
HttpStatus.CONFLICT,
);
}
throw new HttpException(
new ErroMessageDto(
HttpStatus.INTERNAL_SERVER_ERROR,
err),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
/* istanbul ignore next */
async delete(id: number): Promise<UserDto> {
const user = await this.findUser(+id);
await user.destroy();
return new UserDto(user);
}
async login(
userLoginRequestDto: UserLoginRegRequestDto,
): Promise<UserLoginResponseDto> {
const login = userLoginRequestDto.login;
const password = userLoginRequestDto.password;
const user = await this.findUserformLogin(login);
if (!user) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.UNAUTHORIZED,
'Invalid login or password.'),
HttpStatus.UNAUTHORIZED,
);
}
const isMatch = await this.comparePass(password, user.password);
if (!isMatch) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.UNAUTHORIZED,
'Invalid login or password.'),
HttpStatus.UNAUTHORIZED,
);
}
const token = await this.signToken(user);
return new UserLoginResponseDto(token);
}
async create(createUser: UserLoginRegRequestDto): Promise<UserLoginResponseDto> {
const userData = await this.creatUserOnDb(createUser);
// when registering then log user in automatically by returning a token
const token = await this.signToken(userData);
return new UserLoginResponseDto(token);
}
async updateUser(id: number | string, updateUserDto: UpdateUserDto): Promise<UserLoginResponseDto> {
const user = await this.findUser(+id);
if (!user) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.NOT_FOUND,
'User not found.'),
HttpStatus.NOT_FOUND,
);
}
user.login = updateUserDto.login || user.login;
user.userType = updateUserDto.userType || user.userType;
user.needChangePass = false;
const isMatch = await this.comparePass(updateUserDto.password, user.password);
if (updateUserDto.password && !isMatch) {
user.password = await this.hashPass(updateUserDto.password);
} else {
user.password = user.password;
}
const userData = await this.updateUserOnDb(user);
const token = await this.signToken(userData);
return new UserLoginResponseDto(token);
}
async signToken(user: UserDto): Promise<string> {
const payload: JwtPayload = {
id: user.id,
login: user.login,
};
const token = sign(payload, this.configService.jwtConfig.jwtPrivateKey,
{
expiresIn: this.configService.jwtConfig.valideTime,
});
return token;
}
async hashPass(passToHash: string): Promise<string> {
const saltValue = await bcrypt.genSaltSync(SALT_FACTOR);
return await bcrypt.hashSync(passToHash, saltValue);
}
async comparePass(passToCheck: string, correntPass: string) {
return await bcrypt.compareSync(passToCheck, correntPass);
}
}
users.modules.ts
import { Module } from '#nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import {userProviders} from './users.providers';
import { DatabaseModule } from '../database/database.module';
import { JwtStrategy } from './auth/jwt-strategy';
import { ConfigService } from '../shared/config/config.service';
#Module({
imports: [DatabaseModule, ConfigService],
controllers: [UsersController],
providers: [UsersService,
...userProviders, JwtStrategy],
exports: [UsersService],
})
export class UsersModule {}
config.service.ts
import { Injectable } from '#nestjs/common';
import { JwtConfig } from './interfaces/jwt-config.interface';
import { config } from '../../../config/config.JwT';
import { config as dbConfigData } from '../../../config/config.db';
import { SequelizeOrmConfig } from './interfaces/sequelize-orm-config.interface';
#Injectable()
export class ConfigService {
get sequelizeOrmConfig(): SequelizeOrmConfig {
return dbConfigData.databaseOpt;
}
get jwtConfig(): JwtConfig {
return {
jwtPrivateKey: config.jwtPrivateKey,
valideTime: config.valideTime,
};
}
}
You need to provide some value for Nest to inject for your UserRepository. It looks like you are using the TypeORM #InjectRepository() decorator, so in your testing module you'll need to add something like this under your providers
{
provide: getRepositoryToken('UsersRepository'),
useValue: MyMockUserRepo,
}
So that Nest can know what value to inject for that string. MyMockUserRepo would be your mock repository functionality, so that you aren't making actual database calls to your backend
I have an app where you can create many events, and I have created an API with express and node JS. In the react-native projet, I use Axios to fetch with API. But I have this weird error in my terminal :
(node:59293) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): RangeError: Invalid status code: 0
(node:59293) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
When I try to create an event, and in my browser console I have this :
Error: Network Error
at createError (createError.js:15)
at XMLHttpRequest.handleError (xhr.js:87)
at XMLHttpRequest.dispatchEvent (event-target.js:172)
at XMLHttpRequest.setReadyState (XMLHttpRequest.js:542)
at XMLHttpRequest.__didCompleteResponse (XMLHttpRequest.js:378)
at XMLHttpRequest.js:482
at RCTDeviceEventEmitter.emit (EventEmitter.js:181)
at MessageQueue.__callFunction (MessageQueue.js:242)
at MessageQueue.js:108
at guard (MessageQueue.js:46)
I paste my code here, maybe I'm wrong somewhere,
BACK END PART
import Event from './model';
export const createEvent = async (req, res) => {
const { title, description } = req.body;
const newEvent = new Event({ title, description });
try {
return res.status(201).json({ event: await newEvent.save() });
} catch(e) {
return res.status(e.status).json({ error: true, message: 'Error with event' });
}
};
export const getAllEvents = async (req, res) => {
try {
return res.status(200).json({ events: await Event.find({} )});
} catch(e) {
return res.status(e.status).json({ error: true, message: 'Error with all events' });
}
};
FRONT-END PART
api.js
import axios from 'axios';
axios.defaults.baseURL = 'http://localhost:3000/api';
class EventApi {
constructor() {
this.path = '/events';
}
async fetchEvents() {
try {
const { data } = await axios.get(this.path);
return data.events;
} catch (e) {
console.log(e);
}
}
async createEventPost(args) {
// console.log('nous entrons dans le cadre de la création dun evenement');
try {
console.log('nous tryons');
const res = await axios.post(`${this.path}/new`, { ...args });
console.log(res);
console.log('hello world', args);
return res;
} catch (e) {
console.log(e);
console.log('lol');
}
}
}
export {
EventApi
};
CreateScreen.js
import React, { Component } from 'react';
import { View } from 'react-native';
import { connect } from 'react-redux';
import DateTimePicker from 'react-native-modal-datetime-picker';
import moment from 'moment';
import { Ionicons } from '#expo/vector-icons';
import { createEvent } from './actions';
import { LoadingScreen } from '../../common';
import Colors from '../../../constants/colors';
import styles from './styles/CreateScreen';
import CreateEventsForm from './components/CreateEventsForm';
#connect(
state => ({
event: state.createEvent
}),
{ createEvent }
)
export default class CreateScreen extends Component {
static navigationOptions = {
title: 'Créer un événement',
header: {
style: {
backgroundColor: Colors.whiteColor
},
titleStyle: {
color: Colors.redParty
}
},
tabBar: {
icon: ({ tintColor }) => (
<Ionicons name="ios-create" size={25} color={tintColor} />
)
}
}
state = {
isDateTimePickerVisible: false,
date: moment()
}
_showDateTimePicker = () => this.setState({ isDateTimePickerVisible: true })
_handleDateTimePicker = () => this.setState({ isDateTimePickerVisible: false })
_handleDatePicked = date => {
this.setState({ date });
this._handleDateTimePicker();
}
_checkTitle() {
const { date } = this.state;
if (date > moment()) {
return moment(date).format('MMMM Do YYYY, h:mm.ss a');
}
return 'Choisir une date';
}
_checkNotEmpty() {
const { date } = this.state;
if (date > moment()) {
return false;
}
return true;
}
_createEvent = async values => {
await this.props.createEvent(values);
this.props.navigation.goBack();
}
render() {
const { event } = this.props;
if (event.isLoading) {
return (
<View style={styles.root}>
<LoadingScreen />
</View>
);
} else if (event.error.on) {
return (
<View>
<Text>
{event.error.message}
</Text>
</View>
);
}
return (
<View style={styles.root}>
<CreateEventsForm
createEvent={this._createEvent}
showDateTimePicker={this._showDateTimePicker}
checkTitle={this._checkTitle()}
/>
<DateTimePicker
isVisible={this.state.isDateTimePickerVisible}
onConfirm={this._handleDatePicked}
onCancel={this._handleDateTimePicker}
mode="datetime"
/>
</View>
);
}
}
acion.js
import { EventApi } from '../../../constants/api';
import { fetchMyEvents } from '../home/actions';
const eventApi = new EventApi();
export const CREATE_EVENT = 'CREATE_EVENT';
export const CREATE_EVENT_SUCCESS = 'CREATE_EVENT_SUCCESS';
export const CREATE_EVENT_ERROR = 'CREATE_EVENT_ERROR';
export const createEvent = args => async dispatch => {
dispatch({ type: CREATE_EVENT });
try {
await eventApi.createEventPost(args);
dispatch({ type: CREATE_EVENT_SUCCESS });
} catch (e) {
return dispatch({ type: CREATE_EVENT_ERROR });
}
return await dispatch(fetchMyEvents());
};
reducer.js
import { CREATE_EVENT, CREATE_EVENT_ERROR, CREATE_EVENT_SUCCESS } from './actions';
const INITIAL_STATE = {
error: {
on: false,
message: null
},
isLoading: false
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case CREATE_EVENT:
return {
...INITIAL_STATE,
isLoading: true
};
case CREATE_EVENT_SUCCESS:
return {
...INITIAL_STATE,
isLoading: false
};
case CREATE_EVENT_ERROR:
return {
error: {
on: true,
message: 'Error happened'
},
isLoading: false
};
default:
return state;
}
};
Don't hesitate to ask if you need more code (for example the CreateEventsForm)
Thank you !
It looks like the original error is being swallowed. One solution I found for a similar problem seems to be to drop the version of react-native - https://github.com/mzabriskie/axios/issues/640, but a better approach would to be to discover the original error and then you should be able to address that - https://www.webkj.com/react-native/javascript-error-unhandled-promise-rejection-warning :