ldc-com-app/ComApp/src/App/Views/SyncScreen.js
2023-08-22 10:32:40 +02:00

423 lines
11 KiB
JavaScript

import React from 'react';
import { Alert, Button, Text, View } from 'react-native';
// Redux
import { connect } from 'react-redux';
import { initContact } from '../Store/Actions/contacts';
import { initDirectories } from '../Store/Actions/directories';
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 {
Contact,
Directory,
Document,
SendBrochure,
User,
} 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);