Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56c783020d | |||
| 43106f0081 | |||
| df6bc575d0 | |||
| d77cb17f1d | |||
| bcc8ebd7e2 | |||
| a54dad9b1d | |||
| bb83785e56 | |||
| 0a80b30388 |
@@ -0,0 +1,33 @@
|
|||||||
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
|
import AppLoadingView from '../../common/app-loading'
|
||||||
|
import AppPage from '../../common/app-page'
|
||||||
|
import DeleteData from './DeleteData'
|
||||||
|
import ImportData from './ImportData'
|
||||||
|
import ExportData from './ExportData'
|
||||||
|
|
||||||
|
const DataManagement = () => {
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [isDeletingData, setIsDeletingData] = useState(false)
|
||||||
|
|
||||||
|
if (isLoading) return <AppLoadingView />
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppPage>
|
||||||
|
<ExportData
|
||||||
|
resetIsDeletingData={() => setIsDeletingData(false)}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
|
/>
|
||||||
|
<ImportData
|
||||||
|
resetIsDeletingData={() => setIsDeletingData(false)}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
|
/>
|
||||||
|
<DeleteData
|
||||||
|
isDeletingData={isDeletingData}
|
||||||
|
onStartDeletion={() => setIsDeletingData(true)}
|
||||||
|
/>
|
||||||
|
</AppPage>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DataManagement
|
||||||
+17
-12
@@ -11,9 +11,10 @@ import alertError from '../common/alert-error'
|
|||||||
import { clearDb, isDbEmpty } from '../../../db'
|
import { clearDb, isDbEmpty } from '../../../db'
|
||||||
import { showToast } from '../../helpers/general'
|
import { showToast } from '../../helpers/general'
|
||||||
import { hasEncryptionObservable } from '../../../local-storage'
|
import { hasEncryptionObservable } from '../../../local-storage'
|
||||||
import settings from '../../../i18n/en/settings'
|
|
||||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
|
||||||
import { EXPORT_FILE_NAME } from './constants'
|
import { EXPORT_FILE_NAME } from './constants'
|
||||||
|
import Segment from '../../common/segment'
|
||||||
|
import AppText from '../../common/app-text'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
const exportedFilePath = `${RNFS.DocumentDirectoryPath}/${EXPORT_FILE_NAME}`
|
const exportedFilePath = `${RNFS.DocumentDirectoryPath}/${EXPORT_FILE_NAME}`
|
||||||
|
|
||||||
@@ -22,6 +23,10 @@ const DeleteData = ({ onStartDeletion, isDeletingData }) => {
|
|||||||
const [isConfirmingWithPassword, setIsConfirmingWithPassword] =
|
const [isConfirmingWithPassword, setIsConfirmingWithPassword] =
|
||||||
useState(false)
|
useState(false)
|
||||||
|
|
||||||
|
const { t } = useTranslation(null, {
|
||||||
|
keyPrefix: 'hamburgerMenu.settings.data.delete',
|
||||||
|
})
|
||||||
|
|
||||||
const onAlertConfirmation = () => {
|
const onAlertConfirmation = () => {
|
||||||
onStartDeletion()
|
onStartDeletion()
|
||||||
if (isPasswordSet) {
|
if (isPasswordSet) {
|
||||||
@@ -32,17 +37,16 @@ const DeleteData = ({ onStartDeletion, isDeletingData }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const alertBeforeDeletion = async () => {
|
const alertBeforeDeletion = async () => {
|
||||||
const { question, message, confirmation, errors } = settings.deleteSegment
|
|
||||||
if (isDbEmpty() && !(await RNFS.exists(exportedFilePath))) {
|
if (isDbEmpty() && !(await RNFS.exists(exportedFilePath))) {
|
||||||
alertError(errors.noData)
|
alertError(t('error.noData'))
|
||||||
} else {
|
} else {
|
||||||
Alert.alert(question, message, [
|
Alert.alert(t('dialog.title'), t('dialog.message'), [
|
||||||
{
|
{
|
||||||
text: confirmation,
|
text: t('dialog.delete'),
|
||||||
onPress: onAlertConfirmation,
|
onPress: onAlertConfirmation,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: sharedLabels.cancel,
|
text: t('dialog.cancel'),
|
||||||
style: 'cancel',
|
style: 'cancel',
|
||||||
onPress: cancelConfirmationWithPassword,
|
onPress: cancelConfirmationWithPassword,
|
||||||
},
|
},
|
||||||
@@ -57,16 +61,14 @@ const DeleteData = ({ onStartDeletion, isDeletingData }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const deleteAppData = async () => {
|
const deleteAppData = async () => {
|
||||||
const { errors, success } = settings.deleteSegment
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!isDbEmpty()) {
|
if (!isDbEmpty()) {
|
||||||
clearDb()
|
clearDb()
|
||||||
}
|
}
|
||||||
await deleteExportedFile()
|
await deleteExportedFile()
|
||||||
showToast(success.message)
|
showToast(t('success.message'))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alertError(errors.couldNotDeleteFile)
|
alertError(t('error.delete'))
|
||||||
}
|
}
|
||||||
cancelConfirmationWithPassword()
|
cancelConfirmationWithPassword()
|
||||||
}
|
}
|
||||||
@@ -85,9 +87,12 @@ const DeleteData = ({ onStartDeletion, isDeletingData }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Segment title={t('title')} last>
|
||||||
|
<AppText>{t('subTitle')}</AppText>
|
||||||
<Button isCTA onPress={alertBeforeDeletion}>
|
<Button isCTA onPress={alertBeforeDeletion}>
|
||||||
{settings.deleteSegment.title}
|
{t('title')}
|
||||||
</Button>
|
</Button>
|
||||||
|
</Segment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { getCycleDaysSortedByDate, mapRealmObjToJsObj } from '../../../db'
|
||||||
|
import getDataAsCsvDataUri from '../../../lib/import-export/export-to-csv'
|
||||||
|
import alertError from '../common/alert-error'
|
||||||
|
import { EXPORT_FILE_NAME } from './constants'
|
||||||
|
import RNFS from 'react-native-fs'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import AppText from '../../common/app-text'
|
||||||
|
import Button from '../../common/button'
|
||||||
|
import Segment from '../../common/segment'
|
||||||
|
import Share from 'react-native-share'
|
||||||
|
|
||||||
|
export default function ExportData({ setIsLoading, resetIsDeletingData }) {
|
||||||
|
const { t } = useTranslation(null, {
|
||||||
|
keyPrefix: 'hamburgerMenu.settings.data.export',
|
||||||
|
})
|
||||||
|
|
||||||
|
async function startExport() {
|
||||||
|
resetIsDeletingData()
|
||||||
|
setIsLoading(true)
|
||||||
|
await exportData()
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getData() {
|
||||||
|
const cycleDaysByDate = mapRealmObjToJsObj(getCycleDaysSortedByDate())
|
||||||
|
|
||||||
|
try {
|
||||||
|
return cycleDaysByDate.length
|
||||||
|
? getDataAsCsvDataUri(cycleDaysByDate)
|
||||||
|
: null
|
||||||
|
} catch (err) {
|
||||||
|
alertError(t('error.convert'))
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exportData() {
|
||||||
|
const data = await getData()
|
||||||
|
if (!data) {
|
||||||
|
alertError(t('error.data'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const path = `${RNFS.DocumentDirectoryPath}/${EXPORT_FILE_NAME}`
|
||||||
|
await RNFS.writeFile(path, data)
|
||||||
|
|
||||||
|
await Share.open({
|
||||||
|
title: t('title'),
|
||||||
|
url: `file://${path}`,
|
||||||
|
subject: t('title'),
|
||||||
|
type: 'text/csv',
|
||||||
|
showAppsToView: true,
|
||||||
|
failOnCancel: false,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
return alertError(t('error.share'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Segment title={t('button')}>
|
||||||
|
<AppText>{t('text')}</AppText>
|
||||||
|
<Button isCTA onPress={startExport}>
|
||||||
|
{t('button')}
|
||||||
|
</Button>
|
||||||
|
</Segment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportData.propTypes = {
|
||||||
|
resetIsDeletingData: PropTypes.func.isRequired,
|
||||||
|
setIsLoading: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { Alert } from 'react-native'
|
||||||
|
import DocumentPicker from 'react-native-document-picker'
|
||||||
|
import rnfs from 'react-native-fs'
|
||||||
|
import importCsv from '../../../lib/import-export/import-from-csv'
|
||||||
|
import alertError from '../common/alert-error'
|
||||||
|
import Segment from '../../common/segment'
|
||||||
|
import AppText from '../../common/app-text'
|
||||||
|
import Button from '../../common/button'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
export default function ImportData({ resetIsDeletingData, setIsLoading }) {
|
||||||
|
const { t } = useTranslation(null, {
|
||||||
|
keyPrefix: 'hamburgerMenu.settings.data.import',
|
||||||
|
})
|
||||||
|
|
||||||
|
async function startImport(shouldDeleteExistingData) {
|
||||||
|
setIsLoading(true)
|
||||||
|
await importData(shouldDeleteExistingData)
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFileInfo() {
|
||||||
|
try {
|
||||||
|
const fileInfo = await DocumentPicker.pickSingle({
|
||||||
|
type: [DocumentPicker.types.csv, 'text/comma-separated-values'],
|
||||||
|
})
|
||||||
|
return fileInfo
|
||||||
|
} catch (error) {
|
||||||
|
if (DocumentPicker.isCancel(error)) return // User cancelled the picker, exit any dialogs or menus and move on
|
||||||
|
showImportErrorAlert(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFileContent() {
|
||||||
|
const fileInfo = await getFileInfo()
|
||||||
|
if (!fileInfo) return null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fileContent = await rnfs.readFile(fileInfo.uri, 'utf8')
|
||||||
|
return fileContent
|
||||||
|
} catch (err) {
|
||||||
|
return showImportErrorAlert(t('errors.couldNotOpenFile'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function importData(shouldDeleteExistingData) {
|
||||||
|
const fileContent = await getFileContent()
|
||||||
|
if (!fileContent) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
await importCsv(fileContent, shouldDeleteExistingData)
|
||||||
|
Alert.alert(t('success.title'), t('success.message'))
|
||||||
|
} catch (err) {
|
||||||
|
showImportErrorAlert(err.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openImportDialog() {
|
||||||
|
resetIsDeletingData()
|
||||||
|
Alert.alert(t('dialog.title'), t('dialog.message'), [
|
||||||
|
{
|
||||||
|
text: t('dialog.cancel'),
|
||||||
|
style: 'cancel',
|
||||||
|
onPress: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: t('dialog.replace'),
|
||||||
|
onPress: () => startImport(false),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: t('dialog.delete'),
|
||||||
|
onPress: () => startImport(true),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
function showImportErrorAlert(message) {
|
||||||
|
const errorMessage = t('errors.noDataImported', { message })
|
||||||
|
alertError(errorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Segment title={t('button')}>
|
||||||
|
<AppText>{t('segmentExplainer')}</AppText>
|
||||||
|
<Button isCTA onPress={openImportDialog}>
|
||||||
|
{t('button')}
|
||||||
|
</Button>
|
||||||
|
</Segment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportData.propTypes = {
|
||||||
|
resetIsDeletingData: PropTypes.func.isRequired,
|
||||||
|
setIsLoading: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import Share from 'react-native-share'
|
|
||||||
|
|
||||||
import { getCycleDaysSortedByDate, mapRealmObjToJsObj } from '../../../db'
|
|
||||||
import getDataAsCsvDataUri from '../../../lib/import-export/export-to-csv'
|
|
||||||
import alertError from '../common/alert-error'
|
|
||||||
import settings from '../../../i18n/en/settings'
|
|
||||||
import { EXPORT_FILE_NAME } from './constants'
|
|
||||||
import RNFS from 'react-native-fs'
|
|
||||||
|
|
||||||
export default async function exportData() {
|
|
||||||
let data
|
|
||||||
const labels = settings.export
|
|
||||||
const cycleDaysByDate = mapRealmObjToJsObj(getCycleDaysSortedByDate())
|
|
||||||
|
|
||||||
if (!cycleDaysByDate.length) return alertError(labels.errors.noData)
|
|
||||||
|
|
||||||
try {
|
|
||||||
data = getDataAsCsvDataUri(cycleDaysByDate)
|
|
||||||
if (!data) {
|
|
||||||
return alertError(labels.errors.noData)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err)
|
|
||||||
return alertError(labels.errors.couldNotConvert)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const path = `${RNFS.DocumentDirectoryPath}/${EXPORT_FILE_NAME}`
|
|
||||||
await RNFS.writeFile(path, data)
|
|
||||||
|
|
||||||
await Share.open({
|
|
||||||
title: labels.title,
|
|
||||||
url: `file://${path}`,
|
|
||||||
subject: labels.subject,
|
|
||||||
type: 'text/csv',
|
|
||||||
showAppsToView: true,
|
|
||||||
failOnCancel: false,
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err)
|
|
||||||
return alertError(labels.errors.problemSharing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import { Alert } from 'react-native'
|
|
||||||
import DocumentPicker from 'react-native-document-picker'
|
|
||||||
import rnfs from 'react-native-fs'
|
|
||||||
import importCsv from '../../../lib/import-export/import-from-csv'
|
|
||||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
|
||||||
import labels from '../../../i18n/en/settings'
|
|
||||||
import alertError from '../common/alert-error'
|
|
||||||
|
|
||||||
export function openImportDialog(onImportData) {
|
|
||||||
Alert.alert(labels.import.title, labels.import.message, [
|
|
||||||
{
|
|
||||||
text: sharedLabels.cancel,
|
|
||||||
style: 'cancel',
|
|
||||||
onPress: () => {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: labels.import.replaceOption,
|
|
||||||
onPress: () => onImportData(false),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: labels.import.deleteOption,
|
|
||||||
onPress: () => onImportData(true),
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getFileContent() {
|
|
||||||
let fileInfo
|
|
||||||
try {
|
|
||||||
fileInfo = await DocumentPicker.pickSingle({
|
|
||||||
type: [DocumentPicker.types.csv, 'text/comma-separated-values'],
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
if (DocumentPicker.isCancel(error)) {
|
|
||||||
// User cancelled the picker, exit any dialogs or menus and move on
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
importError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let fileContent
|
|
||||||
try {
|
|
||||||
fileContent = await rnfs.readFile(fileInfo.uri, 'utf8')
|
|
||||||
} catch (err) {
|
|
||||||
return importError(labels.import.errors.couldNotOpenFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileContent
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function importData(shouldDeleteExistingData, fileContent) {
|
|
||||||
try {
|
|
||||||
await importCsv(fileContent, shouldDeleteExistingData)
|
|
||||||
Alert.alert(sharedLabels.successTitle, labels.import.success.message)
|
|
||||||
} catch (err) {
|
|
||||||
importError(err.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function importError(msg) {
|
|
||||||
const postFixed = `${msg}\n\n${labels.import.errors.postFix}`
|
|
||||||
alertError(postFixed)
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import React, { useState } from 'react'
|
|
||||||
|
|
||||||
import AppLoadingView from '../../common/app-loading'
|
|
||||||
import AppPage from '../../common/app-page'
|
|
||||||
import AppText from '../../common/app-text'
|
|
||||||
import Button from '../../common/button'
|
|
||||||
import Segment from '../../common/segment'
|
|
||||||
|
|
||||||
import { openImportDialog, getFileContent, importData } from './import-dialog'
|
|
||||||
import openShareDialogAndExport from './export-dialog'
|
|
||||||
import DeleteData from './delete-data'
|
|
||||||
|
|
||||||
import labels from '../../../i18n/en/settings'
|
|
||||||
import { ACTION_DELETE, ACTION_EXPORT, ACTION_IMPORT } from '../../../config'
|
|
||||||
|
|
||||||
const DataManagement = () => {
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
|
||||||
const [currentAction, setCurrentAction] = useState(null)
|
|
||||||
|
|
||||||
const startImportFlow = async (shouldDeleteExistingData) => {
|
|
||||||
setIsLoading(true)
|
|
||||||
const fileContent = await getFileContent()
|
|
||||||
if (fileContent) {
|
|
||||||
await importData(shouldDeleteExistingData, fileContent)
|
|
||||||
}
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
const startExport = () => {
|
|
||||||
setCurrentAction(ACTION_EXPORT)
|
|
||||||
openShareDialogAndExport()
|
|
||||||
}
|
|
||||||
|
|
||||||
const startImport = () => {
|
|
||||||
setCurrentAction(ACTION_IMPORT)
|
|
||||||
openImportDialog(startImportFlow)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLoading) return <AppLoadingView />
|
|
||||||
|
|
||||||
const isDeletingData = currentAction === ACTION_DELETE
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AppPage>
|
|
||||||
<Segment title={labels.export.button}>
|
|
||||||
<AppText>{labels.export.segmentExplainer}</AppText>
|
|
||||||
<Button isCTA onPress={startExport}>
|
|
||||||
{labels.export.button}
|
|
||||||
</Button>
|
|
||||||
</Segment>
|
|
||||||
<Segment title={labels.import.button}>
|
|
||||||
<AppText>{labels.import.segmentExplainer}</AppText>
|
|
||||||
<Button isCTA onPress={startImport}>
|
|
||||||
{labels.import.button}
|
|
||||||
</Button>
|
|
||||||
</Segment>
|
|
||||||
<Segment title={labels.deleteSegment.title} last>
|
|
||||||
<AppText>{labels.deleteSegment.explainer}</AppText>
|
|
||||||
<DeleteData
|
|
||||||
isDeletingData={isDeletingData}
|
|
||||||
onStartDeletion={() => setCurrentAction(ACTION_DELETE)}
|
|
||||||
/>
|
|
||||||
</Segment>
|
|
||||||
</AppPage>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DataManagement
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Reminders from './reminders/reminders'
|
import Reminders from './reminders/reminders'
|
||||||
import NfpSettings from './nfp-settings'
|
import NfpSettings from './nfp-settings'
|
||||||
import DataManagement from './data-management'
|
import DataManagement from './data-management/DataManagement'
|
||||||
import Password from './password'
|
import Password from './password'
|
||||||
import About from './About'
|
import About from './About'
|
||||||
import License from './License'
|
import License from './License'
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import { PixelRatio, StatusBar } from 'react-native'
|
import { PixelRatio, StatusBar } from 'react-native'
|
||||||
import { scale, verticalScale } from 'react-native-size-matters'
|
import { scale, verticalScale } from 'react-native-size-matters'
|
||||||
|
|
||||||
export const ACTION_DELETE = 'delete'
|
|
||||||
export const ACTION_EXPORT = 'export'
|
|
||||||
export const ACTION_IMPORT = 'import'
|
|
||||||
|
|
||||||
export const SYMPTOMS = [
|
export const SYMPTOMS = [
|
||||||
'bleeding',
|
'bleeding',
|
||||||
'temperature',
|
'temperature',
|
||||||
@@ -40,7 +36,7 @@ export const HIT_SLOP = {
|
|||||||
top: verticalScale(20),
|
top: verticalScale(20),
|
||||||
bottom: verticalScale(20),
|
bottom: verticalScale(20),
|
||||||
left: scale(20),
|
left: scale(20),
|
||||||
right: scale(20)
|
right: scale(20),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const STATUSBAR_HEIGHT = StatusBar.currentHeight
|
export const STATUSBAR_HEIGHT = StatusBar.currentHeight
|
||||||
|
|||||||
@@ -80,6 +80,55 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"data": {
|
||||||
|
"delete": {
|
||||||
|
"dialog": {
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"delete": "Delete app data permanently",
|
||||||
|
"message": "Please note that deletion of the app data is permanent and irreversible. We recommend exporting existing data before deletion.",
|
||||||
|
"title": "Do you want to delete app data from this phone?"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"delete": "Could not delete data",
|
||||||
|
"noData": "There is no data to delete"
|
||||||
|
},
|
||||||
|
"subTitle": "Delete app data from this phone",
|
||||||
|
"success": {
|
||||||
|
"message": "App data successfully deleted"
|
||||||
|
},
|
||||||
|
"title": "Delete app data"
|
||||||
|
},
|
||||||
|
"export": {
|
||||||
|
"button": "Export data",
|
||||||
|
"error": {
|
||||||
|
"convert": "Could not convert data to CSV",
|
||||||
|
"data": "There is no data to export",
|
||||||
|
"share": "There was a problem sharing the data export file"
|
||||||
|
},
|
||||||
|
"text": "Export data in CSV format for backup or so you can use it elsewhere",
|
||||||
|
"title": "My drip. data export"
|
||||||
|
},
|
||||||
|
"import": {
|
||||||
|
"button": "Import data",
|
||||||
|
"dialog": {
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"delete": "Import and delete existing",
|
||||||
|
"message": "There are two options for the import:\n\n1. Keep existing cycle days and replace only the ones in the import file.\n\n2. Delete all existing cycle days and import cycle days from file",
|
||||||
|
"replace": "Import and replace",
|
||||||
|
"title": "Keep existing data?"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"couldNotOpenFile": "Could not open file",
|
||||||
|
"futureEdit": "Future dates may only contain a note, no other symptoms",
|
||||||
|
"noDataImported": "{{message}}\n\nNo data was imported or changed"
|
||||||
|
},
|
||||||
|
"segmentExplainer": "Import data in CSV format",
|
||||||
|
"success": {
|
||||||
|
"message": "Data successfully imported",
|
||||||
|
"title": "Success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"menuItem": {
|
"menuItem": {
|
||||||
"dataManagement": {
|
"dataManagement": {
|
||||||
"name": "Data",
|
"name": "Data",
|
||||||
|
|||||||
@@ -19,52 +19,6 @@ export default {
|
|||||||
text: '',
|
text: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
export: {
|
|
||||||
errors: {
|
|
||||||
noData: 'There is no data to export',
|
|
||||||
couldNotConvert: 'Could not convert data to CSV',
|
|
||||||
problemSharing: 'There was a problem sharing the data export file',
|
|
||||||
},
|
|
||||||
title: 'My drip. data export',
|
|
||||||
subject: 'My drip. data export',
|
|
||||||
button: 'Export data',
|
|
||||||
segmentExplainer:
|
|
||||||
'Export data in CSV format for backup or so you can use it elsewhere',
|
|
||||||
},
|
|
||||||
import: {
|
|
||||||
button: 'Import data',
|
|
||||||
title: 'Keep existing data?',
|
|
||||||
message: `There are two options for the import:
|
|
||||||
1. Keep existing cycle days and replace only the ones in the import file.
|
|
||||||
2. Delete all existing cycle days and import cycle days from file.`,
|
|
||||||
replaceOption: 'Import and replace',
|
|
||||||
deleteOption: 'Import and delete existing',
|
|
||||||
errors: {
|
|
||||||
couldNotOpenFile: 'Could not open file',
|
|
||||||
postFix: 'No data was imported or changed',
|
|
||||||
futureEdit: 'Future dates may only contain a note, no other symptoms',
|
|
||||||
},
|
|
||||||
success: {
|
|
||||||
message: 'Data successfully imported',
|
|
||||||
},
|
|
||||||
segmentExplainer: 'Import data in CSV format',
|
|
||||||
},
|
|
||||||
deleteSegment: {
|
|
||||||
title: 'Delete app data',
|
|
||||||
explainer: 'Delete app data from this phone',
|
|
||||||
question: 'Do you want to delete app data from this phone?',
|
|
||||||
message:
|
|
||||||
'Please note that deletion of the app data is permanent and irreversible. We recommend exporting existing data before deletion.',
|
|
||||||
confirmation: 'Delete app data permanently',
|
|
||||||
errors: {
|
|
||||||
couldNotDeleteFile: 'Could not delete data',
|
|
||||||
postFix: 'No data was deleted or changed',
|
|
||||||
noData: 'There is no data to delete',
|
|
||||||
},
|
|
||||||
success: {
|
|
||||||
message: 'App data successfully deleted',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tempScale: {
|
tempScale: {
|
||||||
segmentTitle: 'Temperature scale',
|
segmentTitle: 'Temperature scale',
|
||||||
segmentExplainer:
|
segmentExplainer:
|
||||||
|
|||||||
Reference in New Issue
Block a user