Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e2d6387647 | |||
| b6024ae921 | |||
| d17e7ed6a2 |
@@ -5,7 +5,7 @@ buildscript {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
ext.kotlinVersion = "1.3.10"
|
||||
ext.kotlinVersion = "1.4.20"
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:4.2.2")
|
||||
|
||||
@@ -31,7 +31,7 @@ allprojects {
|
||||
content {
|
||||
excludeGroup "com.facebook.react"
|
||||
}
|
||||
}
|
||||
}
|
||||
google()
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
maven {
|
||||
@@ -53,5 +53,5 @@ ext {
|
||||
minSdkVersion = 23
|
||||
compileSdkVersion = 30
|
||||
targetSdkVersion = 30
|
||||
ndkVersion = "21.4.7075529"
|
||||
ndkVersion = "21.4.7075529"
|
||||
}
|
||||
|
||||
+11
-9
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import { ScrollView, StyleSheet, View } from 'react-native'
|
||||
import PropTypes from 'prop-types'
|
||||
import moment from 'moment'
|
||||
@@ -10,6 +10,7 @@ import Footnote from './common/Footnote'
|
||||
|
||||
import cycleModule from '../lib/cycle'
|
||||
import { getFertilityStatusForDay } from '../lib/sympto-adapter'
|
||||
import setupNotifications from '../lib/notifications'
|
||||
import {
|
||||
determinePredictionText,
|
||||
formatWithOrdinalSuffix,
|
||||
@@ -19,13 +20,10 @@ import { Colors, Fonts, Sizes, Spacing } from '../styles'
|
||||
import { LocalDate } from '@js-joda/core'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const Home = ({ navigate, setDate }) => {
|
||||
const Home = ({ navigation }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
function navigateToCycleDayView() {
|
||||
setDate(todayDateString)
|
||||
navigate('CycleDay')
|
||||
}
|
||||
useEffect(() => setupNotifications(navigation), [])
|
||||
|
||||
const todayDateString = LocalDate.now().toString()
|
||||
const { getCycleDayNumber, getPredictedMenses } = cycleModule()
|
||||
@@ -33,11 +31,14 @@ const Home = ({ navigate, setDate }) => {
|
||||
const { status, phase, statusText } =
|
||||
getFertilityStatusForDay(todayDateString)
|
||||
const prediction = determinePredictionText(getPredictedMenses(), t)
|
||||
|
||||
const cycleDayText = cycleDayNumber
|
||||
? formatWithOrdinalSuffix(cycleDayNumber)
|
||||
: ''
|
||||
|
||||
function navigateToCycleDayView() {
|
||||
navigation.navigate('CycleDayOverview', { date: todayDateString })
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
style={styles.container}
|
||||
@@ -109,8 +110,9 @@ const styles = StyleSheet.create({
|
||||
})
|
||||
|
||||
Home.propTypes = {
|
||||
navigate: PropTypes.func,
|
||||
setDate: PropTypes.func,
|
||||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
export default Home
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
import { getLicenseFlag, saveEncryptionFlag } from '../local-storage'
|
||||
import { openDb } from '../db'
|
||||
import { closeDb, openDb } from '../db'
|
||||
|
||||
import App from './app'
|
||||
import AppLoadingView from './common/app-loading'
|
||||
@@ -29,6 +29,8 @@ export default function AppWrapper() {
|
||||
useEffect(() => {
|
||||
checkIsLicenseAccepted()
|
||||
checkIsDbEncrypted()
|
||||
|
||||
return () => closeDb()
|
||||
}, [])
|
||||
|
||||
if (isLoading) {
|
||||
|
||||
+64
-53
@@ -1,71 +1,82 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { BackHandler, StyleSheet, View } from 'react-native'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { LocalDate } from '@js-joda/core'
|
||||
import React from 'react'
|
||||
import 'react-native-gesture-handler'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
import { NavigationContainer } from '@react-navigation/native'
|
||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
|
||||
import { createStackNavigator } from '@react-navigation/stack'
|
||||
|
||||
import Home from './Home'
|
||||
import Chart from './chart/chart'
|
||||
import CalendarView from './calendar'
|
||||
import CycleDayOverview from './cycle-day/cycle-day-overview'
|
||||
import Stats from './stats'
|
||||
import Icon from './common/menu-icon'
|
||||
import Header from './header'
|
||||
import Menu from './menu'
|
||||
import { viewsList } from './views'
|
||||
import { pages } from './pages'
|
||||
|
||||
import setupNotifications from '../lib/notifications'
|
||||
import { closeDb } from '../db'
|
||||
import { Colors, Fonts, Sizes } from '../styles'
|
||||
|
||||
const App = ({ restartApp }) => {
|
||||
const [date, setDate] = useState(LocalDate.now().toString())
|
||||
const [currentPage, setCurrentPage] = useState('Home')
|
||||
const goBack = () => {
|
||||
if (currentPage === 'Home') {
|
||||
closeDb()
|
||||
BackHandler.exitApp()
|
||||
} else {
|
||||
const { parent } = pages.find((p) => p.component === currentPage)
|
||||
|
||||
setCurrentPage(parent)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const backHandler = BackHandler.addEventListener(
|
||||
'hardwareBackPress',
|
||||
goBack
|
||||
)
|
||||
|
||||
return () => backHandler.remove()
|
||||
})
|
||||
|
||||
useEffect(() => setupNotifications(setCurrentPage, setDate), [])
|
||||
|
||||
const Page = viewsList[currentPage]
|
||||
const isTemperatureEditView = currentPage === 'TemperatureEditView'
|
||||
const headerProps = { navigate: setCurrentPage }
|
||||
const pageProps = {
|
||||
date,
|
||||
setDate,
|
||||
isTemperatureEditView,
|
||||
navigate: setCurrentPage,
|
||||
}
|
||||
const HomeStack = createStackNavigator()
|
||||
|
||||
function HomeStackScreen() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Header {...headerProps} />
|
||||
<Page {...pageProps} restartApp={restartApp} />
|
||||
<Menu currentPage={currentPage} navigate={setCurrentPage} />
|
||||
</View>
|
||||
<HomeStack.Navigator screenOptions={{ headerShown: false }}>
|
||||
<HomeStack.Screen name="Home" component={Home} />
|
||||
<HomeStack.Screen name="CycleDayOverview" component={CycleDayOverview} />
|
||||
</HomeStack.Navigator>
|
||||
)
|
||||
}
|
||||
|
||||
App.propTypes = {
|
||||
restartApp: PropTypes.func,
|
||||
const Tab = createBottomTabNavigator()
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<NavigationContainer>
|
||||
<Tab.Navigator
|
||||
screenOptions={({ route }) => ({
|
||||
header: ({ navigation }) => <Header navigation={navigation} />,
|
||||
tabBarIcon: ({ focused }) => {
|
||||
let icon = 'chart'
|
||||
|
||||
if (route.name === 'CalendarStackScreen') {
|
||||
icon = 'calendar'
|
||||
} else if (route.name === 'Stats') {
|
||||
icon = 'statistics'
|
||||
}
|
||||
|
||||
return <Icon name={icon} isActive={focused} />
|
||||
},
|
||||
tabBarLabel: ({ color }) => {
|
||||
return (
|
||||
<Text style={[styles.text, { color: color }]}>{route.name}</Text>
|
||||
)
|
||||
},
|
||||
tabBarActiveTintColor: Colors.orange,
|
||||
tabBarInactiveTintColor: Colors.grey,
|
||||
tabBarStyle: { height: 80 },
|
||||
})}
|
||||
>
|
||||
<Tab.Screen
|
||||
name="HomeStackScreen"
|
||||
component={HomeStackScreen}
|
||||
options={{ tabBarButton: () => null, tabBarVisible: false }}
|
||||
/>
|
||||
<Tab.Screen name="Calendar" component={CalendarView} />
|
||||
<Tab.Screen name="Chart" component={Chart} />
|
||||
<Tab.Screen name="Stats" component={Stats} />
|
||||
</Tab.Navigator>
|
||||
</NavigationContainer>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
text: {
|
||||
fontFamily: Fonts.bold,
|
||||
fontSize: Sizes.small,
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
})
|
||||
|
||||
export default App
|
||||
|
||||
@@ -12,13 +12,12 @@ import {
|
||||
todayToCalFormat,
|
||||
} from './helpers/calendar'
|
||||
|
||||
const CalendarView = ({ setDate, navigate }) => {
|
||||
const CalendarView = ({ navigation }) => {
|
||||
const bleedingDays = getBleedingDaysSortedByDate()
|
||||
const predictedMenses = cycleModule().getPredictedMenses()
|
||||
|
||||
const passDateToDayView = ({ dateString }) => {
|
||||
setDate(dateString)
|
||||
navigate('CycleDay')
|
||||
navigation.navigate('CycleDayOverview', { date: dateString })
|
||||
}
|
||||
|
||||
const markedDates = Object.assign(
|
||||
@@ -49,8 +48,9 @@ const styles = StyleSheet.create({
|
||||
})
|
||||
|
||||
CalendarView.propTypes = {
|
||||
setDate: PropTypes.func.isRequired,
|
||||
navigate: PropTypes.func.isRequired,
|
||||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
export default CalendarView
|
||||
|
||||
@@ -28,7 +28,7 @@ import { Spacing } from '../../styles'
|
||||
const getSymptomsFromCycleDays = (cycleDays) =>
|
||||
SYMPTOMS.filter((symptom) => cycleDays.some((cycleDay) => cycleDay[symptom]))
|
||||
|
||||
const CycleChart = ({ navigate, setDate }) => {
|
||||
const CycleChart = ({ navigation }) => {
|
||||
const [shouldShowHint, setShouldShowHint] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -84,9 +84,8 @@ const CycleChart = ({ navigate, setDate }) => {
|
||||
const renderColumn = ({ item }) => {
|
||||
return (
|
||||
<DayColumn
|
||||
setDate={setDate}
|
||||
dateString={item}
|
||||
navigate={navigate}
|
||||
navigation={navigation}
|
||||
symptomHeight={symptomHeight}
|
||||
columnHeight={columnHeight}
|
||||
symptomRowSymptoms={symptomRowSymptoms}
|
||||
@@ -100,7 +99,7 @@ const CycleChart = ({ navigate, setDate }) => {
|
||||
const hasDataToDisplay = chartSymptoms.length > 0
|
||||
|
||||
if (!hasDataToDisplay) {
|
||||
return <NoData navigate={navigate} />
|
||||
return <NoData />
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -135,8 +134,9 @@ const CycleChart = ({ navigate, setDate }) => {
|
||||
}
|
||||
|
||||
CycleChart.propTypes = {
|
||||
navigate: PropTypes.func,
|
||||
setDate: PropTypes.func,
|
||||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
@@ -19,8 +19,7 @@ const DayColumn = ({
|
||||
dateString,
|
||||
chartSymptoms,
|
||||
columnHeight,
|
||||
setDate,
|
||||
navigate,
|
||||
navigation,
|
||||
shouldShowTemperatureColumn,
|
||||
symptomHeight,
|
||||
symptomRowSymptoms,
|
||||
@@ -60,10 +59,8 @@ const DayColumn = ({
|
||||
columnHeight
|
||||
)
|
||||
|
||||
const onDaySelect = (date) => {
|
||||
setDate(date)
|
||||
navigate('CycleDay')
|
||||
}
|
||||
const onDaySelect = (date) =>
|
||||
navigation.navigate('CycleDayOverview', { date })
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={() => onDaySelect(dateString)} activeOpacity={1}>
|
||||
@@ -104,12 +101,13 @@ DayColumn.propTypes = {
|
||||
dateString: PropTypes.string.isRequired,
|
||||
chartSymptoms: PropTypes.array,
|
||||
columnHeight: PropTypes.number.isRequired,
|
||||
navigate: PropTypes.func.isRequired,
|
||||
setDate: PropTypes.func.isRequired,
|
||||
shouldShowTemperatureColumn: PropTypes.bool,
|
||||
symptomHeight: PropTypes.number.isRequired,
|
||||
symptomRowSymptoms: PropTypes.array,
|
||||
xAxisHeight: PropTypes.number,
|
||||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
export default DayColumn
|
||||
|
||||
@@ -12,7 +12,8 @@ import { getData, nextDate, prevDate } from '../helpers/cycle-day'
|
||||
import { Spacing } from '../../styles'
|
||||
import { SYMPTOMS } from '../../config'
|
||||
|
||||
const CycleDayOverView = ({ date, setDate, isTemperatureEditView }) => {
|
||||
const CycleDayOverView = ({ route }) => {
|
||||
const { date, isTemperatureEditView } = route.params
|
||||
const cycleDay = getCycleDay(date)
|
||||
|
||||
const [editedSymptom, setEditedSymptom] = useState(
|
||||
@@ -20,11 +21,11 @@ const CycleDayOverView = ({ date, setDate, isTemperatureEditView }) => {
|
||||
)
|
||||
|
||||
const showNextCycleDay = () => {
|
||||
setDate(nextDate(date))
|
||||
//setDate(nextDate(date))
|
||||
}
|
||||
|
||||
const showPrevCycleDay = () => {
|
||||
setDate(prevDate(date))
|
||||
//setDate(prevDate(date))
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -57,10 +58,12 @@ const CycleDayOverView = ({ date, setDate, isTemperatureEditView }) => {
|
||||
}
|
||||
|
||||
CycleDayOverView.propTypes = {
|
||||
cycleDay: PropTypes.object,
|
||||
date: PropTypes.string,
|
||||
setDate: PropTypes.func,
|
||||
isTemperatureEditView: PropTypes.bool,
|
||||
route: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
date: PropTypes.string,
|
||||
isTemperatureEditView: PropTypes.bool,
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
@@ -7,17 +7,17 @@ import HamburgerMenu from './hamburger-menu'
|
||||
|
||||
import { Colors, Containers, Sizes } from '../../styles'
|
||||
|
||||
const Header = ({ isStatic, navigate }) => {
|
||||
const Header = ({ isStatic, navigation }) => {
|
||||
return (
|
||||
<View style={styles.header}>
|
||||
{isStatic ? (
|
||||
<Logo />
|
||||
) : (
|
||||
<>
|
||||
<TouchableOpacity onPress={() => navigate('Home')}>
|
||||
<TouchableOpacity onPress={() => navigation.navigate('Home')}>
|
||||
<Logo />
|
||||
</TouchableOpacity>
|
||||
<HamburgerMenu navigate={navigate} />
|
||||
<HamburgerMenu navigate={navigation.navigate} />
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
@@ -26,7 +26,9 @@ const Header = ({ isStatic, navigate }) => {
|
||||
|
||||
Header.propTypes = {
|
||||
isStatic: PropTypes.bool,
|
||||
navigate: PropTypes.func,
|
||||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
}
|
||||
|
||||
Header.defaultProps = {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import React from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import MenuItem from './menu-item'
|
||||
|
||||
import { Containers } from '../../styles'
|
||||
import { pages } from '../pages'
|
||||
|
||||
const Menu = ({ currentPage, navigate }) => {
|
||||
const menuItems = pages.filter((page) => page.isInMenu)
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{menuItems.map(({ icon, label, component }) => {
|
||||
return (
|
||||
<MenuItem
|
||||
isActive={component === currentPage}
|
||||
onPress={() => navigate(component)}
|
||||
icon={icon}
|
||||
key={label}
|
||||
label={label}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
Menu.propTypes = {
|
||||
currentPage: PropTypes.string,
|
||||
navigate: PropTypes.func,
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: 'white',
|
||||
...Containers.rowContainer,
|
||||
},
|
||||
})
|
||||
|
||||
export default Menu
|
||||
@@ -1,33 +0,0 @@
|
||||
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
|
||||
@@ -1,77 +0,0 @@
|
||||
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,
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
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,
|
||||
}
|
||||
+14
-19
@@ -11,10 +11,9 @@ import alertError from '../common/alert-error'
|
||||
import { clearDb, isDbEmpty } from '../../../db'
|
||||
import { showToast } from '../../helpers/general'
|
||||
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 Segment from '../../common/segment'
|
||||
import AppText from '../../common/app-text'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const exportedFilePath = `${RNFS.DocumentDirectoryPath}/${EXPORT_FILE_NAME}`
|
||||
|
||||
@@ -23,10 +22,6 @@ const DeleteData = ({ onStartDeletion, isDeletingData }) => {
|
||||
const [isConfirmingWithPassword, setIsConfirmingWithPassword] =
|
||||
useState(false)
|
||||
|
||||
const { t } = useTranslation(null, {
|
||||
keyPrefix: 'hamburgerMenu.settings.data.delete',
|
||||
})
|
||||
|
||||
const onAlertConfirmation = () => {
|
||||
onStartDeletion()
|
||||
if (isPasswordSet) {
|
||||
@@ -37,16 +32,17 @@ const DeleteData = ({ onStartDeletion, isDeletingData }) => {
|
||||
}
|
||||
|
||||
const alertBeforeDeletion = async () => {
|
||||
const { question, message, confirmation, errors } = settings.deleteSegment
|
||||
if (isDbEmpty() && !(await RNFS.exists(exportedFilePath))) {
|
||||
alertError(t('error.noData'))
|
||||
alertError(errors.noData)
|
||||
} else {
|
||||
Alert.alert(t('dialog.title'), t('dialog.message'), [
|
||||
Alert.alert(question, message, [
|
||||
{
|
||||
text: t('dialog.delete'),
|
||||
text: confirmation,
|
||||
onPress: onAlertConfirmation,
|
||||
},
|
||||
{
|
||||
text: t('dialog.cancel'),
|
||||
text: sharedLabels.cancel,
|
||||
style: 'cancel',
|
||||
onPress: cancelConfirmationWithPassword,
|
||||
},
|
||||
@@ -61,14 +57,16 @@ const DeleteData = ({ onStartDeletion, isDeletingData }) => {
|
||||
}
|
||||
|
||||
const deleteAppData = async () => {
|
||||
const { errors, success } = settings.deleteSegment
|
||||
|
||||
try {
|
||||
if (!isDbEmpty()) {
|
||||
clearDb()
|
||||
}
|
||||
await deleteExportedFile()
|
||||
showToast(t('success.message'))
|
||||
showToast(success.message)
|
||||
} catch (err) {
|
||||
alertError(t('error.delete'))
|
||||
alertError(errors.couldNotDeleteFile)
|
||||
}
|
||||
cancelConfirmationWithPassword()
|
||||
}
|
||||
@@ -87,12 +85,9 @@ const DeleteData = ({ onStartDeletion, isDeletingData }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Segment title={t('title')} last>
|
||||
<AppText>{t('subTitle')}</AppText>
|
||||
<Button isCTA onPress={alertBeforeDeletion}>
|
||||
{t('title')}
|
||||
</Button>
|
||||
</Segment>
|
||||
<Button isCTA onPress={alertBeforeDeletion}>
|
||||
{settings.deleteSegment.title}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
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 NfpSettings from './nfp-settings'
|
||||
import DataManagement from './data-management/DataManagement'
|
||||
import DataManagement from './data-management'
|
||||
import Password from './password'
|
||||
import About from './About'
|
||||
import License from './License'
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { PixelRatio, StatusBar } from 'react-native'
|
||||
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 = [
|
||||
'bleeding',
|
||||
'temperature',
|
||||
@@ -36,7 +40,7 @@ export const HIT_SLOP = {
|
||||
top: verticalScale(20),
|
||||
bottom: verticalScale(20),
|
||||
left: scale(20),
|
||||
right: scale(20),
|
||||
right: scale(20)
|
||||
}
|
||||
|
||||
export const STATUSBAR_HEIGHT = StatusBar.currentHeight
|
||||
|
||||
@@ -80,55 +80,6 @@
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"dataManagement": {
|
||||
"name": "Data",
|
||||
|
||||
@@ -19,6 +19,52 @@ export default {
|
||||
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: {
|
||||
segmentTitle: 'Temperature scale',
|
||||
segmentExplainer:
|
||||
|
||||
@@ -11,16 +11,15 @@ import { getBleedingDaysSortedByDate } from '../db'
|
||||
import cycleModule from './cycle'
|
||||
import nothingChanged from '../db/db-unchanged'
|
||||
|
||||
export default function setupNotifications(navigate, setDate) {
|
||||
export default function setupNotifications(navigation) {
|
||||
Notification.configure({
|
||||
onNotification: (notification) => {
|
||||
const date = LocalDate.now().toString()
|
||||
// https://github.com/zo0r/react-native-push-notification/issues/966#issuecomment-479069106
|
||||
if (notification.data?.id === '1' || notification.id === '1') {
|
||||
const todayDate = LocalDate.now().toString()
|
||||
setDate(todayDate)
|
||||
navigate('TemperatureEditView')
|
||||
navigation.navigate('TemperatureEditView', { date })
|
||||
} else {
|
||||
navigate('Home')
|
||||
navigation.navigate('Home', { date })
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
"@react-native-community/art": "^1.2.0",
|
||||
"@react-native-community/datetimepicker": "^6.3.1",
|
||||
"@react-native-community/push-notification-ios": "^1.8.0",
|
||||
"@react-navigation/bottom-tabs": "^6.4.0",
|
||||
"@react-navigation/native": "^6.0.13",
|
||||
"@react-navigation/native-stack": "^6.9.0",
|
||||
"@react-navigation/stack": "^6.3.1",
|
||||
"csvtojson": "^2.0.8",
|
||||
"i18next": "^21.9.0",
|
||||
"jshashes": "^1.0.8",
|
||||
@@ -48,8 +52,11 @@
|
||||
"react-native-calendars": "^1.1287.0",
|
||||
"react-native-document-picker": "^8.1.1",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-gesture-handler": "^2.6.2",
|
||||
"react-native-modal-datetime-picker": "14.0.0",
|
||||
"react-native-push-notification": "3.2.1",
|
||||
"react-native-safe-area-context": "^4.3.4",
|
||||
"react-native-screens": "^3.17.0",
|
||||
"react-native-share": "^7.9.0",
|
||||
"react-native-simple-toast": "^1.1.3",
|
||||
"react-native-size-matters": "^0.4.0",
|
||||
|
||||
@@ -1197,6 +1197,13 @@
|
||||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@egjs/hammerjs@^2.0.17":
|
||||
version "2.0.17"
|
||||
resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124"
|
||||
integrity sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==
|
||||
dependencies:
|
||||
"@types/hammerjs" "^2.0.36"
|
||||
|
||||
"@eslint/eslintrc@^0.2.1":
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76"
|
||||
@@ -1709,6 +1716,66 @@
|
||||
resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa"
|
||||
integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==
|
||||
|
||||
"@react-navigation/bottom-tabs@^6.4.0":
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-6.4.0.tgz#63743874648f92adedf37186cb7cedcd47826ee9"
|
||||
integrity sha512-90CapiXjiWudbCiki9e6fOr/CECQRguIxv5OD7IBfbAMGX5GGiJpX8aqiHAz2DxpAz31v4JZcUr945+lFhXBfA==
|
||||
dependencies:
|
||||
"@react-navigation/elements" "^1.3.6"
|
||||
color "^4.2.3"
|
||||
warn-once "^0.1.0"
|
||||
|
||||
"@react-navigation/core@^6.4.0":
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.0.tgz#c44d33a8d8ef010a102c7f831fc8add772678509"
|
||||
integrity sha512-tpc0Ak/DiHfU3LlYaRmIY7vI4sM/Ru0xCet6runLUh9aABf4wiLgxyFJ5BtoWq6xFF8ymYEA/KWtDhetQ24YiA==
|
||||
dependencies:
|
||||
"@react-navigation/routers" "^6.1.3"
|
||||
escape-string-regexp "^4.0.0"
|
||||
nanoid "^3.1.23"
|
||||
query-string "^7.0.0"
|
||||
react-is "^16.13.0"
|
||||
use-latest-callback "^0.1.5"
|
||||
|
||||
"@react-navigation/elements@^1.3.6":
|
||||
version "1.3.6"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.6.tgz#fa700318528db93f05144b1be4b691b9c1dd1abe"
|
||||
integrity sha512-pNJ8R9JMga6SXOw6wGVN0tjmE6vegwPmJBL45SEMX2fqTfAk2ykDnlJHodRpHpAgsv0DaI8qX76z3A+aqKSU0w==
|
||||
|
||||
"@react-navigation/native-stack@^6.9.0":
|
||||
version "6.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.0.tgz#1e79e06da8b81f0368d3709aedca269947da3649"
|
||||
integrity sha512-cwqm/2GO0hf94OFRuH6R0beZPVKY4vMFxrdAPaDwwoukN5a0UgcsMYxrN8s2huwssTCuGScABFME9GnqG5hC5w==
|
||||
dependencies:
|
||||
"@react-navigation/elements" "^1.3.6"
|
||||
warn-once "^0.1.0"
|
||||
|
||||
"@react-navigation/native@^6.0.13":
|
||||
version "6.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.0.13.tgz#ec504120e193ea6a7f24ffa765a1338be5a3160a"
|
||||
integrity sha512-CwaJcAGbhv3p3ECablxBkw8QBCGDWXqVRwQ4QbelajNW623m3sNTC9dOF6kjp8au6Rg9B5e0KmeuY0xWbPk79A==
|
||||
dependencies:
|
||||
"@react-navigation/core" "^6.4.0"
|
||||
escape-string-regexp "^4.0.0"
|
||||
fast-deep-equal "^3.1.3"
|
||||
nanoid "^3.1.23"
|
||||
|
||||
"@react-navigation/routers@^6.1.3":
|
||||
version "6.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-6.1.3.tgz#1df51959e9a67c44367462e8b929b7360a5d2555"
|
||||
integrity sha512-idJotMEzHc3haWsCh7EvnnZMKxvaS4YF/x2UyFBkNFiEFUaEo/1ioQU6qqmVLspdEv4bI/dLm97hQo7qD8Yl7Q==
|
||||
dependencies:
|
||||
nanoid "^3.1.23"
|
||||
|
||||
"@react-navigation/stack@^6.3.1":
|
||||
version "6.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-navigation/stack/-/stack-6.3.1.tgz#71f53d7598332765da08f78b56aeae245cc98cb6"
|
||||
integrity sha512-WkURDiSip8QpB+cuEbp5GfDPDGxER7w7ooJVgG3J2nJNnYuKxsZR7qnlqWL2vjQW81NzKQpT7xrCADy+mfvIiQ==
|
||||
dependencies:
|
||||
"@react-navigation/elements" "^1.3.6"
|
||||
color "^4.2.3"
|
||||
warn-once "^0.1.0"
|
||||
|
||||
"@realm.io/common@^0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@realm.io/common/-/common-0.1.1.tgz#2950846cbedd14bdfdc1175d7c3119c3469547b0"
|
||||
@@ -1808,6 +1875,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/hammerjs@^2.0.36":
|
||||
version "2.0.41"
|
||||
resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.41.tgz#f6ecf57d1b12d2befcce00e928a6a097c22980aa"
|
||||
integrity sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
|
||||
@@ -2793,11 +2865,27 @@ color-name@1.1.3:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||
|
||||
color-name@~1.1.4:
|
||||
color-name@^1.0.0, color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-string@^1.9.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
|
||||
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
|
||||
dependencies:
|
||||
color-name "^1.0.0"
|
||||
simple-swizzle "^0.2.2"
|
||||
|
||||
color@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
|
||||
integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
color-string "^1.9.0"
|
||||
|
||||
colorette@^1.0.7, colorette@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40"
|
||||
@@ -3392,6 +3480,11 @@ escape-string-regexp@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
|
||||
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
|
||||
|
||||
escape-string-regexp@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||
|
||||
eslint-plugin-react@^7.8.2:
|
||||
version "7.25.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.25.2.tgz#d567a217d306b76dd110561f28074e2328ae38f8"
|
||||
@@ -3653,7 +3746,7 @@ extsprintf@1.3.0, extsprintf@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==
|
||||
|
||||
fast-deep-equal@^3.1.1:
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||
@@ -3717,6 +3810,11 @@ fill-range@^7.0.1:
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
filter-obj@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
|
||||
integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==
|
||||
|
||||
finalhandler@1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
|
||||
@@ -4145,7 +4243,7 @@ hermes-profile-transformer@^0.0.6:
|
||||
dependencies:
|
||||
source-map "^0.7.3"
|
||||
|
||||
hoist-non-react-statics@^3.3.1:
|
||||
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
@@ -4383,6 +4481,11 @@ is-arrayish@^0.2.1:
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
||||
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
|
||||
|
||||
is-arrayish@^0.3.1:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
|
||||
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
|
||||
|
||||
is-bigint@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
|
||||
@@ -5479,7 +5582,7 @@ lodash@^2.4.1:
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e"
|
||||
integrity sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==
|
||||
|
||||
lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.3:
|
||||
lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
@@ -6047,6 +6150,11 @@ multimatch@^4.0.0:
|
||||
arrify "^2.0.1"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
nanoid@^3.1.23:
|
||||
version "3.3.4"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
||||
@@ -6738,6 +6846,16 @@ qs@^6.1.0, qs@~6.5.2:
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||
|
||||
query-string@^7.0.0:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.1.tgz#754620669db978625a90f635f12617c271a088e1"
|
||||
integrity sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==
|
||||
dependencies:
|
||||
decode-uri-component "^0.2.0"
|
||||
filter-obj "^1.1.0"
|
||||
split-on-first "^1.0.0"
|
||||
strict-uri-encode "^2.0.0"
|
||||
|
||||
querystringify@^2.1.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
|
||||
@@ -6766,6 +6884,11 @@ react-devtools-core@4.19.1:
|
||||
shell-quote "^1.6.1"
|
||||
ws "^7"
|
||||
|
||||
react-freeze@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d"
|
||||
integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==
|
||||
|
||||
react-i18next@^11.18.3:
|
||||
version "11.18.3"
|
||||
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.18.3.tgz#50211810bcc9fdea2d70c8aefdfff5f1eb39a923"
|
||||
@@ -6779,7 +6902,7 @@ react-i18next@^11.18.3:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
||||
react-is@^16.13.1, react-is@^16.7.0:
|
||||
react-is@^16.13.0, react-is@^16.13.1, react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
@@ -6829,6 +6952,17 @@ react-native-fs@^2.20.0:
|
||||
base-64 "^0.1.0"
|
||||
utf8 "^3.0.0"
|
||||
|
||||
react-native-gesture-handler@^2.6.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.6.2.tgz#f3b68d374f5dda603ff29f7df2edb39472eb97ce"
|
||||
integrity sha512-Ff/WKlR8KiM1wq7UJZvIyCB+OsweewaeZk+4RDIYNGM9tvNIAXEm/MtYnLHiBXiSJjZItF/8B83gE6pVq40vIw==
|
||||
dependencies:
|
||||
"@egjs/hammerjs" "^2.0.17"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
invariant "^2.2.4"
|
||||
lodash "^4.17.21"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-native-modal-datetime-picker@14.0.0:
|
||||
version "14.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-modal-datetime-picker/-/react-native-modal-datetime-picker-14.0.0.tgz#ca2c81a275ee3a23d9ad02113e76ed243c90781e"
|
||||
@@ -6843,6 +6977,19 @@ react-native-push-notification@3.2.1:
|
||||
dependencies:
|
||||
"@react-native-community/push-notification-ios" "^1.0.1"
|
||||
|
||||
react-native-safe-area-context@^4.3.4:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.3.4.tgz#79060fcc02ef38d6fd7afdf87b2301b06bd99fe9"
|
||||
integrity sha512-4dFZPDHRigZ+uw8HCmMLyC/IT1BG0B9QLvuwsBQAMDCRSrxISIYza9VIbsIn2FGvZiQ1gOoXBHDmy9WFihQsTg==
|
||||
|
||||
react-native-screens@^3.17.0:
|
||||
version "3.17.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.17.0.tgz#b099b3ec9d46de07c857f14d713c293024c7c842"
|
||||
integrity sha512-OZCQU7+3neHNaM19jBkYRjL50kXz7p7MUgWQTCcdRoshcCiolf8aXs4eRVQKGK6m1RmoB8UL0//m5R9KoR+41w==
|
||||
dependencies:
|
||||
react-freeze "^1.0.0"
|
||||
warn-once "^0.1.0"
|
||||
|
||||
react-native-share@^7.9.0:
|
||||
version "7.9.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-share/-/react-native-share-7.9.0.tgz#31f28d85201bada5e511c5f14d5935df2166fe93"
|
||||
@@ -7542,6 +7689,13 @@ simple-plist@^1.0.0:
|
||||
bplist-parser "0.2.0"
|
||||
plist "^3.0.1"
|
||||
|
||||
simple-swizzle@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
|
||||
integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
|
||||
dependencies:
|
||||
is-arrayish "^0.3.1"
|
||||
|
||||
sisteransi@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
|
||||
@@ -7638,6 +7792,11 @@ source-map@^0.7.3:
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
|
||||
integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
|
||||
|
||||
split-on-first@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
|
||||
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
|
||||
|
||||
split-string@^3.0.1, split-string@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
|
||||
@@ -7717,6 +7876,11 @@ stream-counter@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/stream-counter/-/stream-counter-1.0.0.tgz#91cf2569ce4dc5061febcd7acb26394a5a114751"
|
||||
integrity sha512-4nfHc1016AhNOs0CFDR3S0FNeqnYbT7xZ408coajcx2Msj8malNNjvFHzWYIfIAXNK5i0eaKIVfgBYPOkyOTIg==
|
||||
|
||||
strict-uri-encode@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||
integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==
|
||||
|
||||
string-length@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
|
||||
@@ -8347,6 +8511,11 @@ url-parse@^1.4.4:
|
||||
querystringify "^2.1.1"
|
||||
requires-port "^1.0.0"
|
||||
|
||||
use-latest-callback@^0.1.5:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.1.5.tgz#a4a836c08fa72f6608730b5b8f4bbd9c57c04f51"
|
||||
integrity sha512-HtHatS2U4/h32NlkhupDsPlrbiD27gSH5swBdtXbCAlc6pfOFzaj0FehW/FO12rx8j2Vy4/lJScCiJyM01E+bQ==
|
||||
|
||||
use-subscription@^1.0.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.8.0.tgz#f118938c29d263c2bce12fc5585d3fe694d4dbce"
|
||||
@@ -8463,6 +8632,11 @@ walker@^1.0.7, walker@^1.0.8, walker@~1.0.5:
|
||||
dependencies:
|
||||
makeerror "1.0.12"
|
||||
|
||||
warn-once@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/warn-once/-/warn-once-0.1.1.tgz#952088f4fb56896e73fd4e6a3767272a3fccce43"
|
||||
integrity sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==
|
||||
|
||||
wcwidth@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
|
||||
|
||||
Reference in New Issue
Block a user