Commit df219edf authored by Tamás Danis's avatar Tamás Danis

save item

parent 6077bee6
<?php
namespace App\Http\Controllers;
use App\Product;
use Illuminate\Http\Request;
class ProductController extends Controller {
public function save( Request $request ) {
$payload = [
'name' => $request["description"],
'created_at' => $request["date"],
'price' => $request["price"]
];
$product = new Product( $payload );
$product->save();
return Product::all()->toArray();
}
public function get() {
return Product::all()->toArray();
}
}
......@@ -5,10 +5,17 @@ namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model {
protected $fillable = [
'name',
'price',
'created_at'
];
public function transactions() {
return $this->belongsToMany( 'App\Transaction' );
}
public function type(){
return $this->belongsTo('App\Type');
}
public function type() {
return $this->belongsTo( 'App\Type' );
}
}
......@@ -14,7 +14,8 @@ class CreateProductsTable extends Migration {
Schema::create( 'products', function ( Blueprint $table ) {
$table->bigIncrements( 'id' );
$table->string( 'name' );
$table->bigInteger( 'type_id' )->unsigned();
$table->float( 'price' );
$table->bigInteger( 'type_id' )->unsigned()->nullable();
$table->timestamps();
} );
......
......@@ -2,3 +2,8 @@ export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_ERROR = 'LOGIN_ERROR';
export const REGISTER_SUCCESS = 'REGISTER_SUCCESS';
export const REGISTER_ERROR = 'REGISTER_ERROR';
export const LOGOUT = 'LOGOUT';
export const LOGGED_OUT = 'LOGGED_OUT';
export const SAVE_TRANSACTION = 'SAVE_TRANSACTION';
export const FETCH_TRANSACTIONS = 'FETCH_TRANSACTIONS';
......@@ -26,3 +26,11 @@ export function register(registerData) {
dispatch({ type: types.REGISTER_ERROR, data: error });
});
}
export function logout() {
return dispatch => dispatch({ type: types.LOGOUT });
}
export function loggedOut() {
return dispatch => dispatch({ type: types.LOGGED_OUT });
}
import * as types from './actionTypes';
import API from '../api/API';
export function saveTransaction(data) {
return dispatch =>
API.saveTransaction(data)
.then(data => {
dispatch({ type: types.FETCH_TRANSACTIONS, transactions: data.data });
});
}
export function fetchTransactions() {
return dispatch =>
API.fetchTransactions()
.then(data => {
dispatch({ type: types.FETCH_TRANSACTIONS, transactions: data.data });
});
}
import axios from 'axios';
const token = localStorage.getItem('auth_token');
const loginUrl = 'http://localhost:8000/api/user/login';
const registerUrl = 'http://localhost:8000/api/user/register';
const saveTransactionUrl = `http://localhost:8000/api/product`;
const fetchTransactionUrl = `http://localhost:8000/api/products`;
class API {
static login(loginData) {
......@@ -29,6 +32,32 @@ class API {
});
});
}
static saveTransaction(data) {
return new Promise(resolve => {
axios
.post(saveTransactionUrl, JSON.stringify(data))
.then(response => {
resolve(response);
})
.catch(error => {
resolve(error);
});
});
}
static fetchTransactions() {
return new Promise(resolve => {
axios
.get(fetchTransactionUrl)
.then(response => {
resolve(response);
})
.catch(error => {
resolve(error);
});
});
}
}
export default API;
......@@ -3,12 +3,16 @@ import { Switch, Route } from 'react-router-dom';
import Dashboard from './layouts/Dashboard';
import Auth from './layouts/Auth';
const Main = () => (
<Switch>
<Route exact path="/login" component={Auth}/>
<Route exact path="/register" component={Auth}/>
<Route path="/" component={Dashboard}/>
</Switch>
);
const Main =() => {
return (
<Switch>
<Route exact path="/login" component={Auth}/>
<Route exact path="/register" component={Auth}/>
<Route exact path="/main" component={Dashboard}/>
<Route path="/" component={Dashboard}/>
</Switch>
);
};
export default Main;
import React from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';
import { NavLink, Link } from 'react-router-dom';
import { authNavItems, navItems } from '../../data/header';
import * as authActions from '../../actions/authActions';
const Header = props => {
const navLinks = props.auth.loggedIn ? navItems : authNavItems;
const Header = ({ auth, actions }) => {
const navLinks = auth.loggedIn ? navItems : authNavItems;
const handleClick = e => {
e.preventDefault();
actions.logout();
};
return (
<nav className="navbar navbar-expand-lg navbar-dark bg-dark static-top">
......@@ -18,9 +26,17 @@ const Header = props => {
</button>
<div className="collapse navbar-collapse" id="navbarResponsive">
<ul className="navbar-nav ml-auto">
{navLinks.map(item => <li className="nav-item" key={item.route}>
<NavLink exact to={item.route} className="nav-link">{item.title}</NavLink>
</li>)}
{navLinks.map(item => (
<li className="nav-item" key={item.route}>
<NavLink exact to={item.route} className="nav-link">{item.title}</NavLink>
</li>
))}
{auth.loggedIn
? <li className="nav-item">
<Link className="nav-link" to="/" onClick={handleClick}>Logout</Link>
</li>
: null}
</ul>
</div>
</nav>
......@@ -28,7 +44,8 @@ const Header = props => {
};
Header.propTypes = {
auth: PropTypes.object.isRequired
auth: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired
};
const mapStateToProps = state => {
......@@ -37,4 +54,10 @@ const mapStateToProps = state => {
};
};
export default connect(mapStateToProps)(Header);
const mapDispatchToProps = dispatch => {
return {
actions: bindActionCreators(authActions, dispatch)
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Header);
......@@ -21,7 +21,6 @@ const RegisterForm = props => {
const handleSubmit = e => {
e.preventDefault();
console.log(data)
actions.register(data);
};
......
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import { Field, formValueSelector, reduxForm } from 'redux-form';
import { bindActionCreators } from 'redux';
import moment from 'moment';
import InputField from '../../common/form/InputField';
import { required, numeric } from '../../../validation/validation';
import ButtonField from '../../common/form/ButtonField';
import * as transactionActions from '../../../actions/transactionActions';
const now = moment().format('YYYY-MM-DD');
const TransactionForm = ({ valid, actions, data }) => {
const TransactionForm = (props) => {
const { valid } = props;
const handleSubmit = e => {
e.preventDefault();
actions.saveTransaction(data);
};
return (
<form onSubmit={handleSubmit}>
<div className="row">
......@@ -29,9 +31,9 @@ const TransactionForm = (props) => {
<div className="col-md-5">
<Field
label="description"
label="Description"
type="text"
name="Description"
name="description"
component={InputField}
validate={[required]}
/>
......@@ -39,9 +41,9 @@ const TransactionForm = (props) => {
<div className="col-md-2">
<Field
label="price"
label="Price"
type="text"
name="Price"
name="price"
component={InputField}
validate={[required, numeric]}
/>
......@@ -56,13 +58,34 @@ const TransactionForm = (props) => {
};
TransactionForm.propTypes = {
valid: PropTypes.bool.isRequired
valid: PropTypes.bool.isRequired,
actions: PropTypes.object.isRequired,
data: PropTypes.object
};
TransactionForm.defaultProps = {
data: null
};
const mapStateToProps = () => ({
initialValues: { date: now }
const selector = formValueSelector('transactionForm');
const mapStateToProps = (state) => ({
initialValues: {
date: moment().format('YYYY-MM-DD')
},
data: {
date: selector(state, 'date'),
description: selector(state, 'description'),
price: selector(state, 'price')
}
});
export default connect(mapStateToProps)(reduxForm({
const mapDispatchToProps = dispatch => {
return {
actions: bindActionCreators(transactionActions, dispatch)
};
};
export default connect(mapStateToProps, mapDispatchToProps)(reduxForm({
form: 'transactionForm'
})(TransactionForm));
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import TransactionListItem from './TransactionListItem';
import * as transactionActions from '../../../actions/transactionActions';
class TransactionList extends Component {
//
// static propTypes = {
// actions: PropTypes.func.isRequired,
//
// transactions: PropTypes.array.isRequired
// };
componentDidMount() {
this.props.actions.fetchTransactions();
}
render() {
const { transactions } = this.props;
return (
<ul className="list-group">
{transactions.map(transaction => (
<TransactionListItem key={transaction.id} transaction={transaction}/>
))}
</ul>
);
};
}
const mapStateToProps = ({ transactions }) => ({
transactions
});
const mapDispatchToProps = dispatch => {
return {
actions: bindActionCreators(transactionActions, dispatch)
};
};
export default connect(mapStateToProps, mapDispatchToProps)(TransactionList);
import React from 'react';
import PropTypes from 'prop-types';
const TransactionListItem = ({ transaction }) => {
return (
<li className="list-group-item d-flex justify-content-between align-items-center">
{transaction.name}
<span className="badge badge-primary badge-pill">{transaction.price}&euro;</span>
</li>
);
};
TransactionListItem.propTypes = {
transaction: PropTypes.object.isRequired
};
export default TransactionListItem;
import React, { Component } from 'react';
import TransactionForm from './DashBoard/TransactionForm';
import TransactionList from './DashBoard/TransactionList';
class Dashboard extends Component {
render() {
......@@ -11,6 +12,7 @@ class Dashboard extends Component {
<div className="col-md-12">
<h1>Dashboard</h1>
<TransactionForm/>
<TransactionList/>
</div>
</div>
</div>
......
import * as types from '../actions/actionTypes';
import initialState from './initialState';
const login = (state = initialState.auth, action) => {
const auth = (state = initialState.auth, action) => {
switch (action.type) {
case types.LOGIN_SUCCESS:
// localStorage.setItem('user', action.user);
localStorage.setItem('auth_token', action.user.auth_token);
return {
...state,
...action.auth,
loggedIn: true
};
case types.LOGIN_ERROR:
return {
...state,
...action.auth,
loggedIn: false,
hasError: true,
......@@ -21,9 +23,20 @@ const login = (state = initialState.auth, action) => {
case types.REGISTER_ERROR:
window.location.replace('/login');
return state;
case types.LOGOUT:
return {
...state,
loggedIn: false,
redirect: true
};
case types.LOGGED_OUT:
return {
...state,
redirect: false
};
default:
return state;
}
};
export default login;
export default auth;
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
import auth from './authReducer';
import transaction from './transactionReducer'
const rootReducer = combineReducers({
auth,
form: formReducer
form: formReducer,
transactions:transaction
});
export default rootReducer;
export default {
auth: { loggedIn: true, hasError: false, error: {} },
form: {}
auth: {
loggedIn: false,
hasError: false,
error: {},
redirect: false
},
form: {},
transactions: []
};
import * as types from '../actions/actionTypes';
import initialState from './initialState';
const transaction = (state = initialState.transactions, action) => {
switch (action.type) {
case types.FETCH_TRANSACTIONS:
return action.transactions;
default:
return state;
}
};
export default transaction;
......@@ -26,6 +26,7 @@ Route::group( [ 'middleware' => [ 'jwt.auth', 'api-header' ] ], function () {
return response()->json( $response, 201 );
} );
} );
Route::group( [ 'middleware' => 'api-header' ], function () {
......@@ -34,4 +35,6 @@ Route::group( [ 'middleware' => 'api-header' ], function () {
// Therefore the jwtMiddleware will be exclusive of them
Route::post( 'user/login', 'UserController@login' );
Route::post( 'user/register', 'UserController@register' );
Route::post( 'product', 'ProductController@save' );
Route::get( 'products', 'ProductController@get' );
} );
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment