Commit 40b3d589 authored by Elena Tsoy's avatar Elena Tsoy

Merge branch 'front' into 'master'

Front

See merge request !22
parents 77c1b178 c67d62b1
...@@ -8,6 +8,7 @@ import Payments from "./containers/Payments/Payments"; ...@@ -8,6 +8,7 @@ import Payments from "./containers/Payments/Payments";
import "./App.css" import "./App.css"
import Register from "./containers/Register/Register"; import Register from "./containers/Register/Register";
import Login from "./containers/Login/Login"; import Login from "./containers/Login/Login";
import Registry from "./containers/Registry/Registry";
const App = () => { const App = () => {
const user = useSelector(state=>state.users.user); const user = useSelector(state=>state.users.user);
...@@ -17,7 +18,7 @@ const App = () => { ...@@ -17,7 +18,7 @@ const App = () => {
<main className="App__main"> <main className="App__main">
<Switch> <Switch>
<Route path="/" exact component={Payments} /> <Route path="/" exact component={Payments} />
{/*<Route path="/new-payment" component={AddPaymentForm} />*/} <Route path="/registry" exact component={Registry} />
<ProtectedRoute <ProtectedRoute
isAllowed={user} isAllowed={user}
redirectTo={"/login"} redirectTo={"/login"}
......
.container {
padding: 2rem 0rem;
}
h4 { h4 {
margin: 2rem 0rem 1rem; margin: 2rem 0rem 1rem;
} }
...@@ -13,10 +8,11 @@ th { ...@@ -13,10 +8,11 @@ th {
text-align: center; text-align: center;
} }
.table{ .table{
margin: 0 auto;
border-collapse: collapse; border-collapse: collapse;
font-size: 0.9em; font-size: 0.9em;
font-family: sans-serif; font-family: sans-serif;
max-width: 100%; max-width: 1000px;
min-width: 400px; min-width: 400px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15); box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
} }
......
import React, { useState } from "react"; import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { apiURL } from "../../config"; import { apiURL } from "../../config";
import { fetchApprove, fetchPaid } from "../../store/actions/paymentAction";
import Modal from "../UI/Modal/Modal"; import Modal from "../UI/Modal/Modal";
import './Account.css'; import './Account.css';
const Account = ({ payments }) => { const Account = ({ payments }) => {
const user = useSelector(state => state.users.user);
const dispatch = useDispatch();
const [approved, setApproved] = useState(false);
const [showModal, setShowModal] = useState({ const [showModal, setShowModal] = useState({
show: false, show: false,
src:"" src:""
}) });
const openModal = (src) => { const openModal = (src) => {
setShowModal({show: true,src}); setShowModal({show: true,src});
...@@ -16,35 +21,54 @@ const Account = ({ payments }) => { ...@@ -16,35 +21,54 @@ const Account = ({ payments }) => {
const closeModal = () => { const closeModal = () => {
setShowModal({show: false}) setShowModal({show: false})
} }
const approve = (id) => {
dispatch(fetchApprove(id));
setApproved(!approved);
};
const pay = (id) => {
dispatch(fetchPaid(id));
setApproved(!approved);
}
return ( return (
<> <>
<table className="table"> <table className="table">
<thead> <thead>
<tr> <tr>
<th>Назначение</th> <th>Назначение</th>
<th>Компания</th> <th>Контрагент</th>
<th>Дата платежа</th> <th>Дата платежа</th>
<th>Статус оплаты</th> <th>Статус оплаты</th>
<th>Контрагент</th> <th>Компания</th>
<th>Важность</th> <th>Важность</th>
<th>Сумма платежа</th> <th>Сумма платежа</th>
<th>Изображение</th> <th>Изображение</th>
<th>Подтверждение</th>
{user && user.role === 'director' && <th>Кнопка подтверждения</th>}
{user && user.role === 'accountant' && <th>Кнопка оплаты</th>}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{payments.map((payment,index) => ( {payments && payments.map((payment,index) => (
<tr key={index}> <tr key={index}>
<td>{payment.purpose}</td> <td>{payment.purpose}</td>
<td>{payment.contractor}</td> <td>{payment.contractor}</td>
<td>{payment.dateOfPayment}</td> <td>{payment.dateOfPayment}</td>
<td>{payment.paided ? "Оплачен" : "Не оплачен"}</td> <td>{payment.paided ? <span style={{color: 'green'}}>Оплачен</span> : <span style={{color: 'red'}}>Не оплачен</span>}</td>
<td>{payment.payer}</td> <td>{payment.payer}</td>
<td>{payment.priority}</td> <td>{payment.priority}</td>
<td>{payment.sum}</td> <td>{payment.sum}</td>
<td > <td >
<span onClick={()=>openModal(apiURL + "/uploads/" + payment.image)}>click me</span> <span onClick={()=>openModal(apiURL + "/uploads/" + payment.image)}>click me</span>
</td> </td>
<td>{payment.approved ? <span style={{color: 'green'}}>Подтвержден</span> : <span style={{color: 'red'}}>Не подтвержден</span>}</td>
{user && user.role === 'director' && <td>
{!payment.approved && <button onClick={() => approve(payment._id)}>Подтвердить</button>}
</td>}
{user && user.role === 'accountant' && payment.approved && <td>
{!payment.paided && <button onClick={() => pay(payment._id)}>Оплатить</button>}
</td>}
</tr> </tr>
))} ))}
</tbody> </tbody>
......
...@@ -12,6 +12,7 @@ const Header = ({ user }) => { ...@@ -12,6 +12,7 @@ const Header = ({ user }) => {
<img src={logo} alt="logo" /> <img src={logo} alt="logo" />
</NavLink> </NavLink>
<menu> <menu>
{user && (user.role === 'director' || user.role === 'accountant') && <NavLink className="Header__link" to='/registry'>Реестр на сегодня</NavLink>}
<NavLink to="/" className="Header__link"> <NavLink to="/" className="Header__link">
Платежи Платежи
</NavLink> </NavLink>
......
...@@ -9,4 +9,18 @@ ...@@ -9,4 +9,18 @@
margin: 5px; margin: 5px;
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
}
.FormElement:hover {
box-shadow: 5px 5px 5px #7a7878;
}
.FormElement__error_message {
padding: 10px;
color: red;
width: 100%;
}
.FormElement__error {
color: red;
border: 2px solid red;
box-shadow: 5px 5px 5px #e98a8a;
} }
\ No newline at end of file
...@@ -10,10 +10,12 @@ const FormElement = ({ ...@@ -10,10 +10,12 @@ const FormElement = ({
value, value,
onChange, onChange,
placeholder, placeholder,
error
}) => { }) => {
return ( return (
<>
<input <input
className="FormElement" className={error ? "FormElement FormElement__error" : "FormElement"}
autoComplete={name} autoComplete={name}
name={name} name={name}
type={type} type={type}
...@@ -24,6 +26,8 @@ const FormElement = ({ ...@@ -24,6 +26,8 @@ const FormElement = ({
value={value} value={value}
placeholder={placeholder} placeholder={placeholder}
/> />
<span className="FormElement__error_message" >{error}</span>
</>
); );
}; };
...@@ -35,6 +39,7 @@ FormElement.propTypes = { ...@@ -35,6 +39,7 @@ FormElement.propTypes = {
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
value: PropTypes.string, value: PropTypes.string,
placeholder: PropTypes.string, placeholder: PropTypes.string,
error: PropTypes.string,
}; };
export default FormElement; export default FormElement;
// export const apiURL = "http://localhost:8000"; export const apiURL = "http://localhost:8000";
export const apiURL = "http://104.248.198.29:8000/"; // export const apiURL = "http://104.248.198.29:8000/";
...@@ -30,3 +30,17 @@ ...@@ -30,3 +30,17 @@
font-weight: bold; font-weight: bold;
margin: 10px auto; margin: 10px auto;
} }
.Login__navlink {
text-decoration: none;
margin: 0 10px;
padding: 10px;
background: linear-gradient(64.35deg,#ff7488 9.2%,#ff077d 89.76%);
color: white;
border-radius: 10px
}
.flex-end {
display: flex;
justify-content: flex-end;
align-items: center;
margin: 10px;
}
\ No newline at end of file
import React, { useState } from 'react' import React, { useState } from 'react'
import { useDispatch } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import FormElement from '../../components/UI/Forms/FormElement' import FormElement from '../../components/UI/Forms/FormElement'
import icon from "../../assets/images/icon-close.png" import icon from "../../assets/images/icon-close.png"
import './Login.css' import './Login.css'
import { loginUser } from '../../store/actions/usersActions' import { loginUser } from '../../store/actions/usersActions'
import { push } from 'connected-react-router' import { push } from 'connected-react-router'
import { NavLink } from 'react-router-dom'
const Login = () => { const Login = () => {
const dispatch = useDispatch() const dispatch = useDispatch()
const [state, setstate] = useState({ const [state, setstate] = useState({
workEmail: '', workEmail: '',
surname: '',
name: '',
patronymic: '',
position: '',
telegramName: '',
phone: '',
password: '' password: ''
}) })
const error = useSelector(state => state.users.loginError)
const inputChangeHandler = e => { const inputChangeHandler = e => {
const { name, value } = e.target const { name, value } = e.target
setstate(prevState => { setstate(prevState => {
...@@ -39,6 +36,7 @@ const Login = () => { ...@@ -39,6 +36,7 @@ const Login = () => {
<img className="icon" src={icon} /> <img className="icon" src={icon} />
</div> </div>
</div> </div>
{error && <span className="FormElement__error_message" >{error.error}</span>}
<form className="Login__form" onSubmit={submitFormHandler} > <form className="Login__form" onSubmit={submitFormHandler} >
<FormElement <FormElement
placeholder="Рабочий email" placeholder="Рабочий email"
...@@ -60,6 +58,7 @@ const Login = () => { ...@@ -60,6 +58,7 @@ const Login = () => {
<div className="flex-center"> <div className="flex-center">
<button className="Login__btn" type="submit">Войти</button> <button className="Login__btn" type="submit">Войти</button>
</div> </div>
<div className='flex-end'>У вас еще нет аккаунта? <NavLink className='Login__navlink' to='/register'>Регистрация</NavLink></div>
</form> </form>
</div> </div>
) )
......
...@@ -45,6 +45,19 @@ ...@@ -45,6 +45,19 @@
outline: none; outline: none;
cursor: pointer; cursor: pointer;
} }
.Payments__filter-btn {
padding: 10px;
font-size: 15px;
font-weight: bold;
background: #ff067c;
border: none;
margin: 20px 0;
color: white;
border-radius: 10px;
box-shadow: 0 0 3px 2px;
outline: none;
cursor: pointer;
}
.Payments__btn:hover { .Payments__btn:hover {
background: #480866; background: #480866;
} }
......
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import Account from "../../components/Account/Account"; import Account from "../../components/Account/Account";
import { apiURL } from "../../config";
import { import {
fetchPayments, fetchPayments,
fetchSortedData, fetchSortedData,
...@@ -67,18 +66,26 @@ const Payments = () => { ...@@ -67,18 +66,26 @@ const Payments = () => {
}; };
return ( return (
<div style={{ maxWidth: "1000px", margin: "0 auto" }}> <div style={{ maxWidth: "1300px", margin: "0 auto" }}>
<div style={{ maxWidth: "50%", margin: "0 auto" }}> <div style={{display: 'flex', alignItems: 'center', maxWidth: "60%", margin: "0 auto" }}>
<input {/* <input
placeholder="payer" placeholder="payer"
className="FormElement"
onChange={(e) => inputChangeHandler(e)} onChange={(e) => inputChangeHandler(e)}
name="payer" name="payer"
/> /> */}
<select
name="payer"
value={state.payer}
onChange={e => inputChangeHandler(e)}
>
<option disabled value="Выберите компанию-плательщика">Выберите компанию-плательщика</option>
<option value="Froot_Middle_Asia">Froot_Middle_Asia</option>
<option value="Froot_Бизнес">Froot_Бизнес</option>
</select>
<p>FROM</p> <p>FROM</p>
<input <input
className="FormElement"
type="date" type="date"
onChange={(e) => inputDateChangeHandler(e)} onChange={(e) => inputDateChangeHandler(e)}
name="fromDate" name="fromDate"
...@@ -86,12 +93,11 @@ const Payments = () => { ...@@ -86,12 +93,11 @@ const Payments = () => {
<p>TO</p> <p>TO</p>
<input <input
className="FormElement"
type="date" type="date"
onChange={(e) => inputDateChangeHandler(e)} onChange={(e) => inputDateChangeHandler(e)}
name="toDate" name="toDate"
/> />
<button className="Payments__btn" onClick={() => postData()}>Apply filter</button> <button className="Payments__filter-btn" onClick={() => postData()}>Apply filter</button>
</div> </div>
<Account payments={payments}/> <Account payments={payments}/>
</div> </div>
......
...@@ -30,6 +30,20 @@ ...@@ -30,6 +30,20 @@
font-weight: bold; font-weight: bold;
margin: 10px auto; margin: 10px auto;
} }
.Register__navlink {
text-decoration: none;
margin: 0 10px;
padding: 10px;
background: linear-gradient(64.35deg,#ff7488 9.2%,#ff077d 89.76%);
color: white;
border-radius: 10px
}
.flex-end {
display: flex;
justify-content: flex-end;
align-items: center;
margin: 10px;
}
.flex-center { .flex-center {
display: flex; display: flex;
justify-content: center; justify-content: center;
......
import React, { useState } from 'react' import React, { useState } from 'react'
import { useDispatch } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import FormElement from '../../components/UI/Forms/FormElement' import FormElement from '../../components/UI/Forms/FormElement'
import icon from "../../assets/images/icon-close.png" import icon from "../../assets/images/icon-close.png"
import './Register.css' import './Register.css'
import { registerUser } from '../../store/actions/usersActions' import { registerUser } from '../../store/actions/usersActions'
import { push } from 'connected-react-router' import { push } from 'connected-react-router'
import { NavLink } from 'react-router-dom'
const Register = () => { const Register = () => {
const dispatch = useDispatch() const dispatch = useDispatch()
...@@ -18,6 +19,14 @@ const Register = () => { ...@@ -18,6 +19,14 @@ const Register = () => {
phone: '', phone: '',
password: '' password: ''
}) })
const error = useSelector(state => state.users.registerError)
const getError = fieldName => {
try{
return error.errors[fieldName].message
}catch(e){
return undefined
}
}
const inputChangeHandler = e => { const inputChangeHandler = e => {
const { name, value } = e.target const { name, value } = e.target
setstate(prevState => { setstate(prevState => {
...@@ -47,6 +56,7 @@ const Register = () => { ...@@ -47,6 +56,7 @@ const Register = () => {
name="workEmail" name="workEmail"
value={state.workEmail} value={state.workEmail}
required required
error={getError('workEmail')}
/> />
<FormElement <FormElement
placeholder="Фамилия" placeholder="Фамилия"
...@@ -55,6 +65,7 @@ const Register = () => { ...@@ -55,6 +65,7 @@ const Register = () => {
name="surname" name="surname"
value={state.surname} value={state.surname}
required required
error={getError('surname')}
/> />
<FormElement <FormElement
placeholder="Имя" placeholder="Имя"
...@@ -63,6 +74,7 @@ const Register = () => { ...@@ -63,6 +74,7 @@ const Register = () => {
name="name" name="name"
value={state.name} value={state.name}
required required
error={getError('name')}
/> />
<FormElement <FormElement
placeholder="Отчество" placeholder="Отчество"
...@@ -71,6 +83,7 @@ const Register = () => { ...@@ -71,6 +83,7 @@ const Register = () => {
name="patronymic" name="patronymic"
value={state.patronymic} value={state.patronymic}
required required
error={getError('patronymic')}
/> />
<FormElement <FormElement
placeholder="Должность" placeholder="Должность"
...@@ -79,6 +92,7 @@ const Register = () => { ...@@ -79,6 +92,7 @@ const Register = () => {
name="position" name="position"
value={state.position} value={state.position}
required required
error={getError('position')}
/> />
{/* <FormElement {/* <FormElement
placeholder="Имя в телеграм" placeholder="Имя в телеграм"
...@@ -95,6 +109,7 @@ const Register = () => { ...@@ -95,6 +109,7 @@ const Register = () => {
name="phone" name="phone"
value={state.phone} value={state.phone}
required required
error={getError('phone')}
/> />
<FormElement <FormElement
placeholder="Пароль" placeholder="Пароль"
...@@ -103,10 +118,12 @@ const Register = () => { ...@@ -103,10 +118,12 @@ const Register = () => {
name="password" name="password"
value={state.password} value={state.password}
required required
error={getError('password')}
/> />
<div className="flex-center"> <div className="flex-center">
<button className="Register__btn" type="submit">Зарегистрировать</button> <button className="Register__btn" type="submit">Зарегистрировать</button>
</div> </div>
<div className='flex-end'>У вас уже имеется акканут для входа? <NavLink className='Register__navlink' to='/login'>Войти</NavLink></div>
</form> </form>
</div> </div>
) )
......
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Account from '../../components/Account/Account';
import { fetchTodaysPayments } from '../../store/actions/paymentAction';
const Registry = () => {
const todaysPayments = useSelector(state => state.payments.todaysPayments);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchTodaysPayments())
},[dispatch]);
return (
<Account payments={todaysPayments}/>
)
};
export default Registry;
\ No newline at end of file
...@@ -3,6 +3,8 @@ import axiosApi from "../../axiosApi"; ...@@ -3,6 +3,8 @@ import axiosApi from "../../axiosApi";
export const FETCH_PAYMENTS_SUCCESS = "FETCH_PAYMENTS_SUCCESS"; export const FETCH_PAYMENTS_SUCCESS = "FETCH_PAYMENTS_SUCCESS";
export const CREATE_PAYMENT_SUCCESS = "CREATE_PAYMENT_SUCCESS"; export const CREATE_PAYMENT_SUCCESS = "CREATE_PAYMENT_SUCCESS";
export const FETCH_TODAYS_PAYMENTS_SUCCESS = "FETCH_TODAYS_PAYMENTS_SUCCESS";
export const FETCH_STATUS_SUCCESS = "FETCH_STATUS_SUCCESS";
export const fetchPaymentsSuccess = (payments) => { export const fetchPaymentsSuccess = (payments) => {
return { type: FETCH_PAYMENTS_SUCCESS, payments }; return { type: FETCH_PAYMENTS_SUCCESS, payments };
...@@ -10,7 +12,43 @@ export const fetchPaymentsSuccess = (payments) => { ...@@ -10,7 +12,43 @@ export const fetchPaymentsSuccess = (payments) => {
export const createPaymentSuccess = (payment) => { export const createPaymentSuccess = (payment) => {
return { type: FETCH_PAYMENTS_SUCCESS, payment }; return { type: FETCH_PAYMENTS_SUCCESS, payment };
}; };
export const fetchTodaysPaymentsSuccess = payments => {
return {type: FETCH_TODAYS_PAYMENTS_SUCCESS, payments};
};
export const fetchStatusSuccess = (payment)=>{
return {type:FETCH_STATUS_SUCCESS,payment}
};
export const fetchPaid = id => {
return async dispatch => {
try {
const response = await axiosApi.post('/payments/'+id+'/paid');
dispatch(fetchStatusSuccess(response.data));
} catch(e) {
console.error(e);
}
}
}
export const fetchApprove = id => {
return async dispatch => {
try {
const response = await axiosApi.post('/payments/'+id+'/approved');
dispatch(fetchStatusSuccess(response.data));
} catch(e) {
console.error(e);
}
}
}
export const fetchTodaysPayments = () => {
return async dispatch => {
try {
const response = await axiosApi.get("/payments/today");
dispatch(fetchTodaysPaymentsSuccess(response.data));
} catch(e) {
console.error(e);
}
}
};
export const fetchSortedData = (data) => { export const fetchSortedData = (data) => {
return async (dispatch) => { return async (dispatch) => {
try { try {
......
const { FETCH_PAYMENTS_SUCCESS } = require("../actions/paymentAction"); const { FETCH_PAYMENTS_SUCCESS, FETCH_TODAYS_PAYMENTS_SUCCESS, FETCH_STATUS_SUCCESS } = require("../actions/paymentAction");
const initialState = { const initialState = {
payments: [], payments: [],
todaysPayments: []
}; };
const paymentReducer = (state = initialState, action) => { const paymentReducer = (state = initialState, action) => {
switch (action.type) { switch (action.type) {
case FETCH_PAYMENTS_SUCCESS: case FETCH_PAYMENTS_SUCCESS:
return { ...state, payments: action.payments }; return { ...state, payments: action.payments };
case FETCH_TODAYS_PAYMENTS_SUCCESS:
return {...state, todaysPayments: action.payments};
case FETCH_STATUS_SUCCESS:
return {...state,todaysPayments:
[... state.todaysPayments.map(element => {
if(element._id === action.payment._id) {
return action.payment
}
else return element
})], payments:
[...state.payments.map(element => {
if(element._id === action.payment._id) {
return action.payment
}
else return element
})]}
default: default:
return { ...state }; return { ...state };
} }
......
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