2022-10-05 18:03:52 +02:00
|
|
|
import React from 'react';
|
2023-08-31 13:29:17 +02:00
|
|
|
import { Alert, Button, Linking, Text, View } from 'react-native';
|
2022-10-05 18:03:52 +02:00
|
|
|
// Redux
|
|
|
|
|
import { connect } from 'react-redux';
|
2022-12-28 17:53:43 +01:00
|
|
|
import { initContact } from '../Store/Actions/contacts';
|
2023-08-22 10:32:40 +02:00
|
|
|
import { initDirectories } from '../Store/Actions/directories';
|
2023-01-04 15:28:10 +01:00
|
|
|
import { initDocuments } from '../Store/Actions/documents';
|
2023-01-04 11:38:44 +01:00
|
|
|
// Sentry
|
2023-08-22 10:32:40 +02:00
|
|
|
import * as Sentry from '@sentry/react-native';
|
2022-10-05 18:03:52 +02:00
|
|
|
// Style
|
|
|
|
|
import styles from '../../Resources/Styles/SyncStyle';
|
|
|
|
|
// Translations
|
2023-08-22 10:32:40 +02:00
|
|
|
import i18n from '../../I18n';
|
|
|
|
|
// Controller
|
2022-10-05 18:03:52 +02:00
|
|
|
import SyncController from '../Controllers/SyncController';
|
|
|
|
|
// Progress
|
|
|
|
|
import * as Progress from 'react-native-progress';
|
2023-08-22 10:32:40 +02:00
|
|
|
// Database
|
|
|
|
|
import {
|
|
|
|
|
Contact,
|
|
|
|
|
Directory,
|
|
|
|
|
Document,
|
|
|
|
|
SendBrochure,
|
|
|
|
|
User,
|
|
|
|
|
} from '../../Database';
|
2022-10-06 16:25:15 +02:00
|
|
|
// FileSytem
|
|
|
|
|
import * as FileSystem from 'expo-file-system';
|
2022-10-05 18:03:52 +02:00
|
|
|
|
|
|
|
|
function mapStateToProps(state) {
|
2023-08-22 10:32:40 +02:00
|
|
|
return {
|
|
|
|
|
syncVersion: state.app.syncVersion,
|
|
|
|
|
currentUser: state.app.currentUser,
|
|
|
|
|
locale: state.locale.locale,
|
|
|
|
|
mainColor: state.app.mainColor,
|
|
|
|
|
directories: state.directories,
|
|
|
|
|
};
|
2022-10-05 18:03:52 +02:00
|
|
|
}
|
|
|
|
|
|
2022-12-28 16:32:30 +01:00
|
|
|
const mapDispatchToProps = dispatch => {
|
2023-08-22 10:32:40 +02:00
|
|
|
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,
|
|
|
|
|
}),
|
|
|
|
|
};
|
2022-12-28 16:32:30 +01:00
|
|
|
};
|
|
|
|
|
|
2022-10-05 18:03:52 +02:00
|
|
|
class SyncScreen extends React.Component {
|
2023-08-22 10:32:40 +02:00
|
|
|
state = {
|
|
|
|
|
progress: 0,
|
|
|
|
|
txtStep: '',
|
|
|
|
|
downloadProgress: 0,
|
|
|
|
|
downloadingFile: false,
|
|
|
|
|
processing: false,
|
|
|
|
|
newApp: false,
|
|
|
|
|
forced: false,
|
|
|
|
|
};
|
2022-10-05 18:03:52 +02:00
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
componentDidMount() {
|
|
|
|
|
const { forceSync } = this.props.route.params;
|
|
|
|
|
if (forceSync === true) {
|
|
|
|
|
this.setState({ forced: true });
|
|
|
|
|
this.sync();
|
2022-10-07 18:27:54 +02:00
|
|
|
}
|
2023-08-22 10:32:40 +02:00
|
|
|
}
|
2022-10-07 18:27:54 +02:00
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
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>
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-10-05 18:03:52 +02:00
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
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;
|
2022-10-05 18:03:52 +02:00
|
|
|
}
|
2023-08-22 10:32:40 +02:00
|
|
|
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;
|
2022-10-05 18:03:52 +02:00
|
|
|
}
|
2023-08-22 10:32:40 +02:00
|
|
|
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;
|
2022-10-06 16:25:15 +02:00
|
|
|
});
|
|
|
|
|
}
|
2023-08-22 10:32:40 +02:00
|
|
|
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;
|
2022-10-06 16:25:15 +02:00
|
|
|
}
|
2023-08-22 10:32:40 +02:00
|
|
|
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,
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-10-06 16:25:15 +02:00
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
fileProgress() {
|
|
|
|
|
if (this.state.downloadingFile === true) {
|
|
|
|
|
return this.state.downloadProgress + ' %';
|
2022-10-06 16:25:15 +02:00
|
|
|
}
|
2023-08-22 10:32:40 +02:00
|
|
|
}
|
2022-10-06 16:25:15 +02:00
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
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') + '.',
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-10-06 16:25:15 +02:00
|
|
|
});
|
2023-08-22 10:32:40 +02:00
|
|
|
} else {
|
|
|
|
|
this.deleteFile(toDelete, 0).then(status => {
|
|
|
|
|
this.setState({ progress: 1 });
|
|
|
|
|
this.finishSync(version);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-10-06 16:25:15 +02:00
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
async getToDL(docs, i, toDL = []) {
|
|
|
|
|
if (docs.length < 1) {
|
|
|
|
|
return toDL;
|
2022-10-06 16:25:15 +02:00
|
|
|
}
|
2023-08-22 10:32:40 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2022-10-06 16:25:15 +02:00
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2022-10-06 16:25:15 +02:00
|
|
|
}
|
2023-08-22 10:32:40 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callback(downloadProgress) {
|
|
|
|
|
let progress =
|
|
|
|
|
(downloadProgress.totalBytesWritten /
|
|
|
|
|
downloadProgress.totalBytesExpectedToWrite) *
|
|
|
|
|
100;
|
|
|
|
|
progress = Math.round(progress);
|
|
|
|
|
progress = progress.toString();
|
|
|
|
|
this.setState({
|
|
|
|
|
downloadProgress: progress,
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-10-06 16:25:15 +02:00
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
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;
|
2022-10-06 16:25:15 +02:00
|
|
|
}
|
2023-08-22 10:32:40 +02:00
|
|
|
}
|
2022-10-06 16:25:15 +02:00
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
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 },
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-05 18:03:52 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-22 10:32:40 +02:00
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(SyncScreen);
|