I'm recieiving the error below while tring to run my react redux app.
It cannot find the basket api.
I can add more files if needed but I'll add the ones that I think are sufficient for this question.
I also am recieving "A no default engine was specified" when trying to navigate to my /basket page. I will inslude this too.
When I run the app>>
GET http://www.localhost:3000/api/basket 404 (Not Found)
dispatchXhrRequest @ bundle.js:17637
xhrAdapter @ bundle.js:17471
dispatchRequest @ bundle.js:40197
Promise resolved (async)
request @ bundle.js:39674
Axios.(anonymous function) @ bundle.js:39684
wrap @ bundle.js:17450
(anonymous) @ bundle.js:11273
(anonymous) @ bundle.js:36221
(anonymous) @ bundle.js:35887
componentDidMount @ bundle.js:21837
(anonymous) @ bundle.js:30139
measureLifeCyclePerf @ bundle.js:29949
(anonymous) @ bundle.js:30138
notifyAll @ bundle.js:13509
close @ bundle.js:32099
closeAll @ bundle.js:6749
perform @ bundle.js:6696
batchedMountComponentIntoNode @ bundle.js:15237
perform @ bundle.js:6683
batchedUpdates @ bundle.js:31765
batchedUpdates @ bundle.js:2529
_renderNewRootComponent @ bundle.js:15431
_renderSubtreeIntoContainer @ bundle.js:15512
render @ bundle.js:15533
(anonymous) @ bundle.js:22170
__webpack_require__ @ bundle.js:20
module.exports @ bundle.js:63
(anonymous) @ bundle.js:66
bundle.js:36239 action GET_BASKET_DECLINED @ 13:21:53.185
When I try to access my /basket
Error: No default engine was specified and no extension was provided.
at new View (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\view.js:61:11)
at EventEmitter.render (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\application.js:570:12)
at ServerResponse.render (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\response.js:971:7)
at C:\Users\Cmac\Documents\prj400r\dealstore\app.js:88:7
at Layer.handle_error (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\layer.js:71:5)
at trim_prefix (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\index.js:315:13)
at C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\index.js:275:10)
at C:\Users\Cmac\Documents\prj400r\dealstore\app.js:77:3
at Layer.handle [as handle_request] (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\index.js:317:13)
at C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\express\lib\router\index.js:275:10)
at SendStream.error (C:\Users\Cmac\Documents\prj400r\dealstore\node_modules\serve-static\index.js:121:7)
My basket.js file
"use strict"
// NECCESSARY IMPORTS
import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
// OTHER COMPONENTS IMPORTS
import {deleteBasketItem, updateBasket, getBasket} from '../../actions/basketActions';
// STYLING IMPORTS
import {Panel, Col, Row, Well, Button, ButtonGroup, Label, Modal} from 'react-bootstrap';
class Basket extends React.Component{
componentDidMount(){
this.props.getBasket();
}
// DELETE
onDel(_id){
const currentDealToDelete = this.props.basket;
const indexToDelete = currentDealToDelete.findIndex(function(basket){return basket._id === _id;})
let basketAfterDel = [...currentDealToDelete.slice(0, indexToDelete), ...currentDealToDelete.slice(indexToDelete + 1)]
this.props.deleteBasketItem(basketAfterDel);
}
// ON INCREMENTING
onIn(_id){
this.props.updateBasket(_id, 1, this.props.basket);
}
// ON DECREMENTING
onDec(_id, quantity){
if(quantity > 1){
this.props.updateBasket(_id, -1, this.props.basket);
}
}
render(){
if(this.props.basket[0]){
return this.renderBasket();
} else {
return this.renderBasketEmpty();
}
}
// SUPER PROPS
constructor(){
super();
this.state = {
// Modal closed in state initially
showModal:false
}
}
// OPEN MODAL
open(){
this.setState({showModal:true})
}
// CLOSE MODAL
close(){
this.setState({showModal:false})
}
// BLANK BASKET
renderBasketEmpty(){
return(
<div></div>
)
}
// DISPLAY DEALS/ITEMS IN THE BASKET COMPONENT
renderBasket(){
const basketItemsList = this.props.basket.map(function(basketArr){
return(
<Panel key={basketArr._id}>
<Row>
<Col xs={12} md={12}>
<h2>{basketArr.title}</h2>
</Col>
<Col xs={12} md={2}>
<h4>€{basketArr.price}</h4>
</Col>
<Col xs={12} md={2}>
<h4>Quantity: <Label bsStyle="info">{basketArr.quantity}</Label></h4>
</Col>
<Col xs={6} md={8}>
<ButtonGroup style={{minWidth: '250px'}}>
<Button onClick={this.onDec.bind(this, basketArr._id, basketArr.quantity)} bsStyle="default" bsSize="small">-</Button>
<Button onClick={this.onIn.bind(this, basketArr._id)} bsStyle="default" bsSize="small">+</Button>
<Button onClick={this.onDel.bind(this, basketArr._id)} bsStyle="danger" bsSize="small">Remove</Button>
</ButtonGroup>
</Col>
</Row>
</Panel>
)
}, this)
return(
<Panel header="Basket" bsStyle="info" >
{basketItemsList}
<Row>
<Col xs={12} md={12}>
<h4>Total: {this.props.ttlAmount} </h4>
<Button onClick={this.open.bind(this)} bsStyle="success" bsSize="small">
Checkout
</Button>
</Col>
</Row>
<Modal show={this.state.showModal} onHide={this.close.bind(this)}>
<Modal.Header closeButton>
<Modal.Title>Deal Store</Modal.Title>
</Modal.Header>
<Modal.Body>
<h2>SUCCESS!</h2>
<p>Order is ready!</p>
</Modal.Body>
<Modal.Footer>
<Col xs={4} md={4}>
<h2>Total is € {this.props.ttlAmount}</h2>
</Col>
<Button onClick={this.close.bind(this)}>Close</Button>
</Modal.Footer>
</Modal>
</Panel>
)
}
}
function mapStateToProps(state){
return{
basket: state.basket.basket,
ttlAmount: state.basket.ttlAmount
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({
deleteBasketItem:deleteBasketItem,
updateBasket:updateBasket,
getBasket:getBasket
}, dispatch)
}
// MAKE CONNECTION == connect
export default connect(mapStateToProps, mapDispatchToProps)(Basket);
DealItem.js
"use strict"
import React from 'react';
import {Row, Well, Col, Button } from 'react-bootstrap';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {addBasket, updateBasket} from '../../actions/basketActions';
class DealItem extends React.Component{
handleBasket(){
const deal = [...this.props.basket, {
_id: this.props._id,
title: this.props.title,
description: this.props.description,
price: this.props.price,
quantity: 1
}]
// CHECK IF ITEM IN BASKET
// IF EMPTY
// DISPLAY ERROR MESSAGE
if(this.props.basket.length > 0){
let _id = this.props._id;
let basketIndex = this.props.basket.findIndex(function(basket){
return basket._id === _id;
})
// == -1 ADD TO BASKET
if (basketIndex === -1){
this.props.addBasket(deal);
} else {
// THEN UPDATE BASKET
this.props.updateBasket(_id, 1, this.props.basket)
}
} else {
this.props.addBasket(deal);
}
}
// RENDER HTML
render(){
return(
<Well>
<Row>
<Col xs={12}>
<h2>{this.props.title}</h2>
<p>{this.props.description}</p>
<h4>€ {this.props.price}</h4>
<Button onClick={this.handleBasket.bind(this)}
bsStyle='primary'>Purchase</Button>
</Col>
</Row>
</Well>
)
}
}
function mapStateToProps(state){
return{
basket: state.basket.basket
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({
addBasket:addBasket,
updateBasket: updateBasket
}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(DealItem);
basketReducers.js
"use strict"
export function basketReducers(state={basket:[]}, action) {
switch (action.type) {
// ADD***********************
case "ADD_TO_BASKET":
return {...state, basket:action.payload,
ttlAmount: totals(action.payload).dealAmount,
totalQuantity: totals(action.payload).quantity}
break;
// UPDATE *****************
case "UPDATE_BASKET":
return {...state, basket:action.payload,
ttlAmount: totals(action.payload).dealAmount,
totalQuantity: totals(action.payload).quantity}
break;
// GET *******************
case "GET_BASKET":
return{...state, basket:action.payload, ttlAmount:totals(action.payload).dealAmount,
totalQuantity: totals(action.payload).quantity}
// DELETE ****************
case "DELETE_BASKET_ITEM":
return {...state, basket:action.payload,
ttlAmount: totals(action.payload).dealAmount,
totalQuantity: totals(action.payload).quantity}
break;
}
return state
}
// TOTALING
export function totals(payloadArr){
const ttlAmount = payloadArr.map(function(basketArr){
return basketArr.price * basketArr.quantity;
}).reduce(function(y, z) {
return y + z;
}, 0); //start from 0 and add onto
const totalQuantity = payloadArr.map(function(quantity){
return quantity.quantity;
}).reduce(function(y, z) {
return y + z;
}, 0);
return {dealAmount:ttlAmount.toFixed(2), quantity:totalQuantity}
}
apiServer.js
//IMPORT EXPRESS
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
// ROUTES
var index = require('./routes/index');
var users = require('./routes/users');
// COOKIES & SESSION
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
var app = express();
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// MONGOOSE FOR THE API FOR DEALS
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/dealshop');
// DEALS COLLECTION
var Deals = require('./collections/deals.js');
// START CONN
var db = mongoose.connection;
db.on('error', console.error.bind(console, '#########~~~~~~ ERROR'));
app.use(session({
secret: 'anonStr',
saveUninitialized: false,
resave: false,
cookie: {maxAge: 1000 * 60 * 60 * 24 * 2},
store: new MongoStore({mongooseConnection: db, ttl: 1 * 24 * 30 * 60})
// time to leave
}))
// SAVE BASKET
app.post('/basket', function(req, res){
var basket = req.body;
req.session.basket = basket;
req.session.save(function(err){
if(err){
throw err;
}
res.json(req.session.basket);
})
});
// GET THE BASKET
app.get('/basket', function(req, res){
if (typeof req.session.basket !== 'undefined') {
res.json(req.session.basket);
}
});
// END THE COOKIE SESSION
// POST DEALS
app.post('/deals', function(req, res){
var deal = req.body;
Deals.create(deal, function(err, deals){
if(err){
throw err;
}
res.json(deals);
})
});
// GET DEALS
app.get('/deals', function(req, res){
Deals.find(function(err, deals){
if(err){
throw err;
}
res.json(deals);
})
});
// DELETE DEALS
app.delete('/deals/:_id', function(req, res){
var query = {_id: req.params._id};
Deals.remove(query, function(err, deals){
if(err){
throw err;
}
res.json(deals);
})
});
// FINISH API SERVER
app.listen(3001, function(err){
if(err){
return console.log(err);
}
console.log('API running on 3001');
})
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
// app.set('views', path.join(__dirname, 'views'));
// app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// MONGOOSE FOR THE API FOR DEALS
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/dealshop');
// DEALS COLLECTION
var Deals = require('./collections/deals.js');
// POST DEALS
app.post('/deals', function(req, res){
var deal = req.body;
Deals.create(deal, function(err, deals){
if(err){
throw err;
}
res.json(deals);
})
});
// GET DEALS
app.get('/deals', function(req, res){
Deals.find(function(err, deals){
if(err){
throw err;
}
res.json(deals);
})
});
// DELETE DEALS
app.delete('/deals/:_id', function(req, res){
var query = {_id: req.params._id};
Deals.remove(query, function(err, deals){
if(err){
throw err;
}
res.json(deals);
})
});
// app.use('/', index);
// app.use('/users', users);
app.get('/', function(req, res) {
res.sendFile(path.resolve(__dirname, 'public', 'index.html'))
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
package.json
{
"name": "dealstore",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"devDependencies": {
"nodemon": "^1.11.0",
"redux-logger": "^3.0.6",
"webpack": "^3.5.5"
},
"dependencies": {
"axios": "^0.16.2",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-1": "^6.24.1",
"body-parser": "~1.17.1",
"cookie-parser": "~1.4.3",
"debug": "~2.6.3",
"express": "^4.15.4",
"jade": "~1.11.0",
"mongoose": "^4.11.8",
"morgan": "~1.8.1",
"react": "^15.4.1",
"react-bootstrap": "^0.31.2",
"react-dom": "^15.4.1",
"react-redux": "^5.0.5",
"react-router": "^3.0.4",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0",
"serve-favicon": "~2.4.2"
}
}
server.js
'use strict'
var express = require('express');
var app = express();
var path = require('path');
app.use(express.static('public'));
app.get('/', function(req, res){
res.sendFile(path.resolve(__dirname,'public', 'index.html'))
});
app.listen(3000, function(){console.log('App web-server listening onport 3000');
});