Sync nomenclatures with fieldnotes server
This commit is contained in:
parent
5d5277d7e4
commit
f2a49c0936
|
@ -56,6 +56,12 @@ class SettingScreen extends React.Component {
|
|||
name="useNotebookGPS"
|
||||
defaultValue={settings.useNotebookGPS}
|
||||
form={form} />
|
||||
<TextField
|
||||
label="URL de récupération des nomenclatures"
|
||||
name="nomenclaturesURL"
|
||||
defaultValue={ settings.nomenclaturesURL }
|
||||
form={form}
|
||||
/>
|
||||
</Form>
|
||||
<Text />
|
||||
<Button full success onPress={form.onSubmit}>
|
||||
|
|
|
@ -1,30 +1,5 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View, Text,
|
||||
List, ListItem,
|
||||
Left, Right,
|
||||
Button, Icon,
|
||||
} from 'native-base';
|
||||
import { ScrollView } from 'react-native';
|
||||
import {
|
||||
addNotification,
|
||||
NOTIFICATION_LEVEL_WARN,
|
||||
} from '../../store';
|
||||
|
||||
const styles = {
|
||||
root: {
|
||||
height: '100%',
|
||||
},
|
||||
positionsList: {
|
||||
height: '100%',
|
||||
paddingBottom: 100
|
||||
},
|
||||
positionsHeader: {
|
||||
fontWeight: 'bold',
|
||||
paddingTop: 5,
|
||||
paddingLeft: 10
|
||||
}
|
||||
};
|
||||
|
||||
export default class BaseCollect extends React.Component {
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import {
|
|||
} from '../../util';
|
||||
import EntityIcon from './EntityIcon';
|
||||
import { ErrSelectionCanceled } from "../../util/errors";
|
||||
|
||||
const styles = {
|
||||
mode: {
|
||||
[TypeRect]: { backgroundColor: '#D32F2F' },
|
||||
|
@ -316,13 +317,13 @@ class CollectSiteScreen extends React.Component {
|
|||
|
||||
onSavePress = () => {
|
||||
|
||||
const { dispatch } = this.props;
|
||||
const { dispatch, entities } = this.props;
|
||||
const { collect } = this;
|
||||
const { mode } = this.state;
|
||||
|
||||
if (!collect.validate()) return;
|
||||
|
||||
selectEntityType(mode)
|
||||
selectEntityType(entities, mode)
|
||||
.then(entity => {
|
||||
const positions = collect.getPositions();
|
||||
const { site } = this.props;
|
||||
|
@ -374,7 +375,8 @@ const mapStateToProp = (state, props) => {
|
|||
notebookPosition: state.position.notebook,
|
||||
moduleStatus: state.reachview.moduleStatus,
|
||||
useNotebookGPS: state.settings.useNotebookGPS,
|
||||
autoFollow: state.settings.autoFollow
|
||||
autoFollow: state.settings.autoFollow,
|
||||
entities: state.nomenclatures.entities,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -21,14 +21,14 @@ import { ErrSelectionCanceled } from "../../util/errors";
|
|||
class ExportSiteTab extends React.Component {
|
||||
|
||||
render() {
|
||||
const { entities } = this.props;
|
||||
const { entities, nomenclatures } = this.props;
|
||||
|
||||
const items = entities.map(e => {
|
||||
return (
|
||||
<ListItem icon key={e.uuid}>
|
||||
<Left><EntityIcon type={e.metadata.type} /></Left>
|
||||
<Body>
|
||||
<Text>{ getEntityCodeLabel(e.metadata.code) }</Text>
|
||||
<Text>{ getEntityCodeLabel(nomenclatures, e.metadata.code) }</Text>
|
||||
<Text note>{ moment(e.metadata.creationDate).fromNow() }</Text>
|
||||
</Body>
|
||||
</ListItem>
|
||||
|
@ -77,7 +77,8 @@ const mapStateToProp = (state, props) => {
|
|||
const { siteUUID } = props;
|
||||
return {
|
||||
site: selectSiteByUUID(state.sites.byUUID, siteUUID),
|
||||
entities: selectEntitiesBySiteUUID(state.entities.byUUID, siteUUID)
|
||||
entities: selectEntitiesBySiteUUID(state.entities.byUUID, siteUUID),
|
||||
nomenclatures: state.nomenclatures.entities,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -5,12 +5,11 @@ import {
|
|||
Text, Card, CardItem, Body,
|
||||
Button, View,
|
||||
} from 'native-base';
|
||||
import { askPermissions, cleanupPlans } from '../../store';
|
||||
import { askPermissions, cleanupPlans, startSync } from '../../store';
|
||||
import { PermissionsAndroid } from 'react-native';
|
||||
import MainRouter from './MainRouter';
|
||||
import { askWriteExternalStoragePermission } from '../../util';
|
||||
|
||||
const { GRANTED, DENIED, NEVER_ASK_AGAIN } = PermissionsAndroid.RESULTS;
|
||||
const { GRANTED, NEVER_ASK_AGAIN } = PermissionsAndroid.RESULTS;
|
||||
|
||||
const styles = {
|
||||
|
||||
|
@ -123,6 +122,7 @@ class SplashScreen extends React.Component {
|
|||
componentDidUpdate(prevProps) {
|
||||
if (!prevProps.isHydrated && this.props.isHydrated) {
|
||||
this.props.dispatch(cleanupPlans());
|
||||
this.props.dispatch(startSync());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,4 +5,5 @@ export * from './position';
|
|||
export * from './reachview';
|
||||
export * from './entity';
|
||||
export * from './permission';
|
||||
export * from './settings';
|
||||
export * from './settings';
|
||||
export * from './sync';
|
|
@ -0,0 +1,7 @@
|
|||
export const SYNC_REQUEST = 'SYNC_REQUEST';
|
||||
export const SYNC_SUCCESS = 'SYNC_SUCCESS';
|
||||
export const SYNC_FAILURE = 'SYNC_FAILURE';
|
||||
|
||||
export function startSync() {
|
||||
return { type: SYNC_REQUEST };
|
||||
}
|
|
@ -7,4 +7,5 @@ export positionReducer from './position';
|
|||
export reachviewReducer from './reachview';
|
||||
export entitiesReducer from './entities';
|
||||
export permissionReducer from './permission';
|
||||
export settingsReducer from './settings';
|
||||
export settingsReducer from './settings';
|
||||
export nomenclaturesReducer from './nomenclatures';
|
|
@ -0,0 +1,23 @@
|
|||
import defaultNomenclatures from '../../resources/nomenclatures.json';
|
||||
import { SYNC_SUCCESS } from '../actions/sync.js';
|
||||
|
||||
const defaultState = {
|
||||
entities: defaultNomenclatures.entities,
|
||||
};
|
||||
|
||||
export default function nomenclaturesReducer(state = defaultState, action) {
|
||||
switch(action.type) {
|
||||
case SYNC_SUCCESS:
|
||||
return handleSyncSuccess(state, action);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSyncSuccess(state, action) {
|
||||
const { nomenclatures } = action;
|
||||
return {
|
||||
...state,
|
||||
entities: [...nomenclatures.entities],
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import reachviewReducer from './reachview';
|
|||
import entitiesReducer from './entities';
|
||||
import permissionReducer from './permission';
|
||||
import settingsReducer from './settings';
|
||||
import nomenclaturesReducer from './nomenclatures';
|
||||
|
||||
export default combineReducers({
|
||||
wifiNetworks: wifiNetworksReducer,
|
||||
|
@ -19,4 +20,5 @@ export default combineReducers({
|
|||
entities: entitiesReducer,
|
||||
permission: permissionReducer,
|
||||
settings: settingsReducer,
|
||||
nomenclatures: nomenclaturesReducer,
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@ const defaultState = {
|
|||
wifiPassword: 'emlidreach',
|
||||
useNotebookGPS: false,
|
||||
autoFollow: false,
|
||||
nomenclaturesURL: 'https://fieldnotes.dev.lookingfora.name/field-surveys/nomenclatures.json'
|
||||
};
|
||||
|
||||
export default function settingsReducer(state = defaultState, action) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { permissionSaga } from './permission';
|
|||
import { reachviewSaga } from './reachview';
|
||||
import { positionSaga } from './position';
|
||||
import { planSaga } from './plan';
|
||||
import { syncSaga } from './sync';
|
||||
|
||||
export function* rootSaga() {
|
||||
yield all([
|
||||
|
@ -10,5 +11,6 @@ export function* rootSaga() {
|
|||
reachviewSaga(),
|
||||
positionSaga(),
|
||||
planSaga(),
|
||||
syncSaga()
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import { takeLatest, select, put, all, call } from 'redux-saga/effects'
|
||||
import {
|
||||
SYNC_REQUEST,
|
||||
SYNC_FAILURE,
|
||||
SYNC_SUCCESS
|
||||
} from '../actions';
|
||||
import { NetInfo } from 'react-native';
|
||||
import { Sentry } from 'react-native-sentry';
|
||||
|
||||
export function* syncSaga() {
|
||||
yield all([
|
||||
takeLatest(SYNC_REQUEST, doSync),
|
||||
])
|
||||
}
|
||||
|
||||
function* doSync() {
|
||||
try {
|
||||
|
||||
const isConnected = yield NetInfo.isConnected.fetch();
|
||||
|
||||
if (!isConnected) {
|
||||
yield put({ type: SYNC_FAILURE, err: new Error('No internet connectivity.') });
|
||||
return
|
||||
}
|
||||
|
||||
const [ nomenclatures ] = yield all([
|
||||
fetchNomenclaturesSaga(),
|
||||
])
|
||||
|
||||
yield put({ type: SYNC_SUCCESS, nomenclatures });
|
||||
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
yield put({ type: SYNC_FAILURE, err });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function* fetchNomenclaturesSaga() {
|
||||
const nomenclaturesURL = yield select(state => state.settings.nomenclaturesURL);
|
||||
const res = yield call(fetch, nomenclaturesURL, {
|
||||
headers: {
|
||||
'Pragma': 'no-cache',
|
||||
'Cache-Control': 'no-cache'
|
||||
}
|
||||
});
|
||||
const nomenclatures = yield res.json();
|
||||
return nomenclatures;
|
||||
}
|
|
@ -30,7 +30,7 @@ const store = createStore(
|
|||
...offlineConfig,
|
||||
persistOptions: {
|
||||
...offlineConfig.persistOptions,
|
||||
whitelist: ['sites', 'entities', 'settings']
|
||||
whitelist: ['sites', 'entities', 'settings', 'nomenclatures']
|
||||
}
|
||||
}),
|
||||
applyMiddleware(...reduxMiddlewares)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import nomenclatures from '../resources/nomenclatures.json';
|
||||
import { ActionSheet } from 'native-base';
|
||||
import { ErrSelectionCanceled } from './errors';
|
||||
|
||||
|
@ -7,9 +6,9 @@ export const TypeCurve = 'curve';
|
|||
export const TypeRect = 'rect';
|
||||
export const TypeCircle = 'circle';
|
||||
|
||||
export function selectEntityType(typeFilter) {
|
||||
export function selectEntityType(entities, typeFilter) {
|
||||
|
||||
const buttons = nomenclatures.entities.reduce((buttons, entityCategory) => {
|
||||
const buttons = entities.reduce((buttons, entityCategory) => {
|
||||
// Iterate over entity categories
|
||||
buttons.push(...entityCategory.types.reduce((buttons, entityType) => {
|
||||
|
||||
|
@ -48,8 +47,7 @@ export function selectEntityType(typeFilter) {
|
|||
});
|
||||
}
|
||||
|
||||
export function getEntityCategoryLabel(category) {
|
||||
const { entities } = nomenclatures;
|
||||
export function getEntityCategoryLabel(entities, category) {
|
||||
for (let c, i = 0; (c = entities[i]); ++i) {
|
||||
if (c.category === category) {
|
||||
return c.label;
|
||||
|
@ -58,8 +56,7 @@ export function getEntityCategoryLabel(category) {
|
|||
return `Catégorie inconnue (${category})`;
|
||||
}
|
||||
|
||||
export function getEntityCodeLabel(code) {
|
||||
const { entities } = nomenclatures;
|
||||
export function getEntityCodeLabel(entities, code) {
|
||||
for (let c, i = 0; (c = entities[i]); ++i) {
|
||||
for (let e, j = 0; (e = c.types[j]); ++j) {
|
||||
if (e.code === code) {
|
||||
|
|
Loading…
Reference in New Issue