+ new Promise((success, fail) => {
+ setTimeout(() => {
+ success()
+ }, 800)
+ })
+)
+const link = ApolloLink.from([
+ delay,
+ http
+])
+const cache = new InMemoryCache()
+const client = new ApolloClient({
+ link,
+ cache,
+ onError: ({ graphQLErrors, networkError }) => {
+ if (graphQLErrors) {
+ graphQLErrors.map(({ message, locations, path }) =>
+ console.log(
+ `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`),
+ console.log('This is a graphQL error!'),
+ );
+ }
+ if (networkError) {
+ console.log('This is a Network Error!', networkError);
+ console.log('Can be called from a query error in the browser code!');
+ }
+ }
+})
+
+export default client;
\ No newline at end of file
diff --git a/ui/src/component/AccordionGroup.js b/ui/src/component/AccordionGroup.js
new file mode 100644
index 0000000..c3936e0
--- /dev/null
+++ b/ui/src/component/AccordionGroup.js
@@ -0,0 +1,138 @@
+import React, { useState, useEffect } from 'react'
+import Map from 'collections/map'
+import ListGroup from 'react-bootstrap/ListGroup'
+import Accordion from 'react-bootstrap/Accordion'
+import Card from 'react-bootstrap/Card'
+import { GET_REGIONS } from '../container/Query'
+import { useQuery } from '@apollo/react-hooks'
+import City from './City'
+import Loading from '../component/Loading'
+
+const AccordionGroup = ({ selectedContinent }) => {
+ const [selectedRegion, setSelectedRegion] = useState(null)
+ const [selectedCountry, setSelectedCountry] = useState(null)
+ const [selectedCountryCode, setSelectedCountryCode] = useState(null)
+ const [countryData, setCountryData] = useState([])
+
+ useEffect(() => {
+ setSelectedCountry(null)
+ setSelectedCountryCode(null)
+ setCountryData([])
+ setSelectedRegion(null)
+ console.log('value changed selectedContinent!')
+
+ }, [selectedContinent]);
+
+ const { loading, error, data } = useQuery(GET_REGIONS, {
+ variables: {
+ "countryContinent": `${selectedContinent}`
+ }
+ });
+
+ if (loading) return
+ if (error) return An error occured
+
+
+ /* ************************************************************ */
+ /* Get countries on selected region
+ /* ************************************************************ */
+ const handleRegionClick = (selectedRegion) => {
+ let countryData = data.getAllRegions.filter(item => {
+ return item.countryRegion === selectedRegion;
+ });
+ setSelectedRegion(selectedRegion)
+ setCountryData(countryData)
+ setSelectedCountryCode(null)
+ setSelectedCountry(null)
+ }
+
+ /* ************************************************************ */
+ /* Get cities on selected country based on the country code
+ /* ************************************************************ */
+ const handleCountryClick = (item) => {
+ let countryCode = item.countryCode,
+ countryName = item.countryName
+
+ setSelectedCountry(countryName)
+ setSelectedCountryCode(countryCode)
+ }
+
+ const getRegionList = (data) => {
+ const result = [];
+ const map = new Map();
+
+ for (const item of data) {
+ if (!map.has(item.countryRegion)) {
+ map.set(item.countryRegion, true); // set any value to Map
+ result.push({ countryRegion: item.countryRegion });
+ }
+ }
+ return result
+ }
+
+ const getClassname = (item, currentSelection) => {
+ if (item === currentSelection) return 'selected';
+ return 'unselected';
+ }
+
+ let regions = getRegionList(data.getAllRegions)
+ return (
+
+
+ {/* Panel to show regions */}
+
+
+ Regions in Continent {selectedContinent} (Count:{regions.length})
+
+
+
+
+ {regions.map((item, key) => {
+ return handleRegionClick(item.countryRegion)}>
+ {item.countryRegion}
+
+ })
+ }
+
+
+
+
+
+ {/* Panel to show countries */}
+ {/* */}
+
+
+ Countries filtered by selected region {selectedRegion} (Count:{countryData.length})
+
+
+
+
+ {countryData.map((item, key) => {
+ return handleCountryClick(item)}>
+ {item.countryName}
+
+ })
+ }
+
+
+
+
+
+ {/* Panel to show cities */}
+
+
+ Cities filtered by selected country {selectedCountry}
+
+
+
+ {
+ selectedCountryCode &&
+ }
+
+
+
+
+ );
+}
+
+export default AccordionGroup;
diff --git a/ui/src/component/City.js b/ui/src/component/City.js
new file mode 100644
index 0000000..8ec4404
--- /dev/null
+++ b/ui/src/component/City.js
@@ -0,0 +1,74 @@
+import React, { useState } from 'react'
+import { FaRegTrashAlt } from 'react-icons/fa'
+import { AiFillEdit } from 'react-icons/ai'
+import ListGroup from 'react-bootstrap/ListGroup'
+import { useQuery, NetworkStatus } from "@apollo/client"
+import { useMutation } from '@apollo/client'
+import { GET_CITIES, DELETE_CITY } from '../container/Query'
+import UpdateModal from './Modal'
+import Loading from './Loading'
+
+function City({ countryCode }) {
+ const [ show, setShow ] = useState(false)
+ const [ row, setRow ] = useState("")
+
+ const [ deleteCity,{ loading: delMutationLoading, error: delMutationError } ] = useMutation(DELETE_CITY)
+
+ const { loading, error, data, refetch, networkStatus } = useQuery(GET_CITIES, {
+ variables: {countryCode},
+ fetchPolicy: "no-cache",
+ notifyOnNetworkStatusChange: true
+ },
+ );
+
+ if (networkStatus === NetworkStatus.refetch) return 'Refetching!' && ;
+ if (loading) return null;
+ if (error) return `Error! ${error}`;
+
+
+ const toggleOpen = (item) => {
+ setShow(true)
+ setRow(item)
+ }
+
+ const closeModal = () => {
+ refetch()
+ setShow(false)
+ }
+
+ const handleDelete = (item) => {
+ deleteCity({
+ variables: {
+ "cityId": `${item.cityId}`,
+ refetchQueries: [{query: GET_CITIES}]
+ }
+ });
+ console.log("Deleted")
+ refetch()
+
+ }
+
+ const getClassname = (item, currentSelection) => {
+ if (item === currentSelection) return 'selected';
+ return 'unselected';
+ }
+
+ return (<>
+ setShow(false)} handleClose={closeModal}>
+ {delMutationLoading && Loading after delete...
}
+ {delMutationError && Error :( Please try again
}
+ {
+ data && data.getAllCities && data.getAllCities.map((item, key) =>
+
+ {item.cityName}
+
+ toggleOpen(item)} /> | {handleDelete(item)}} />
+
+
+ )
+ }
+ >
+ )
+}
+
+export default City;
diff --git a/ui/src/component/Loading.js b/ui/src/component/Loading.js
new file mode 100644
index 0000000..a1c094b
--- /dev/null
+++ b/ui/src/component/Loading.js
@@ -0,0 +1,8 @@
+import React from 'react';
+import {Spinner} from 'react-bootstrap'
+
+export default function Loading() {
+ return
+ Loading...
+
+}
\ No newline at end of file
diff --git a/ui/src/component/Modal.js b/ui/src/component/Modal.js
index 83c92c7..d148c77 100644
--- a/ui/src/component/Modal.js
+++ b/ui/src/component/Modal.js
@@ -1,172 +1,146 @@
-import React, { useState } from 'react';
+import React, { useState } from 'react'
import Modal from 'react-bootstrap/Modal'
import Button from 'react-bootstrap/Button'
-import InputGroup from 'react-bootstrap/InputGroup'
import Form from 'react-bootstrap/Form'
import FormControl from 'react-bootstrap/FormControl'
import Col from 'react-bootstrap/Col'
-import { gql,useMutation } from '@apollo/client';
-import { client } from '../index';
+import { useMutation } from '@apollo/client'
+import { ADD_CITY, GET_CITIES } from '../container/Query'
+const UpdateModal = ({ show, row, handleClose, handleCloseModal }) => {
+ const [ validated, setValidated ] = useState(false);
+ const [ addCity ] = useMutation(ADD_CITY);
+ const [ state, setState] = useState({
+ id: null,
+ name: null,
+ code: null,
+ district: null,
+ population: null
+ });
-const UpdateModal=({show, handleClose, item}) =>{
- const [state, setState] = useState({
- id: item[0],
- name: item[1],
- code: item[2],
- district: item[3],
- population: item[4]
- });
- const [validated, setValidated] = useState(false);
+ const handleSubmit = (event) => {
+ const form = event.currentTarget;
-
- const SET_MUTATION = gql `
- mutation{
- addCity(cityId:${state.id},cityName:"${state.name}",cityCountrycode:"${state.code}",cityDistrict:"${state.district}",cityPopulation:${state.population}) {
- city{
- cityId,
- cityName,
- cityCountrycode,
- cityDistrict,
- cityPopulation
- }
- }
- }`;
- const DELETE_MUTATION = gql`
- mutation{
- deleteCity(cityId:${item[0]}) {
- city{
- cityId
+ if (form.checkValidity() === false) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ else {
+ setValidated(true);
+ addCity({
+ variables: {
+ "cityId": `${state.id}`,
+ "cityName": `${state.name}`,
+ "cityCountrycode": `${state.code}`,
+ "cityDistrict": `${state.district}`,
+ "cityPopulation": `${state.population}`,
+ refetchQueries: [{query: GET_CITIES}]
}
- }
- }`;
- const [ addCity ] = useMutation(SET_MUTATION);
- const [ deleteCity, { loading, error } ] = useMutation(DELETE_MUTATION);
-
- if (loading) return Loading
;;
- if (error) return An error occurred
;
-
- const handleSubmit = (event) => {
- const form = event.currentTarget;
-
- if (form.checkValidity() === false) {
- event.preventDefault();
- event.stopPropagation();
- } else {
- setValidated(true);
- addCity();
- handleClose();
- }
- };
-
-
- const handleDelete = (event) => {
- deleteCity()
- handleClose()
- }
+ });
+ handleClose();
+ }
+ };
- return (
- <>
-
-
- Admin Panel
-
- Woohoo, you can now edit the city records!
-
- Id
- {
- let inputValue = e.target.value;
- (setState({
- ...state,
- id: inputValue
- }
- ))}}
- />
-
+ return (
+ <>
+
+
+ Admin Panel
+
+ Woohoo, you can now edit the city records!
+
+ Id
+ {
+ let inputValue = e.target.value;
+ (setState({
+ ...state,
+ id: inputValue
+ }
+ ))
+ }}/>
+
-
- Name
-
+ Name
+
- { let inputValue = e.target.value;
- setState({
- ...state,
- name: inputValue
- })}}
- />
-
+ onChange={e => {
+ let inputValue = e.target.value;
+ setState({
+ ...state,
+ name: inputValue
+ })
+ }}
+ />
+
-
+
Code
-
- { let inputValue = e.target.value;
+ {
+ let inputValue = e.target.value;
setState({
- ...state,
- code:inputValue
- })}}
+ ...state,
+ code: inputValue
+ })
+ }}
/>
-
+
-
+
District
{
+ required
+ placeholder={row && row.cityDistrict}
+ aria-label="district"
+ aria-describedby="district"
+ onChange={e => {
let inputValue = e.target.value;
setState({
- ...state,
- district: inputValue
- })}}
+ ...state,
+ district: inputValue
+ })
+ }}
/>
-
+
-
+
Population
- { let inputValue = e.target.value;
+ required
+ placeholder={row && row.cityPopulation}
+ aria-label="population"
+ aria-describedby="population"
+ onChange={e => {
+ let inputValue = e.target.value;
setState({
- ...state,
- population: inputValue
- })}}
- />
-
+ ...state,
+ population: inputValue
+ })
+ }}
+ />
+
-
-
+
-
-
- >
- );
- }
-
- export default UpdateModal;
+
+
+ >
+ );
+}
+
+export default UpdateModal;
diff --git a/ui/src/component/WorldlMap.js b/ui/src/component/WorldlMap.js
index ce1d56c..996c676 100644
--- a/ui/src/component/WorldlMap.js
+++ b/ui/src/component/WorldlMap.js
@@ -25,7 +25,7 @@ export default class WorldMap extends React.Component {
return
`Continent: ${dataTip}`} />
-