diff --git a/src/actions/SuppliersActions.js b/src/actions/SuppliersActions.js
index 803ceb6a..af87be7a 100644
--- a/src/actions/SuppliersActions.js
+++ b/src/actions/SuppliersActions.js
@@ -185,6 +185,60 @@ SuppliersActions.uploadFiles = (files, providerId) => async (
});
};
+SuppliersActions.uploadTariffZonesFiles = (files, provider) => async (
+ dispatch,
+ getState
+) => {
+ dispatch(sendData(0, types.UPDATED_TARIFF_ZONE_FILE_UPLOAD_PROGRESS));
+
+ const url = `${window.config.tariffZonesUrl}${provider.chouetteInfo.xmlns}/files`;
+
+ var data = new FormData();
+
+ files.forEach(file => {
+ data.append('files', file);
+ });
+
+ var config = {
+ onUploadProgress: function(progressEvent) {
+ let percentCompleted = (progressEvent.loaded / progressEvent.total) * 100;
+ dispatch(
+ sendData(
+ percentCompleted,
+ types.UPDATED_TARIFF_ZONE_FILE_UPLOAD_PROGRESS
+ )
+ );
+ },
+ ...(await getApiConfig(getState().UserReducer.auth))
+ };
+
+ return axios
+ .post(url, data, config)
+ .then(function(response) {
+ dispatch(
+ SuppliersActions.addNotification(
+ 'Uploaded tariff zone file(s)',
+ 'success'
+ )
+ );
+ dispatch(
+ SuppliersActions.logEvent({
+ title: 'Uploaded tariff zone file(s): ' + files.join(',')
+ })
+ );
+ dispatch(sendData(0, types.UPDATED_TARIFF_ZONE_FILE_UPLOAD_PROGRESS));
+ })
+ .catch(function(response) {
+ dispatch(
+ SuppliersActions.addNotification(
+ 'Unable to upload tariff zone file(s)',
+ 'error'
+ )
+ );
+ dispatch(sendData(0, types.UPDATED_TARIFF_ZONE_FILE_UPLOAD_PROGRESS));
+ });
+};
+
SuppliersActions.getAllProviderStatus = () => async (dispatch, getState) => {
dispatch(sendData(null, types.REQUESTED_ALL_SUPPLIERS_STATUS));
const state = getState();
diff --git a/src/actions/actionTypes.js b/src/actions/actionTypes.js
index d55ca6ee..7c2961eb 100644
--- a/src/actions/actionTypes.js
+++ b/src/actions/actionTypes.js
@@ -167,6 +167,8 @@ export const REQUESTED_ALL_SUPPLIERS_STATUS = 'REQUESTED_ALL_SUPPLIERS_STATUS';
export const RECEIVED_ALL_SUPPLIERS_STATUS = 'RECEIVED_ALL_SUPPLIERS_STATUS';
export const UPDATED_FILE_UPLOAD_PROGRESS = 'UPDATED_FILE_UPLOAD_PROGRESS';
+export const UPDATED_TARIFF_ZONE_FILE_UPLOAD_PROGRESS =
+ 'UPDATED_TARIFF_ZONE_FILE_UPLOAD_PROGRESS';
/* organization actions */
diff --git a/src/config/environments/dev.json b/src/config/environments/dev.json
index 1df20cb0..7b14c840 100644
--- a/src/config/environments/dev.json
+++ b/src/config/environments/dev.json
@@ -8,6 +8,7 @@
"mapboxAdminBaseUrl": "https://api.dev.entur.io/mapbox-admin/v1/",
"geocoderAdminBaseUrl": "https://api.dev.entur.io/timetable-admin/v1/geocoder/",
"poiFilterBaseUrl": "https://api.dev.entur.io/timetable-admin/v2/poi-filter",
+ "tariffZonesUrl": "https://api.dev.entur.io/timetable-admin/v2/tariffzones-import/",
"endpointBase": "/",
"chouetteBaseUrl": "https://rutedb.dev.entur.org/",
"udugBaseUrl": "/netex-validation-reports/",
diff --git a/src/reducers/SuppliersReducer.js b/src/reducers/SuppliersReducer.js
index 087243c6..a13d52a7 100644
--- a/src/reducers/SuppliersReducer.js
+++ b/src/reducers/SuppliersReducer.js
@@ -94,6 +94,11 @@ const SuppliersReducer = (state = initialState, action) => {
case types.UPDATED_FILE_UPLOAD_PROGRESS:
return Object.assign({}, state, { fileUploadProgress: action.payLoad });
+ case types.UPDATED_TARIFF_ZONE_FILE_UPLOAD_PROGRESS:
+ return Object.assign({}, state, {
+ tariffZoneFileUploadProgress: action.payLoad
+ });
+
case types.RECEIVED_GRAPH_STATUS:
return Object.assign({}, state, { ...action.payLoad });
diff --git a/src/screens/common/components/FileUpload.js b/src/screens/common/components/FileUpload.js
new file mode 100644
index 00000000..674820c2
--- /dev/null
+++ b/src/screens/common/components/FileUpload.js
@@ -0,0 +1,119 @@
+import React, { useEffect, useState } from 'react';
+import Dropzone from 'react-dropzone';
+import Button from 'muicss/lib/react/button';
+import { Line as Progress } from 'rc-progress';
+
+export const FileUpload = ({ fileUploadProgress, handleFileUpload }) => {
+ const [files, setFiles] = useState([]);
+ const [showSuccess, setShowSuccess] = useState(false);
+ const [uploadProgress, setUploadProgress] = useState(0);
+
+ useEffect(() => {
+ if (fileUploadProgress === 100) {
+ setFiles([]);
+ setShowSuccess(true);
+ }
+ }, [fileUploadProgress]);
+
+ useEffect(() => {
+ let showSuccessTimer = setTimeout(() => resetProgress(), 3000);
+ return () => {
+ clearTimeout(showSuccessTimer);
+ };
+ }, [showSuccess]);
+
+ useEffect(() => {
+ if (!showSuccess) {
+ setUploadProgress(fileUploadProgress);
+ }
+ }, [fileUploadProgress]);
+
+ const resetProgress = () => {
+ setShowSuccess(false);
+ setUploadProgress(0);
+ };
+
+ const handleOnDrop = files => {
+ if (files.length) {
+ setFiles(files);
+ }
+ };
+
+ const dropStyle = {
+ height: '150px',
+ borderWidth: 1,
+ borderColor: '#666',
+ borderStyle: 'dashed',
+ borderRadius: 2,
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ cursor: 'pointer'
+ };
+
+ const filesStyle = {
+ marginTop: '5%',
+ minHeight: '300px',
+ maxHeight: '300px'
+ };
+
+ const uploadButtonStyle = {
+ width: 100,
+ fontSize: '0.8em',
+ textAlign: 'center',
+ marginLeft: 'auto',
+ marginTop: 10
+ };
+
+ return (
+
+
{
+ handleOnDrop(files);
+ console.warn('rejected', rejected);
+ }}
+ >
+
+ Try dropping some files here, or click to select files to upload.
+
+
+ {files.length ? (
+
+ ) : (
+
No files added
+ )}
+
+
+ {showSuccess && (
+
Files successfully uploaded
+ )}
+
+ );
+};
diff --git a/src/screens/common/components/SelectSupplier.js b/src/screens/common/components/SelectSupplier.js
new file mode 100644
index 00000000..95fdbf2c
--- /dev/null
+++ b/src/screens/common/components/SelectSupplier.js
@@ -0,0 +1,49 @@
+import SelectField from 'material-ui/SelectField';
+import MenuItem from 'material-ui/MenuItem';
+import React from 'react';
+
+export const SelectSupplier = ({
+ suppliers,
+ selectSupplier,
+ selectedSupplierId,
+ errorText
+}) => {
+ return (
+ <>
+ selectSupplier(v)}
+ autoWidth={true}
+ value={Number(selectedSupplierId) || -1}
+ iconStyle={{ fill: 'rgba(22, 82, 149, 0.69)' }}
+ >
+ {suppliers.map(supplier => {
+ const isLevel1Provider =
+ (supplier.chouetteInfo &&
+ supplier.chouetteInfo.migrateDataToProvider) ||
+ supplier.id === -1;
+ return (
+
+ {errorText && {errorText}
}
+ >
+ );
+};
diff --git a/src/screens/geocoder/components/tariffZonesImport/TariffZonesImport.js b/src/screens/geocoder/components/tariffZonesImport/TariffZonesImport.js
new file mode 100644
index 00000000..b9dc8ede
--- /dev/null
+++ b/src/screens/geocoder/components/tariffZonesImport/TariffZonesImport.js
@@ -0,0 +1,62 @@
+import { SelectSupplier } from '../../../common/components/SelectSupplier';
+import { useSelector, shallowEqual, useDispatch } from 'react-redux';
+import React, { useState } from 'react';
+import { FileUpload } from '../../../common/components/FileUpload';
+import SuppliersActions from '../../../../actions/SuppliersActions';
+
+export const TariffZonesImport = () => {
+ const suppliers = useSelector(
+ state => state.SuppliersReducer.data,
+ shallowEqual
+ );
+
+ const tariffZoneFileUploadProgress = useSelector(
+ state => state.SuppliersReducer.tariffZoneFileUploadProgress,
+ shallowEqual
+ );
+
+ const [selectedSupplier, setSelectedSupplier] = useState(null);
+ const [noSupplierSelected, setNoSupplierSelected] = useState(null);
+ const dispatch = useDispatch();
+
+ const handleFileUpload = files => {
+ if (selectedSupplier === null) {
+ setNoSupplierSelected(true);
+ } else {
+ dispatch(
+ SuppliersActions.uploadTariffZonesFiles(files, selectedSupplier)
+ );
+ }
+ };
+
+ const onSelectSupplier = selectedSupplierId => {
+ setNoSupplierSelected(false);
+ setSelectedSupplier(
+ suppliers.find(supplier => supplier.id === selectedSupplierId)
+ );
+ };
+
+ return (
+
+ );
+};
diff --git a/src/screens/geocoder/index.js b/src/screens/geocoder/index.js
index 7a47c9f7..46892dfe 100644
--- a/src/screens/geocoder/index.js
+++ b/src/screens/geocoder/index.js
@@ -1,10 +1,14 @@
-import React from 'react';
+import React, { useEffect } from 'react';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';
import Pelias from './components/Pelias';
import OSMPOIFilter from './components/OSMPOIFilter';
+import { TariffZonesImport } from './components/tariffZonesImport/TariffZonesImport';
+import { getQueryVariable } from '../../utils';
+import SuppliersActions from '../../actions/SuppliersActions';
+import { useDispatch } from 'react-redux';
function TabPanel(props) {
const { children, value, index, ...other } = props;
@@ -32,6 +36,11 @@ function a11yProps(index) {
export default () => {
const [value, setValue] = React.useState(0);
+ const dispatch = useDispatch();
+
+ useEffect(() => {
+ dispatch(SuppliersActions.getAllProviders());
+ }, []);
const handleChange = (event, newValue) => {
setValue(newValue);
@@ -47,6 +56,7 @@ export default () => {
>
+
@@ -54,6 +64,9 @@ export default () => {
+
+
+
);
};
diff --git a/src/screens/providers/components/FileUpload.js b/src/screens/providers/components/FileUpload.js
deleted file mode 100644
index c0858f25..00000000
--- a/src/screens/providers/components/FileUpload.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
- * the European Commission - subsequent versions of the EUPL (the "Licence");
- * You may not use this work except in compliance with the Licence.
- * You may obtain a copy of the Licence at:
- *
- * https://joinup.ec.europa.eu/software/page/eupl
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the Licence is distributed on an "AS IS" basis,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Licence for the specific language governing permissions and
- * limitations under the Licence.
- *
- */
-
-import React from 'react';
-import Dropzone from 'react-dropzone';
-import Button from 'muicss/lib/react/button';
-import { Line as Progress } from 'rc-progress';
-
-class FileUpload extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- files: []
- };
- }
-
- handleOnDrop(files) {
- if (files.length) {
- this.setState({
- files: files
- });
- return false;
- }
- }
-
- render() {
- const dropStyle = {
- height: '150px',
- borderWidth: 1,
- borderColor: '#666',
- borderStyle: 'dashed',
- borderRadius: 2,
- display: 'flex',
- justifyContent: 'center',
- alignItems: 'center'
- };
-
- const filesStyle = {
- marginTop: '5%',
- minHeight: '300px',
- maxHeight: '300px'
- };
-
- const uploadButtonStyle = {
- width: 100,
- fontSize: '0.8em',
- textAlign: 'center',
- marginLeft: 'auto',
- marginTop: 10
- };
-
- const { files } = this.state;
- const { fileUploadProgress, handleFileUpload } = this.props;
-
- return (
-
-
{
- this.handleOnDrop(files);
- console.warn('rejected', rejected);
- }}
- >
-
- Try dropping some files here, or click to select files to upload.
-
-
- {files.length ? (
-
- ) : (
-
No files added
- )}
-
-
-
- );
- }
-}
-
-export default FileUpload;
diff --git a/src/screens/providers/components/SupplierTabWrapper.js b/src/screens/providers/components/SupplierTabWrapper.js
index 48c5941e..31ca7300 100644
--- a/src/screens/providers/components/SupplierTabWrapper.js
+++ b/src/screens/providers/components/SupplierTabWrapper.js
@@ -24,7 +24,7 @@ import { PulseLoader as Loader } from 'halogenium';
import Tabs from 'muicss/lib/react/tabs';
import Tab from 'muicss/lib/react/tab';
import { getQueryVariable } from 'utils';
-import FileUpload from './FileUpload';
+import { FileUpload } from '../../common/components/FileUpload';
import OrganizationRegister from './OrganizationRegister';
import rolesParser from 'roles/rolesParser';
import ExportedFilesView from './ExportedFilesView';
@@ -403,10 +403,12 @@ class SupplierTabWrapper extends React.Component {
)}
-
+
+
+
);
diff --git a/src/screens/providers/components/SuppliersContainer.js b/src/screens/providers/components/SuppliersContainer.js
index 03336d93..7647413e 100644
--- a/src/screens/providers/components/SuppliersContainer.js
+++ b/src/screens/providers/components/SuppliersContainer.js
@@ -18,14 +18,13 @@ import { connect } from 'react-redux';
import React from 'react';
import SuppliersActions from 'actions/SuppliersActions';
import cfgreader from 'config/readConfig';
-import MenuItem from 'material-ui/MenuItem';
-import SelectField from 'material-ui/SelectField';
import MdNew from 'material-ui/svg-icons/content/add';
import { getQueryVariable } from 'utils';
import rolesParser from 'roles/rolesParser';
import MdEdit from 'material-ui/svg-icons/image/edit';
import MdDelete from 'material-ui/svg-icons/action/delete-forever';
import ConfirmDialog from 'modals/ConfirmDialog';
+import { SelectSupplier } from '../../common/components/SelectSupplier';
class SuppliersContainer extends React.Component {
constructor(props) {
@@ -121,39 +120,11 @@ class SuppliersContainer extends React.Component {
}}
>
-
this.selectSupplier(v)}
- autoWidth={true}
- value={Number(activeProviderId) || -1}
- iconStyle={{ fill: 'rgba(22, 82, 149, 0.69)' }}
- >
- {supplierItems.map(supplier => {
- const isLevel1Provider =
- (supplier.chouetteInfo &&
- supplier.chouetteInfo.migrateDataToProvider) ||
- supplier.id === -1;
- return (
-
+
this.selectSupplier(v)}
+ selectedSupplierId={activeProviderId}
+ />
{canEditOrganisation && (