diff --git a/src/components/App.js b/src/components/App.js index 2d0d023..4f9eecf 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; -import firebase from "firebase/app"; -import "firebase/auth"; +import firebase from 'firebase/app'; +import 'firebase/auth'; import axios from 'axios'; import { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom'; @@ -13,132 +13,197 @@ import Modules from './modules/Modules'; import styled from 'styled-components'; import ProcessProtocols from './process_protocols/ProcessProtocols'; -import { apiKey, authDomain, databaseURL, projectId } from "../../config/keys"; +import { apiKey, authDomain, databaseURL, projectId } from '../../config/keys'; const AppStyle = styled.div` - font-family: Montserrat, sans-serif; + font-family: Montserrat, sans-serif; `; export const AuthContext = React.createContext(); -export default props => { - - const [state, setState] = useState({user: null, loading: true, token: '', parties: [], countries: [], organizations: []}); - - useEffect(() => { - firebase.initializeApp({ apiKey, authDomain, databaseURL, projectId }); - - firebase.app().auth().onAuthStateChanged(async user => { - if (user) { - const idToken = await user.getIdToken(); - - setState({...state, loading: true}); - const res = await axios.get(`${apiHost()}/me`, { - headers: { 'Authorization': `Bearer ${idToken}` } - }); - - const res2 = await axios.get(`${apiHost()}/parties`, { - headers: { 'Authorization': `Bearer ${idToken}` } - }); - - const res3 = await axios.get(`${apiHost()}/countries`, { - headers: { 'Authorization': `Bearer ${idToken}` } - }); - - const res4 = await axios.get(`${apiHost()}/organizations`, { - headers: { 'Authorization': `Bearer ${idToken}` } - }) - - - setState({user: res.data, loading: false, token: idToken, parties: res2.data, countries: res3.data, organizations: res4.data}); - } else { - setState({user: null, loading: false, token: '', parties: [], countries: [], organizations: []}); - } - }); - }, []); - - const logIn = ({ email, password }) => { - return firebase.auth().signInWithEmailAndPassword(email, password); - }; - - const logOut = () => { - firebase.app().auth().signOut(); - }; - - const apiHost = () => { - if(!process.env.API_HOST) { - return 'https://d1tapi.dabulgaria.bg'; +export default (props) => { + const [state, setState] = useState({ + user: null, + loading: true, + token: '', + parties: [], + countries: [], + organizations: [], + roles: [], + }); + + useEffect(() => { + firebase.initializeApp({ apiKey, authDomain, databaseURL, projectId }); + + firebase + .app() + .auth() + .onAuthStateChanged(async (user) => { + if (user) { + const idToken = await user.getIdToken(); + + setState({ ...state, loading: true }); + const res = await axios.get(`${apiHost()}/me`, { + headers: { Authorization: `Bearer ${idToken}` }, + }); + + const res2 = await axios.get(`${apiHost()}/parties`, { + headers: { Authorization: `Bearer ${idToken}` }, + }); + + const res3 = await axios.get(`${apiHost()}/countries`, { + headers: { Authorization: `Bearer ${idToken}` }, + }); + + const res4 = await axios.get(`${apiHost()}/organizations`, { + headers: { Authorization: `Bearer ${idToken}` }, + }); + + const res5 = await axios.get(`${apiHost()}/users/roles`, { + headers: { Authorization: `Bearer ${idToken}` }, + }); + + setState({ + user: res.data, + loading: false, + token: idToken, + parties: res2.data, + countries: res3.data, + organizations: res4.data, + roles: res5.data, + }); } else { - return process.env.API_HOST; - } - }; - - const authGet = async (path) => { - const res = await axios.get(`${apiHost()}${path}`, { headers: { 'Authorization': `Bearer ${state.token}` }}); - return res; - }; - - const authPost = async (path, body) => { - let res; - try { - res = await axios.post(`${apiHost()}${path}`, body? body : {}, { headers: { 'Authorization': `Bearer ${state.token}` }}); - } catch(err) { - alert(`Error ${err.response.status}: ${err.response.statusText}\n${err.response.data.message.map((m, i) => `\n${i+1}. ${m}`)}`); - throw err; - } - return res; - }; - - const authDelete = async (path) => { - const res = await axios.delete(`${apiHost()}${path}`, { headers: { 'Authorization': `Bearer ${state.token}` }}); - return res; - }; - - const authPut = async (path, body) => { - let res; - try { - res = await axios.put(`${apiHost()}${path}`, body? body : {}, { headers: { 'Authorization': `Bearer ${state.token}` }}); - } catch(err) { - alert(`Error ${err.response.status}: ${err.response.statusText}\n${err.response.data.message.map((m, i) => `\n${i+1}. ${m}`)}`); - throw err; - } - return res; - }; - - const authPatch = async (path, body) => { - let res; - try { - res = await axios.patch(`${apiHost()}${path}`, body? body : {}, { headers: { 'Authorization': `Bearer ${state.token}` }}); - } catch(err) { - alert(`Error ${err.response.status}: ${err.response.statusText}\n${err.response.data.message.map((m, i) => `\n${i+1}. ${m}`)}`); - throw err; + setState({ + user: null, + loading: false, + token: '', + parties: [], + countries: [], + organizations: [], + roles: [], + }); } - return res; - }; - - return( - - - - { - state.loading - ? - : - - {state.user? : } - - - {!state.user? : } - - - {!state.user? : } - - - } - - - - ); + }); + }, []); + + const logIn = ({ email, password }) => { + return firebase.auth().signInWithEmailAndPassword(email, password); + }; + + const logOut = () => { + firebase.app().auth().signOut(); + }; + + const apiHost = () => { + if (!process.env.API_HOST) { + return 'https://d1tapi.dabulgaria.bg'; + } else { + return process.env.API_HOST; + } + }; + + const authGet = async (path) => { + const res = await axios.get(`${apiHost()}${path}`, { + headers: { Authorization: `Bearer ${state.token}` }, + }); + return res; + }; + + const authPost = async (path, body) => { + let res; + try { + res = await axios.post(`${apiHost()}${path}`, body ? body : {}, { + headers: { Authorization: `Bearer ${state.token}` }, + }); + } catch (err) { + alert( + `Error ${err.response.status}: ${ + err.response.statusText + }\n${err.response.data.message.map((m, i) => `\n${i + 1}. ${m}`)}` + ); + throw err; + } + return res; + }; + + const authDelete = async (path) => { + const res = await axios.delete(`${apiHost()}${path}`, { + headers: { Authorization: `Bearer ${state.token}` }, + }); + return res; + }; + + const authPut = async (path, body) => { + let res; + try { + res = await axios.put(`${apiHost()}${path}`, body ? body : {}, { + headers: { Authorization: `Bearer ${state.token}` }, + }); + } catch (err) { + alert( + `Error ${err.response.status}: ${ + err.response.statusText + }\n${err.response.data.message.map((m, i) => `\n${i + 1}. ${m}`)}` + ); + throw err; + } + return res; + }; + + const authPatch = async (path, body) => { + let res; + try { + res = await axios.patch(`${apiHost()}${path}`, body ? body : {}, { + headers: { Authorization: `Bearer ${state.token}` }, + }); + } catch (err) { + alert( + `Error ${err.response.status}: ${ + err.response.statusText + }\n${err.response.data.message.map((m, i) => `\n${i + 1}. ${m}`)}` + ); + throw err; + } + return res; + }; + + return ( + + + + {state.loading ? ( + + ) : ( + + + {state.user ? : } + + + {!state.user ? : } + + + {!state.user ? : } + + + )} + + + + ); }; diff --git a/src/components/Util.js b/src/components/Util.js deleted file mode 100644 index eb96b35..0000000 --- a/src/components/Util.js +++ /dev/null @@ -1,103 +0,0 @@ -const format = function(number, n, x, s, c) { - var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')', - num = parseFloat(number).toFixed(Math.max(0, ~~n)); - - return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ',')); -}; - -const formatLv = function(number) { - return format(number, 2, 3, ' ', ','); -}; - -const formatPop = function(number) { - return format(Math.floor(number), 0, 3, ' ', ','); -} - -const pad = num => { - var s = String(num); - while (s.length < 2) {s = "0" + s;} - return s; -}; - -const month = monthStr => { - switch(monthStr) { - case 0: return 'януари'; break; - case 1: return 'февруари'; break; - case 2: return 'март'; break; - case 3: return 'април'; break; - case 4: return 'май'; break; - case 5: return 'юни'; break; - case 6: return 'юли'; break; - case 7: return 'август'; break; - case 8: return 'септември'; break; - case 9: return 'октомври'; break; - case 10: return 'ноември'; break; - case 11: return 'декември'; break; - } -}; - -const formatDay = d => { - if(d >= 10 && d <= 20) - return d + '-ти'; - - switch(d%10) { - case 1: return d + '-ви'; break; - case 2: return d + '-ри'; break; - case 7: case 8: return d + '-ми'; break; - default: return d + '-ти'; break; - } -}; - -const formatDate = dateTime => { - const date = new Date(dateTime); - - return formatDay(date.getDate()) + ' ' + - month(date.getMonth()) + ' '+ - date.getFullYear(); -}; - -const formatTime = dateTime => { - const date = new Date(dateTime); - return pad(date.getHours()) + ':' + - pad(date.getMinutes()); -}; - -const formatDateTime = dateTime => { - return formatTime(dateTime) + ' ' + formatDateShort(dateTime); - -}; - -const formatSecs = secs => { - return pad(Math.floor(secs / 60)) + ':' + pad(secs % 60); -}; - -const formatDateShort = dateTime => { - const date = new Date(dateTime); - - return pad(date.getDate()) + '.' + - pad(date.getMonth()+1) + '.' + - pad(date.getFullYear()); -} - -const checkPaths = (path1, path2) => { - if(!path1 || !path2) return false; - - if(path1[path1.length - 1] !== '/') - path1 = path1 + '/'; - if(path2[path2.length - 1] !== '/') - path2 = path2 + '/'; - - return path1 === path2; -} - -module.exports = { - formatLv, - formatPop, - formatDate, - formatDateShort, - formatDateTime, - formatTime, - formatSecs, - format, - checkPaths, -}; \ No newline at end of file diff --git a/src/components/modules/Admin.js b/src/components/modules/Admin.js deleted file mode 100644 index 00d0c2c..0000000 --- a/src/components/modules/Admin.js +++ /dev/null @@ -1,174 +0,0 @@ -import React, { useEffect, useContext, useState } from 'react'; -import { Link, useLocation, useHistory } from 'react-router-dom'; - -import { AuthContext } from '../App'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faChevronLeft, faChevronRight, faFastForward, faFastBackward } from '@fortawesome/free-solid-svg-icons'; - -import styled from 'styled-components'; - -import Loading from '../layout/Loading'; - -const TableViewContainer = styled.div` - padding: 40px; - - hr { - border: 1px solid #ccc; - border-bottom: none; - } -`; - -const PaginationLinks = styled.div` - padding: 20px; - text-align: center; - - a { - color: #444; - margin: 0 10px; - text-decoration: none; - - &:hover { - color: #777; - } - - &.disabled { - color: #999; - pointer-events: none; - } - } -`; - -const UserTable = styled.table` - background-color: white; - width: 100%; - border-collapse: collapse; - box-shadow: 0 0 10px #aaa; - - thead { - background-color: #f5f5f5; - text-align: left; - border-bottom: 2px solid #eee; - - th { padding: 10px; } - } - - td { - padding: 8px 15px; - border: none; - } - - tr { - cursor: pointer; - border-bottom: 1px solid #eaeaea; - - &:hover { - background-color: rgb(202, 255, 249); - } - } -`; - -const useQuery = () => { - return new URLSearchParams(useLocation().search); -} - -export default props => { - const { authGet } = useContext(AuthContext); - const [data, setData] = useState(null); - const [loading, setLoading] = useState(false); - const query = useQuery(); - const history = useHistory(); - - useEffect(() => { - let url = '/users'; - const page = query.get("page"); - const limit = query.get("limit"); - - if(page || limit) url += '?'; - - if(page) url += `page=${page}`; - if(limit) url += `limit=${limit}`; - - setLoading(true); - authGet(url).then(res => { - setLoading(false); - setData(res.data); - }); - }, [query.get("page")]); - - const renderLinks = () => { - const firstAvail = data.meta.currentPage !== 1; - const lastAvail = data.meta.currentPage !== data.meta.totalPages; - const nextAvail = data.links.next; - const prevAvail = data.links.previous; - - return ( - - - Първа - - - Предишна - -
- {data.meta.currentPage} / {data.meta.totalPages} -
- - Следваща - - - Последна - -
- ); - }; - - return( - -

Административна секция

-
- { - !data? : [ - renderLinks(), - - - Име - Фамилия - Ел. поща - Телефон - ПИН - Съгласие за данни - Регистриран на - Роли - - - { - loading - ? - : data.items.map((user, i) => - - {user.firstName} - {user.lastName} - {user.email} - {user.phone} - {user.pin} - {user.hasAgreedToKeepData? 'Да' : 'Не'} - {user.registeredAt} - {JSON.stringify(user.roles)} - - ) - } - - , - renderLinks(), -
- Потребители на страница: {query.get("limit")} - 10 - 20 - 50 - 100 -
- ] - } -
- ); -}; \ No newline at end of file diff --git a/src/components/modules/Modules.js b/src/components/modules/Modules.js index 8e6186a..39979bb 100644 --- a/src/components/modules/Modules.js +++ b/src/components/modules/Modules.js @@ -3,7 +3,10 @@ import React from 'react'; import Navigation from './layout/Navigation'; import { Switch, Route, Redirect } from 'react-router-dom'; -import Admin from './Admin'; + +import Admin from './admin/Admin'; +import AdminDetails from './admin/AdminDetails'; + import Posts from './Posts'; import Profile from './Profile'; @@ -18,57 +21,63 @@ import styled from 'styled-components'; import Sections from './Sections'; const NavigationHalf = styled.div` - width: 220px; - height: 100vh; - position: absolute; - top: 0; - left: 0; + width: 220px; + height: 100vh; + position: absolute; + top: 0; + left: 0; `; const ContentHalf = styled.div` - width: calc(100% - 220px); - height: 100vh; - overflow-y: auto; - position: absolute; - top: 0; - right: 0; - background-color: #eee; + width: calc(100% - 220px); + height: 100vh; + overflow-y: auto; + position: absolute; + top: 0; + right: 0; + background-color: #eee; `; export const ContentPanel = styled.div` - background-color: white; - margin: 30px auto; - max-width: 800px; - border-radius: 15px; - //box-shadow: 0px 0px 5px #aaa; - border: 1px solid #eee; - padding: 20px 50px; + background-color: white; + margin: 30px auto; + max-width: 840px; + border-radius: 15px; + //box-shadow: 0px 0px 5px #aaa; + border: 1px solid #eee; + padding: 20px 50px; - hr { - margin: 20px 0; - border: 1px solid #ddd; - border-top: 0; - } + hr { + margin: 20px 0; + border: 1px solid #ddd; + border-top: 0; + } `; -export default props => { - return([ - - - , - - - - - - - - - - {/* */} - - - - - ]); +export default (props) => { + return ( + <> + + + + + + + + + + + + + + + + + + + + ); }; diff --git a/src/components/modules/admin/Admin.js b/src/components/modules/admin/Admin.js new file mode 100644 index 0000000..1934b2e --- /dev/null +++ b/src/components/modules/admin/Admin.js @@ -0,0 +1,289 @@ +import React, { useEffect, useContext, useState } from 'react'; +import { Link, useLocation, useHistory } from 'react-router-dom'; + +import { AuthContext } from '../../App'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { + faChevronLeft, + faChevronRight, + faFastForward, + faFastBackward, +} from '@fortawesome/free-solid-svg-icons'; + +import styled from 'styled-components'; + +import AdminFilter from './AdminFilter'; + +import Loading from '../../layout/Loading'; + +import Tooltip from '../../utils/Tooltip'; + +import { mapRoleLocalization } from '../../utils/Util'; + +const TableViewContainer = styled.div` + padding: 40px; + + hr { + border: 1px solid #ccc; + border-bottom: none; + } +`; + +const PaginationLinks = styled.div` + padding: 20px; + text-align: center; + + a { + color: #444; + margin: 0 10px; + text-decoration: none; + + &:hover { + color: #777; + } + + &.disabled { + color: #999; + pointer-events: none; + } + } +`; + +const UserTable = styled.table` + background-color: white; + width: 100%; + border-collapse: collapse; + box-shadow: 0 0 10px #aaa; + + thead { + background-color: #f5f5f5; + text-align: left; + border-bottom: 2px solid #eee; + + th { + padding: 10px; + } + } + + td { + padding: 8px 15px; + border: none; + } + + tr { + cursor: pointer; + border-bottom: 1px solid #eaeaea; + + &:hover { + background-color: rgb(202, 255, 249); + } + } +`; + +const RoleIcon = styled.span` + background-color: #4aa2ff; + border-radius: 50%; + color: white; + font-weight: bold; + height: 34px; + display: block; + width: 34px; + box-sizing: border-box; + display: flex; + justify-content: center; + align-items: center; + &:hover { + background-color: #5da2ec; + } +`; + +const RolesContainer = styled.div` + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + row-gap: 5px; +`; +const useQuery = () => { + return new URLSearchParams(useLocation().search); +}; + +export default (props) => { + const { authGet } = useContext(AuthContext); + const [data, setData] = useState(null); + const [loading, setLoading] = useState(false); + const query = useQuery(); + const history = useHistory(); + const rolesState = useContext(AuthContext).roles; + + useEffect(() => { + let url = '/users'; + const page = query.get('page'); + const firstName = query.get('firstName'); + const lastName = query.get('lastName'); + const email = query.get('email'); + const role = query.get('role'); + const organization = query.get('organization'); + // const limit = query.get('limit'); + + if (page || firstName || lastName || email || role || organization) + url += '?'; + + if (page) url += `page=${page}`; + if (firstName) url += `firstName=${firstName}`; + if (lastName) url += `lastName=${lastName}`; + if (email) url += `email=${email}`; + if (role) url += `role=${role}`; + if (organization) url += `organization=${organization}`; + + // if (limit) url += `limit=${limit}`; + + setLoading(true); + authGet(url).then((res) => { + setLoading(false); + setData(res.data); + }); + }, [ + query.get('firstName'), + query.get('lastName'), + query.get('email'), + query.get('page'), + query.get('role'), + query.get('organization'), + ]); + + const renderLinks = () => { + const firstAvail = data.meta.currentPage !== 1; + const lastAvail = data.meta.currentPage !== data.meta.totalPages; + const nextAvail = data.links.next; + const prevAvail = data.links.previous; + + return ( + + + Първа + + + Предишна + +
+ {data.meta.currentPage} / {data.meta.totalPages} +
+ + Следваща + + + Последна + +
+ ); + }; + + const openUser = (id) => { + history.push(`/user/${id}`); + }; + + const roles = (roles) => { + return roles.length === 0 ? ( + Без Роля + ) : ( + roles.map((role, idx) => { + return createRoleItem(role, idx); + }) + ); + }; + + const createRoleItem = (role, idx) => { + let roleName = mapRoleLocalization(rolesState, role) ?? role[0]; + let color = '#9e9e9e'; + switch (role) { + case 'user': + color = '#4caf50'; + break; + case 'validator': + color = '#6c6cff'; + break; + case 'lawyer': + color = '#00bcd4'; + break; + case 'streamer': + color = '#ff9800'; + break; + case 'admin': + color = '#ff3a39'; + break; + default: + break; + } + return roleCircle(roleName, idx, color); + }; + + const roleCircle = (roleName, idx, color) => { + return ( + + {roleName[0]} + + ); + }; + + return ( + <> + +

Административна секция

+ +
+ {!data ? ( + + ) : ( + <> + {renderLinks()} + + + + Име + Фамилия + Ел. поща + Телефон + ПИН + Съгласие за данни + {/* Регистриран на */} + Роли + + + + {loading ? ( + + + + + + ) : ( + data.items.map((user, i) => ( + openUser(user.id)}> + {user.firstName} + {user.lastName} + {user.email} + {user.phone} + {user.pin} + {user.hasAgreedToKeepData ? 'Да' : 'Не'} + {/* {user.registeredAt} */} + + {roles(user.roles)} + + + )) + )} + + + {renderLinks()} + + )} +
+ + ); +}; diff --git a/src/components/modules/admin/AdminDetails.js b/src/components/modules/admin/AdminDetails.js new file mode 100644 index 0000000..92b4a68 --- /dev/null +++ b/src/components/modules/admin/AdminDetails.js @@ -0,0 +1,206 @@ +import React, { useState, useEffect, useContext } from 'react'; +import { ContentPanel } from '../Modules'; +import { useHistory, useParams } from 'react-router-dom'; +import { AuthContext } from '../../App'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faChevronLeft } from '@fortawesome/free-solid-svg-icons'; +import { TableStyle } from '../Profile'; +import { BackButton } from '../violations/ViolationDetails'; + +import Loading from '../../layout/Loading'; + +import styled from 'styled-components'; + +const CheckboxList = styled.div` + list-style: none; + padding: 0; + + li { + margin-bottom: 0.5rem; + } + + .checkbox-list-item { + display: flex; + justify-content: space-between; + + label { + vertical-align: text-bottom; + margin-left: 0.5rem; + } + } +`; + +const ButtonStyle = styled.button` + background-color: #4892e1; + color: white; + border: none; + padding: 7px 13px; + font-size: 20px; + cursor: pointer; + font-weight: bold; + border-radius: 5px; + border-bottom: 3px solid #2a68aa; + margin-top: 0px; + width: 10rem; + + &:hover { + background-color: #5da2ec; + } + + &:active { + background-color: #1d5a9b; + border-bottom: none; + margin-top: 3px; + } +`; + +export default (props) => { + const { authGet, authPatch } = useContext(AuthContext); + const { userId } = useParams(); + const history = useHistory(); + const [userData, setUserData] = useState(null); + const [roles, setRoles] = useState(null); + const [rolesUpdateSuccessful, setRolesUpdateSuccessful] = useState(undefined); + const rolesState = useContext(AuthContext).roles; + useEffect(async () => { + const resUser = await authGet(`/users/${userId}`); + setUserData(resUser.data); + + let allRoles = rolesState; + if (resUser.data && allRoles) { + allRoles = allRoles.map((role) => ({ + ...role, + isChecked: resUser.data.roles.includes(role.role), + })); + } + setRoles(allRoles); + }, []); + + const goBack = () => { + history.goBack(); + }; + + const saveRoles = () => { + setRolesUpdateSuccessful(undefined); + + if (roles) { + const rolesToSave = roles + .filter((role) => role.isChecked) + .map((role) => role.role); + + authPatch(`/users/${userData.id}`, { + roles: rolesToSave, + }).then((res) => { + setRolesUpdateSuccessful(res.status === 200); + }); + } + }; + + const handleOnChange = (role) => { + const updatedCheckedState = roles.map((item) => + item.role === role.role ? { ...item, isChecked: !item.isChecked } : item + ); + setRoles(updatedCheckedState); + }; + + return ( + +

+ + + + + Лична информация + +

+
+ + {!userData ? ( + + ) : ( + <> +

Профил

+ + + + Имена + + {userData.firstName} {userData.lastName} + + + + Организация + + {userData.organization ? userData.organization.name : null} + + + + Ел. поща + {userData.email} + + + Телефон + {userData.phone} + + + Съгласие за съхранение на данни + {userData.hasAgreedToKeepData ? 'Да' : 'Не'} + + + + + )} +
+

Роли

+ {!roles ? ( + + ) : ( + <> +
    + + {roles.map((role, index) => { + return ( +
  • +
    +
    + handleOnChange(role)} + /> + +
    +
    +
  • + ); + })} +
    +
+ + Запис + {rolesUpdateSuccessful === + undefined ? null : rolesUpdateSuccessful ? ( +

+ Ролите бяха актуализирани успешно +

+ ) : ( +

+ Грешка при актуализацията на ролите (Опитайте отново) +

+ )} + + )} +
+ ); +}; diff --git a/src/components/modules/admin/AdminFilter.js b/src/components/modules/admin/AdminFilter.js new file mode 100644 index 0000000..c2f8d7f --- /dev/null +++ b/src/components/modules/admin/AdminFilter.js @@ -0,0 +1,116 @@ +import React, { useState, useEffect, useContext } from 'react'; +import { Link } from 'react-router-dom'; + +import { AuthContext } from '../../App'; + +import SendBy from '../filter_components/SendBy'; +import Roles from '../filter_components/Roles'; +import TextInput from '../filter_components/TextInput'; + +import styled from 'styled-components'; + +const FilterTable = styled.div` + display: grid; + grid-template-columns: 1fr 1fr 1fr; + row-gap: 24px; +`; + +const ButtonStyle = styled.button` + background-color: #4892e1; + color: white; + border: none; + padding: 7px 13px; + font-size: 20px; + cursor: pointer; + font-weight: bold; + border-radius: 5px; + border-bottom: 3px solid #2a68aa; + margin-top: 0px; + width: 10rem; + + &:hover { + background-color: #5da2ec; + } + + &:active { + background-color: #1d5a9b; + border-bottom: none; + margin-top: 3px; + } +`; + +export default (props) => { + const [firstName, setFirstName] = useState(''); + const [lastName, setLastName] = useState(''); + const [email, setEmail] = useState(''); + const [organization, setOrganization] = useState(''); + const [role, setRole] = useState(''); + + let url = ''; + + let params = { + firstName: firstName, + lastName: lastName, + email: email, + organization: organization, + role: role, + }; + + for (const [key, value] of Object.entries(params)) { + if (value !== '00' && value !== '' && value) { + url += `&${key}=${value}`; + } else { + url.replace(`&${key}=${value}`, ''); + } + } + + useEffect(() => {}, [firstName, lastName, email, organization, role]); + + const clearAll = () => { + setOrganization(''); + setRole(''); + setFirstName(''); + setLastName(''); + setEmail(''); + }; + + return ( + <> + +
+ Име:

+ +
+
+ Фамилия:

+ +
+
+ Емейл:

+ +
+ +
+ Организация:

+ +
+
+ Роля:

+ +
+
+ + Изчисти + +
+ + + Търси + +
+ + ); +}; diff --git a/src/components/modules/filter_components/Countries.js b/src/components/modules/filter_components/Countries.js index 37473a5..74e1c07 100644 --- a/src/components/modules/filter_components/Countries.js +++ b/src/components/modules/filter_components/Countries.js @@ -1,26 +1,25 @@ -import React, { useContext } from "react"; -import { AuthContext } from "../../App"; +import React, { useContext } from 'react'; +import { AuthContext } from '../../App'; export default (props) => { - const countries = useContext(AuthContext).countries; //things to do when country is selected const optionHandler = (event) => { - var selectCountry = document.getElementById("selectCountry"); + var selectCountry = document.getElementById('selectCountry'); var selectedValue = selectCountry.options[selectCountry.selectedIndex].value; //sets the country code for the get request in the filter component - props.setCountry(selectedValue.split(",")[2]); - props.setSelectedCountry(event.target.value) + props.setCountry(selectedValue.split(',')[2]); + props.setSelectedCountry(event.target.value); //if isAbroad === 'true' - if (selectedValue.split(",")[1] === "true") { - props.setIsAbroad(true); //disables MIR dropdown + if (selectedValue.split(',')[1] === 'true') { + props.setIsAbroad(true); //disables MIR dropdown props.setDisabled(false); //enables the town field - props.setMunicipalities([{name: 'Всички'}]); //sets the visible municipality in the dropdown - props.setRegions([{name: 'Всички'}]) //sets the visible region in the dropdown + props.setMunicipalities([{ name: 'Всички' }]); //sets the visible municipality in the dropdown + props.setRegions([{ name: 'Всички' }]); //sets the visible region in the dropdown props.setTown('00'); props.setMunicipality('00'); props.setCityRegion('00'); @@ -28,7 +27,7 @@ export default (props) => { } else { props.setElectionRegion('00'); props.setIsAbroad(false); //enables the MIR dropdown - props.setDisabled(true); //disables the town dropdown because it should be enabled when MIR is chosen + props.setDisabled(true); //disables the town dropdown because it should be enabled when MIR is chosen props.setMunicipality('00'); } }; @@ -36,17 +35,25 @@ export default (props) => { const filters = countries .sort((a, b) => (a.code > b.code ? 1 : -1)) .map(({ name, code, isAbroad }) => { - {/* to test if the removal of name from the array has any effect??? and If I can make that with key:value pairs */} - {/* e.g. value={[isAbroad: isAbroad, code: code]} */} + { + /* to test if the removal of name from the array has any effect??? and If I can make that with key:value pairs */ + } + { + /* e.g. value={[isAbroad: isAbroad, code: code]} */ + } return ( - ); }); return ( - {filters} ); diff --git a/src/components/modules/filter_components/MainFilter.js b/src/components/modules/filter_components/MainFilter.js index 0533211..1835fb1 100644 --- a/src/components/modules/filter_components/MainFilter.js +++ b/src/components/modules/filter_components/MainFilter.js @@ -1,19 +1,19 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect } from 'react'; -import firebase from "firebase/app"; -import "firebase/auth"; +import firebase from 'firebase/app'; +import 'firebase/auth'; -import axios from "axios"; +import axios from 'axios'; -import SectionNumber from "../filters/SectionNumber"; +import TextInput from '../filters/TextInput'; -import Countries from "../filters/Countries"; -import MIRs from "../filters/MIRs"; -import Municipalities from "../filters/Municipalities"; -import Towns from "../filters/Towns"; -import Regions from "../filters/Regions"; +import Countries from '../filters/Countries'; +import MIRs from '../filters/MIRs'; +import Municipalities from '../filters/Municipalities'; +import Towns from '../filters/Towns'; +import Regions from '../filters/Regions'; -import styled from "styled-components"; +import styled from 'styled-components'; const FilterlTable = styled.table` width: 100%; @@ -52,22 +52,21 @@ const ButtonStyle = styled.button` `; export default (props) => { - const [disabled, setDisabled] = useState(true); //sets callback function for disabling field - const [country, setCountry] = useState("00"); + const [country, setCountry] = useState('00'); - const [mirs, setMirs] = useState([]); //sets all MIRs in Bulgaria - const [chosenMir, setChosenMir] = useState("00"); //gets the chosen MIR + const [mirs, setMirs] = useState([]); //sets all MIRs in Bulgaria + const [chosenMir, setChosenMir] = useState('00'); //gets the chosen MIR const [municipalities, setMunicipalities] = useState([]); //sets the municipalities in one MIR - const [chosenMunicipality, setChosenMunicipality] = useState("00"); //gets the chosen municipality + const [chosenMunicipality, setChosenMunicipality] = useState('00'); //gets the chosen municipality const [towns, setTowns] = useState([]); //sets all towns in one municipality const [regions, setRegions] = useState([]); //sets the election regions in one town - const [status, setStatus] = useState(""); + const [status, setStatus] = useState(''); const [isAbroad, setIsAbroad] = useState(false); //sets if country is Bulgaria or not const submitHandler = () => { @@ -76,7 +75,7 @@ export default (props) => { const apiHost = () => { if (!process.env.API_HOST) { - return "https://d1tapi.dabulgaria.bg"; + return 'https://d1tapi.dabulgaria.bg'; } else { return process.env.API_HOST; } @@ -95,8 +94,8 @@ export default (props) => { headers: { Authorization: `Bearer ${idToken}` }, }); - //if country is NOT Bulgaria: gets all the cities in the foreign country - if (country !== "00") { + //if country is NOT Bulgaria: gets all the cities in the foreign country + if (country !== '00') { const res2 = await axios.get( `${apiHost()}/towns?country=${country}`, { @@ -127,7 +126,7 @@ export default (props) => { - N на секция:

+ N на секция:

Произход:

diff --git a/src/components/modules/filter_components/Municipalities.js b/src/components/modules/filter_components/Municipalities.js index 6de3015..dea87fb 100644 --- a/src/components/modules/filter_components/Municipalities.js +++ b/src/components/modules/filter_components/Municipalities.js @@ -1,11 +1,11 @@ -import React from "react"; +import React from 'react'; export default (props) => { let municipalities = []; if (!props.isAbroad) { municipalities = [ - { code: "00", name: "Всички", isAbroad: false }, + { code: '00', name: 'Всички', isAbroad: false }, ...props.municipalities, ]; } else { @@ -13,13 +13,11 @@ export default (props) => { } const municipalityHandler = (event) => { + props.setSelectedMunicipality(event.target.value); - props.setSelectedMunicipality(event.target.value) - - var selectMunicipality = document.getElementById("selectMunicipality"); + var selectMunicipality = document.getElementById('selectMunicipality'); var selectedValue = selectMunicipality.options[selectMunicipality.selectedIndex].value; - municipalities.map(({ code, name }) => { if (selectedValue === name) { props.setMunicipality(code); @@ -28,9 +26,9 @@ export default (props) => { }; const filters = municipalities .sort((a, b) => (a.code > b.code ? 1 : -1)) - .map(({ code, name }) => { + .map(({ code, name }, idx) => { return ( - ); diff --git a/src/components/modules/filter_components/Regions.js b/src/components/modules/filter_components/Regions.js index e016523..ba55fd6 100644 --- a/src/components/modules/filter_components/Regions.js +++ b/src/components/modules/filter_components/Regions.js @@ -1,11 +1,13 @@ -import React from "react"; +import React from 'react'; export default (props) => { - let regions = []; if (!props.isAbroad) { - regions = [{ code: "00", name: "Всички", isAbroad: false }, ...props.regions]; + regions = [ + { code: '00', name: 'Всички', isAbroad: false }, + ...props.regions, + ]; } else { regions = props.regions; } @@ -14,13 +16,21 @@ export default (props) => { props.setCityRegion(event.target.value); }; - const filters = regions.map(({ name, code }) => { + const filters = regions.map(({ name, code }, idx) => { return ( - ); }); - return ; + return ( + + ); }; diff --git a/src/components/modules/filter_components/Roles.js b/src/components/modules/filter_components/Roles.js new file mode 100644 index 0000000..0afb00f --- /dev/null +++ b/src/components/modules/filter_components/Roles.js @@ -0,0 +1,28 @@ +import React, { useContext } from 'react'; +import { AuthContext } from '../../App'; + +export default (props) => { + const roles = useContext(AuthContext).roles; + + const { setRole, role } = props; + + const allRoles = [{ role: '00', roleLocalized: 'Всички' }, ...roles]; + + const changeHandler = (event) => { + setRole(event.target.value); + }; + + const filters = allRoles.map((role, idx) => { + return ( + + ); + }); + + return ( + + ); +}; diff --git a/src/components/modules/filter_components/SectionNumber.js b/src/components/modules/filter_components/TextInput.js similarity index 55% rename from src/components/modules/filter_components/SectionNumber.js rename to src/components/modules/filter_components/TextInput.js index 4d3dc23..179bb78 100644 --- a/src/components/modules/filter_components/SectionNumber.js +++ b/src/components/modules/filter_components/TextInput.js @@ -1,6 +1,6 @@ -import React from "react"; +import React from 'react'; -import styled from "styled-components"; +import styled from 'styled-components'; const InputField = styled.input` background: white; @@ -12,14 +12,12 @@ const InputField = styled.input` `; export default (props) => { + const { setTextInput } = props; - const { setSection } = props; - const changeHandler = (event) => { event.preventDefault(); - setSection(event.target.value); + setTextInput(event.target.value); }; - - return ; + return ; }; diff --git a/src/components/modules/filter_components/Towns.js b/src/components/modules/filter_components/Towns.js index 98dd0dd..3e78b30 100644 --- a/src/components/modules/filter_components/Towns.js +++ b/src/components/modules/filter_components/Towns.js @@ -1,21 +1,21 @@ -import React from "react"; +import React from 'react'; export default (props) => { let towns = []; if (!props.isAbroad) { - towns = [{ id: "00", name: "Всички", isAbroad: false }, ...props.towns]; + towns = [{ id: '00', name: 'Всички', isAbroad: false }, ...props.towns]; } else { - towns = [{ id: "00", name: "Всички", isAbroad: true }, ...props.towns]; + towns = [{ id: '00', name: 'Всички', isAbroad: true }, ...props.towns]; } const townHandler = (event) => { props.setSelectedTown(event.target.value); - var selectTown = document.getElementById("selectTown"); + var selectTown = document.getElementById('selectTown'); var selectedValue = selectTown.options[selectTown.selectedIndex].value; if (!props.isAbroad) { - if (selectedValue !== "Всички") { + if (selectedValue !== 'Всички') { towns.map(({ name, cityRegions, id }) => { if (selectedValue === name) { props.setRegions(cityRegions); @@ -23,10 +23,10 @@ export default (props) => { } }); } else { - props.setTown(""); + props.setTown(''); } } else { - props.setRegions([{ name: "Всички", code: "00" }]); + props.setRegions([{ name: 'Всички', code: '00' }]); towns .sort((a, b) => (a.id > b.id ? 1 : -1)) .map(({ name, id }) => { @@ -49,7 +49,6 @@ export default (props) => { return (