ldc-com-app/ComApp/src/App/Views/SyncScreen.js
2023-01-04 15:28:10 +01:00

379 lines
No EOL
13 KiB
JavaScript

import React from 'react';
import { View, Button, Alert, Text } from 'react-native';
// Redux
import { connect } from 'react-redux';
import { initDirectories } from '../Store/Actions/directories';
import { initContact } from '../Store/Actions/contacts';
import { initDocuments } from '../Store/Actions/documents';
// Sentry
import * as Sentry from "@sentry/react-native";
// Style
import styles from '../../Resources/Styles/SyncStyle';
// Translations
import i18n from "../../I18n";
// Controller
import SyncController from '../Controllers/SyncController';
// Progress
import * as Progress from 'react-native-progress';
// Database
import { User, Contact, Directory, Document, SendBrochure } from '../../Database';
// FileSytem
import * as FileSystem from 'expo-file-system';
function mapStateToProps(state) {
return {
syncVersion: state.app.syncVersion,
currentUser: state.app.currentUser,
locale: state.locale.locale,
mainColor: state.app.mainColor,
directories: state.directories
};
}
const mapDispatchToProps = dispatch => {
return {
init: () => dispatch({ type: 'INIT' }),
initUsers: () => dispatch({ type: 'INIT_USERS' }),
initDirectories: (lang, user) => dispatch(initDirectories(lang, user)),
initDocuments: (lang, directories) => dispatch(initDocuments(lang, directories)),
initContact: currentUser => dispatch(initContact(currentUser)),
initBtns: () => dispatch({ type: 'INIT_HOME_BTNS' }),
updateVersion: version => dispatch({
type: 'UPDATE_VERSION',
data: version,
}),
updateShowIsActive: value => dispatch({
type: 'UPDATE_SHOW_IS_ACTIVE',
data: value,
})
};
};
class SyncScreen extends React.Component {
state = {
progress: 0,
txtStep: '',
downloadProgress: 0,
downloadingFile: false,
processing: false,
newApp: false,
forced: false
};
componentDidMount() {
const { forceSync } = this.props.route.params;
if (forceSync === true) {
this.setState({ forced: true });
this.sync();
}
}
render() {
const fileProgress = this.fileProgress();
return (
<View style={styles.container}>
<Progress.Circle
size={250}
progress={this.state.progress}
showsText={true}
color={this.props.mainColor}
/>
<View style={styles.btnWrapper}>
<Button
disabled={this.state.processing}
color={this.props.mainColor}
title={i18n.t('sync_s.start_sync')}
onPress={() => this.sync()}
/>
</View>
<View style={styles.btnWrapper}>
<Text>
{this.state.txtStep} {fileProgress}
</Text>
</View>
</View>
);
}
async sync() {
let errorStatus = false;
const isConnected = await SyncController.checkConnection().then(state => {
//console.log(state.isConnected)
return state.isConnected
}).catch(error => {
//console.log(error);
return false;
});
if (!isConnected) {
Alert.alert(
i18n.t('global.warning'),
i18n.t('error.must_be_connected_internet_sync')
);
return;
}
this.setState({ processing: true });
// getVersion
const resVersion = await SyncController.getVersion().then(res => {
return res.data;
}).catch(error => {
Sentry.captureException(error);
Alert.alert(
i18n.t('error.error'),
i18n.t('error.error_has_occurred')
);
errorStatus = true
});
if (errorStatus) {
return false;
}
this.props.updateVersion(resVersion.version);
this.props.updateShowIsActive(resVersion.ShowIsActive);
this.setState({ newApp: resVersion.newApp });
// getUsers
this.setState({ txtStep: i18n.t('sync_s.updating_users') + '...' });
const resUsers = await SyncController.getUsers().then(res => {
User.clear();
return res.data;
}).catch(error => {
Sentry.captureException(error);
Alert.alert(
i18n.t('error.error'),
i18n.t('error.error_has_occurred')
);
errorStatus = true
});
if (errorStatus) {
return false;
}
resUsers.forEach(user => {
User.add(user);
});
// getContacts
this.setState({ progress: 0.1, txtStep: i18n.t('sync_s.updating_contacts') + '...' });
const resContacts = await SyncController.getContacts(this.props.currentUser.id).then(res => {
Contact.clear();
return res.data;
}).catch(error => {
Sentry.captureException(error);
Alert.alert(
i18n.t('error.error'),
i18n.t('error.error_has_occurred')
);
errorStatus = true
});
if (errorStatus) {
return false;
}
resContacts.forEach(contact => {
Contact.add(contact);
});
//sendBrochures
this.setState({ progress: 0.2, txtStep: i18n.t('sync_s.sending_flyers') + '...' });
let brochures = SendBrochure.getAll();
for (const brochure of brochures) {
await SyncController.sendBrochure(brochure).then(res => {
SendBrochure.delete(brochure.id);
}).catch(error => {
Sentry.captureException(error);
Alert.alert(
i18n.t('error.error'),
i18n.t('error.error_has_occurred') + ' : Brochures'
);
errorStatus = true;
});
}
if (errorStatus) {
return false;
}
//getDirectories
this.setState({ progress: 0.3, txtStep: i18n.t('sync_s.updating_folders') + '...' });
const resDirectories = await SyncController.getDirectories().then(res => {
Directory.clear();
return res.data;
}).catch(error => {
Sentry.captureException(error);
Alert.alert(
i18n.t('error.error'),
i18n.t('error.error_has_occurred')
);
errorStatus = true
});
if (errorStatus) {
return false;
}
resDirectories.forEach(dir => {
Directory.add(dir);
});
// getDocuments
this.setState({ progress: 0.4, txtStep: i18n.t('sync_s.updating_docs') + '...' });
const resDocuments = await SyncController.getDocuments().then(res => {
return res.data;
}).catch(error => {
Sentry.captureException(error);
Alert.alert(
i18n.t('error.error'),
i18n.t('error.error_has_occurred')
);
errorStatus = true
});
if (errorStatus) {
return false;
}
const toDelete = Document.clear(resDocuments);
resDocuments.forEach(document => {
Document.update(document);
});
this.downloadDocuments(Document.getAll(), toDelete);
// End
this.setState({ txtStep: i18n.t('sync_s.update_completed') + '.', processing: false });
}
fileProgress() {
if (this.state.downloadingFile === true) {
return this.state.downloadProgress + ' %';
}
}
downloadDocuments(docs, toDelete) {
const version = this.props.syncVersion;
this.getToDL(docs, 0).then(toDownload => {
if (toDownload.length > 0) {
this.setState({ progress: 0.5 });
const docProgress = 0.5 / toDownload.length;
this.download(toDownload, docProgress, 0).then(status => {
if (status === true) {
this.deleteFile(toDelete, 0).then(status => {
this.finishSync(version);
});
} else {
this.setState({ txtStep: i18n.t('error.error_has_occurred') + '.' });
}
});
} else {
this.deleteFile(toDelete, 0).then(status => {
this.setState({ progress: 1 });
this.finishSync(version);
});
}
});
}
async getToDL(docs, i, toDL = []) {
if (docs.length < 1)
return toDL;
const item = docs[i];
const { exists, modificationTime } = await FileSystem.getInfoAsync(FileSystem.documentDirectory + item.uuid + '.' + item.type);
if (exists === false) {
toDL.push(item);
} else {
if (modificationTime.toString() !== item.updated_at) {
toDL.push(item);
}
}
if (i < docs.length - 1) {
return this.getToDL(docs, i + 1, toDL);
}
return toDL;
}
async deleteFile(docs, i) {
if (docs.length > 0) {
const file = docs[i];
await FileSystem.deleteAsync(FileSystem.documentDirectory + file.uuid + '.' + file.type, { idempotent: true });
if (i < docs.length - 1) {
return this.deleteFile(docs, i + 1);
}
}
return true;
}
callback(downloadProgress) {
let progress =
(downloadProgress.totalBytesWritten /
downloadProgress.totalBytesExpectedToWrite) *
100;
progress = Math.round(progress);
progress = progress.toString();
this.setState({
downloadProgress: progress,
});
}
downloadResumable(url, uuid, type) {
return FileSystem.createDownloadResumable(
url,
FileSystem.documentDirectory + uuid + '.' + type,
{},
this.callback.bind(this),
);
}
async download(documents, progress, i) {
if (this.state.downloadingFile === false) {
this.setState({ downloadingFile: true });
}
const endpoint = SyncController.getUrlBo() + '/storage/docs/'
const doc = documents[i];
this.setState({
txtStep:
i18n.t('sync_s.download') + ' : ' +
doc.title +
' (' +
doc.type.toUpperCase() +
') ...',
});
try {
await this.downloadResumable(
endpoint + doc.uuid + "." + doc.type,
doc.uuid,
doc.type,
).downloadAsync();
const { modificationTime } = await FileSystem.getInfoAsync(FileSystem.documentDirectory + doc.uuid + '.' + doc.type);
SyncController.updateLastModificationDoc(doc.id, modificationTime);
//console.log('Finished downloading to ', uri);
this.setState({ progress: this.state.progress + progress });
if (i < documents.length - 1) {
return this.download(documents, progress, i + 1);
}
this.setState({ downloadingFile: false });
return true;
} catch (e) {
console.error(e);
return false;
}
}
finishSync(version) {
this.props.init();
this.props.initUsers();
this.props.initContact(this.props.currentUser);
this.props.initDirectories(this.props.locale, this.props.currentUser);
this.props.initDocuments(this.props.locale, this.props.directories.global);
this.props.initBtns();
if (this.state.forced) {
SyncController.setInstalled();
}
SyncController.updateVersion(version);
this.setState({ txtStep: i18n.t('sync_s.update_completed') + '.', processing: false });
if (this.state.newApp === true) {
const appUUID = SyncController.getAppStoreUUID();
const url = 'https://store.ldc.fr' + '/app/' + appUUID;
Alert.alert(
'LDC Store',
i18n.t('sync_s.new_app_version'),
[
{
text: i18n.t('global.cancel'),
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{ text: i18n.t('sync_s.open_store'), onPress: () => Linking.openURL(url).catch((err) => console.error('An error occurred', err)) },
],
{ cancelable: false },
);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SyncScreen);