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