Commit cf2c29e5 authored by Choi Ga Young's avatar Choi Ga Young
Browse files

Merge remote-tracking branch 'origin/shyunDBtest' into rkyoung

parents 824c2e18 a12bc2cf
...@@ -4,9 +4,10 @@ import { NavigationContainer } from '@react-navigation/native'; ...@@ -4,9 +4,10 @@ import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons'; import Ionicons from 'react-native-vector-icons/Ionicons';
import Monthly from './Monthly'; import Monthly from './Monthly';
import Analy from './Analy'; // import Analy from './Analy';
import MoneyDB from './MoneyDB';
import Calendar from './Calendar'; import Calendar from './Calendar';
import PostMoney from './PostMoney';
import InsertCat from './InsertCat';
function MainScreen({ navigation }) { function MainScreen({ navigation }) {
const [number, onChangeNumber] = useState(null) const [number, onChangeNumber] = useState(null)
...@@ -31,8 +32,8 @@ function MainScreen({ navigation }) { ...@@ -31,8 +32,8 @@ function MainScreen({ navigation }) {
title="월별 페이지로 이동" title="월별 페이지로 이동"
onPress={() => navigation.navigate('Monthly')} onPress={() => navigation.navigate('Monthly')}
/> />
<MoneyDB /> <InsertCat />
</> </>
) )
} }
...@@ -67,8 +68,8 @@ function App() { ...@@ -67,8 +68,8 @@ function App() {
}}> }}>
<Tab.Screen name="Main" component={MainScreen} /> <Tab.Screen name="Main" component={MainScreen} />
<Tab.Screen name="Monthly" component={Monthly} /> <Tab.Screen name="Monthly" component={Monthly} />
<Tab.Screen name="Analy" component={Analy} />
<Tab.Screen name="Calendar" component={Calendar} /> <Tab.Screen name="Calendar" component={Calendar} />
<Tab.Screen name="Analy" component={PostMoney} />
</Tab.Navigator> </Tab.Navigator>
</NavigationContainer> </NavigationContainer>
); );
......
import { DEBUG, enablePromise, openDatabase } from 'react-native-sqlite-storage';
import { SafeAreaView, StyleSheet, Text, View, TextInput, FlatList, Button } from 'react-native';
import React, { useEffect, useState } from 'react';
DEBUG(true);
enablePromise(true);
const db = openDatabase({
name: 'MyMoney',
location: 'default',
createFromLocation: '~MyMoney.db', // android/src/main/assets/TestDB.db 파일을 위치 시킴
});
const QueryFunc = async (Query) => {
(await db).transaction(Query)
};
function InsertCat() {
const [cat, setCat] = useState('')
const [asset, setAsset] = useState('')
console.log('money db')
const populateDatabase = async DB => {
await DB.transaction(queryMoney); // 반드시 (await db)를 해야 프라미스가 성공
};
const loadAndQueryDB = async () => {
try {
console.log('load and db query ....');
await populateDatabase(await db);
} catch (error) {
console.log(error);
}
};
const insertCategory = async () => {
QueryFunc(async (tx) => {
console.log("카테고리 정보 저장");
await tx.executeSql('INSERT INTO categories (category_name) VALUES (?);',
[cat],
() => { console.log("카테고리 삽입 성공"); },
(error) => console.log(error))
})
}
const insertAsset = async () => {
QueryFunc(async (tx) => {
console.log("자산 정보 저장");
await tx.executeSql('INSERT INTO assets_type (assets_name) VALUES (?);',
[asset],
() => { console.log("자산 삽입 성공"); },
(error) => console.log(error))
})
}
return (
<SafeAreaView>
<Text>db test</Text>
<View>
<Text style={style.Font}>-데이터 입력 테스트</Text>
<Text>cat</Text>
<TextInput
placeholder="cat"
onChangeText={
(cat) => setCat(cat)
}
/>
<Text>asset</Text>
<TextInput
placeholder="asset"
onChangeText={
(asset) => setAsset(asset)
}
/>
</View>
<Button title='카테고리 삽입하기' onPress={insertCategory} />
<Button title='자산 삽입하기' onPress={insertAsset} />
</SafeAreaView>
);
}
const style = StyleSheet.create({
Font: {
fontSize: 24
}
});
export default InsertCat
\ No newline at end of file
// import SQLite, { openDatabase } from 'react-native-sqlite-storage';
import { DEBUG, enablePromise, openDatabase } from 'react-native-sqlite-storage'; import { DEBUG, enablePromise, openDatabase } from 'react-native-sqlite-storage';
import { View, SafeAreaView, Text, StyleSheet, Button, TextInput } from 'react-native'; import { View, SafeAreaView, Text, StyleSheet, Button, TextInput } from 'react-native';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
...@@ -9,89 +8,15 @@ enablePromise(true); ...@@ -9,89 +8,15 @@ enablePromise(true);
const db = openDatabase({ const db = openDatabase({
name: 'MyMoney', name: 'MyMoney',
location: 'default', location: 'default',
createFromLocation: '~MyMoney.db', createFromLocation: '~MyMoney.db', // android/src/main/assets/TestDB.db 파일을 위치 시킴
}); });
function MoneyDB() { const QueryFunc = async (Query) => {
const [date, setDate] = useState('2021-01-01') (await db).transaction(Query)
const [category, setCategory] = useState(2) };
const [subcategory, setSubcategory] = useState(2)
const [type, setType] = useState('우리')
const [contents, setContents] = useState('경로')
const [price, setPrice] = useState(1000)
const [assetsId, setAssetsId] = useState()
const [assetsname, setAssetsname] = useState()
const populateDatabase = async DB => { const moneyApi = {
await DB.transaction(getData); // 반드시 (await db)를 해야 프라미스가 성공 QueryFunc,
};
const loadAndQueryDB = async () => {
try {
console.log('load and db query ....');
await populateDatabase(await db);
} catch (error) {
console.log(error);
}
};
const getData = async tx => {
console.log('데이터 가져오기');
try {
const [txn, results] = await tx.executeSql('SELECT * FROM money');
console.log('results: ', results.rows.item(0));
} catch (error) {
console.log('error in getData', error);
}
}
const createTable = async tx => {
console.log('테이블 생성하기');
try {
const [txn, results] = await tx.executeSql('CREATE TABLE IF NOT EXISTS Test(' + 'Money INTEGER);');
console.log("테이블 생성 성공 ");
} catch (error) {
console.log('error in createTable', error);
}
}
const insertData = async () => {
try {
(await db).transaction((tx) => {
console.log("데이터 삽입하기");
tx.executeSql('INSERT INTO assets_type (assets_id, assets_name) VALUES (?,?);',
[assetsId, assetsname],
() => { console.log("삽입 성공"); },
(error) => console.log(error))
})
} catch (error) {
console.log('error in insertData', error);
}
}
useEffect(() => {
loadAndQueryDB();
}, []);
return (
<>
<SafeAreaView>
<View>
<Text>DB</Text>
<Button title='데이터 가져오기' onPress={() => getData()} />
<Button title='테이블 생성하기' onPress={() => createTable()} />
<TextInput placeholder='assetsId' onChangeText={(assetsId) => setAssetsId(assetsId)} />
<TextInput placeholder='assetsname' onChangeText={(assetsname) => setAssetsname(assetsname)} />
<Button title='데이터 삽입하기' onPress={() => insertData()} />
</View>
</SafeAreaView>
</>
)
} }
export default moneyApi
export default MoneyDB;
\ No newline at end of file
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';
import { DEBUG, enablePromise, openDatabase } from 'react-native-sqlite-storage';
import InputBox from './components/InputBox';
import ButtonsForm from './components/ButtonsForm';
import SelectForm from './components/SelectForm';
import StyledButton from './components/StyledButton';
import DatePicker from './components/DatePicker';
import moneyApi from './MoneyDB';
DEBUG(true);
enablePromise(true);
const db = openDatabase({
name: 'MyMoney',
location: 'default',
createFromLocation: '~MyMoney.db', // android/src/main/assets/TestDB.db 파일을 위치 시킴
});
const getDate = () => {
var date = new Date();
return (String(date.toJSON()).split(/T/)[0])
}
const INIT_SUBCATEGORIES = [
{
id: 1,
value: '간식',
foreign_id: 1
},
{
id: 2,
value: '외식',
foreign_id: 1
},
{
id: 3,
value: '배달',
foreign_id: 1
},
{
id: 4,
value: '택시',
foreign_id: 2
},
{
id: 5,
value: '영화',
foreign_id: 3
},
{
id: 6,
value: '뮤지컬',
foreign_id: 3
},
]
const PostMoney = () => {
const [selectedIndex, setSelectedIndex] = useState(0)
const [date, setDate] = useState(getDate())
const [contents, setContents] = useState('')
const [price, setPrice] = useState(0)
const [asset_type, setAsset_type] = useState([])
const [selected_asset_type, setSelected_asset_type] = useState(0)
const [categories, setCategories] = useState([])
const [selected_cat, setSelected_cat] = useState(0)
const [subcategories, setSubcategories] = useState(INIT_SUBCATEGORIES)
const [selected_subcat, setSelected_subcat] = useState(0)
console.log('type: ', selectedIndex, '| date: ', date, '| contents: ', contents, '| price: ', price, '| selected_asset_type: ', selected_asset_type, '| selected_cat: ', selected_cat, '| selected_subcat: ', selected_subcat)
const insertData = async () => {
try {
let type = ''
if (selectedIndex === 0) { type = '수입' }
else if (selectedIndex === 1) { type = '지출' }
else { type = '이동' }
(await db).transaction((tx) => {
console.log("데이터 삽입하기");
tx.executeSql('INSERT INTO Money (type, date, contents, price, asset_type, category, subcategory) VALUES (?,?,?,?,?,?,?);',
[type, date, contents, price, selected_asset_type, selected_cat, selected_subcat],
() => { console.log("삽입 성공"); },
(error) => console.log(error))
})
} catch (error) {
console.log('error in insert data', error)
}
}
const loadCat = async () => {
try {
await moneyApi.QueryFunc(async (tx) => {
console.log("카테고리 부르기");
const [txn, results] = await tx.executeSql('SELECT * FROM categories');
console.log('item length', results.rows.length);
const temp = [];
for (let i = 0; i < results.rows.length; i++) {
const tempId = results.rows.item(i).category_id;
const tempName = results.rows.item(i).category_name;
temp.push({ id: tempId, value: tempName });
}
setCategories(temp);
})
} catch (error) {
console.log('error in load data ( postMoney.js )', error)
}
}
const loadAssetType = async () => {
try {
(await db).transaction(async (tx) => {
console.log("자산 유형 부르기");
const [txn, results] = await tx.executeSql('SELECT * FROM assets_type');
console.log('item length', results.rows.length);
const temp = [];
for (let i = 0; i < results.rows.length; i++) {
const tempId = results.rows.item(i).assets_id;
const tempName = results.rows.item(i).assets_name;
temp.push({ id: tempId, value: tempName });
}
setAsset_type(temp);
})
} catch (error) {
console.log('error in insert data', error)
}
}
useEffect(() => {
loadCat()
loadAssetType()
}, [])
return (
<View>
<View>
<ButtonsForm
onPress={(index) => setSelectedIndex(index)}
selectedIndex={selectedIndex}
group={["수입", "지출", "이동"]} />
<DatePicker
inputTitle="날짜"
date={date}
setDate={setDate}
/>
<InputBox
inputTitle="내용"
placeholder="내용을 입력하세요"
onChangeText={
(contents) => setContents(contents)
}
maxLength={30}
/>
<InputBox
inputTitle="금액"
placeholder="금액을 입력하세요"
onChangeText={
(price) => setPrice(price)
}
keyboardType="numeric"
maxLength={30}
/>
<SelectForm
inputTitle="자산"
placeholder="자산 선택"
data={asset_type}
selectedData={selected_asset_type}
onValueChange={(assetId) => setSelected_asset_type(assetId)}
/>
<SelectForm
inputTitle="구분"
placeholder="카테고리 선택"
data={categories}
selectedData={selected_cat}
onValueChange={(catId) => setSelected_cat(catId)}
subData={subcategories}
selectedSubData={selected_subcat}
onSubValueChange={(subcatId) => setSelected_subcat(subcatId)}
/>
</View>
<View style={style.buttonRow}>
<StyledButton
name="저장하기"
onPress={insertData}
style={style.submitButton}
/>
<StyledButton
name="취소"
onPress={() => console.log('취소버튼')}
style={style.cancelButton}
/>
</View>
</View>
)
}
const style = StyleSheet.create({
Font: {
fontSize: 24
},
buttonRow: {
flexDirection: 'row',
alignItems: "center",
marginHorizontal: 10,
marginVertical: 3,
},
submitButton: {
flex: 3,
height: 50,
},
cancelButton: {
flex: 1,
height: 50,
}
});
export default PostMoney;
\ No newline at end of file
import React from 'react';
import { ButtonGroup } from 'react-native-elements';
import { StyleSheet, Text } from 'react-native';
const ButtonsForm = (props) => {
const component1 = () => <Text>{props.group[0]}</Text>
const component2 = () => <Text>{props.group[1]}</Text>
const component3 = () => <Text>{props.group[2]}</Text>
return (
<ButtonGroup
onPress={props.onPress}
selectedIndex={props.selectedIndex}
buttons={[{ element: component1 }, { element: component2 }, { element: component3 }]}
containerStyle={style.container}
selectedButtonStyle={style.selectedButton}
selectedTextStyle={style.selectedText}
/>
);
};
const style = StyleSheet.create({
container: {
height: 50,
flexDirection: 'row',
alignItems: "center",
backgroundColor: "#f5f5f5",
},
text: {
color: "#808080",
fontSize: 24
},
selectedButton: {
backgroundColor: "#adadad",
},
selectedText: {
color: "#1467ff",
fontWeight: "bold",
},
})
export default ButtonsForm
\ No newline at end of file
import React, { useState } from "react";
import { Button, View, Text, StyleSheet, Pressable } from "react-native";
import DateTimePickerModal from "react-native-modal-datetime-picker";
const DatePicker = (props) => {
const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
const showDatePicker = () => {
setDatePickerVisibility(true);
};
const hideDatePicker = () => {
setDatePickerVisibility(false);
};
const handleConfirm = (date) => {
console.log("A date has been picked: ", String(date.toJSON()).split(/T/)[0]);
props.setDate(String(date.toJSON()).split(/T/)[0])
hideDatePicker();
};
return (
<View style={style.container}>
<View style={style.inputTitleArea}>
<Text style={style.inputTitle}>{props.inputTitle}</Text>
</View>
<Pressable
style={style.dateAreaStyle}
onPress={showDatePicker}>
<Text style={style.dateTextStyle}>{props.date}</Text>
</Pressable>
<DateTimePickerModal
isVisible={isDatePickerVisible}
mode="date"
onConfirm={handleConfirm}
onCancel={hideDatePicker}
/>
</View>
);
};
const style = StyleSheet.create({
container: {
height:54,
flexDirection: 'row',
alignItems: "center",
marginHorizontal: 10,
marginVertical: 3,
borderWidth: 1.5,
borderStyle: "solid",
borderColor: "#1467ff",
borderRadius: 5,
backgroundColor: "#f5f5f5",
},
inputTitleArea: {
flex: 1,
},
inputTitle: {
alignSelf: "center",
color: "#1467ff",
fontSize: 20,
},
dateAreaStyle: {
flex: 3,
},
dateTextStyle: {
fontSize: 20,
},
})
export default DatePicker
\ No newline at end of file
import React from 'react';
import { StyleSheet, Text, View, TextInput } from 'react-native';
const InputBox = (props) => {
return (
<View style={style.container}>
<View style={style.inputTitleArea}>
<Text style={style.inputTitle}>{props.inputTitle}</Text>
</View>
<TextInput
underlineColorAndroid="transparent"
placeholder={props.placeholder}
placeholderTextColor="#808080"
keyboardType={props.keyboardType}
onChangeText={props.onChangeText}
returnKeyType={props.returnKeyType}
numberOfLines={props.numberOfLines}
multiline={props.multiline}
onSubmitEditing={props.onSubmitEditing}
style={style.textStyle}
blurOnSubmit={false}
value={props.value}
/>
</View>
);
};
const style = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: "center",
marginHorizontal: 10,
marginVertical: 3,
borderWidth: 1.5,
borderStyle: "solid",
borderColor: "#1467ff",
borderRadius: 5,
backgroundColor: "#f5f5f5",
},
inputTitleArea: {
flex: 1,
},
inputTitle: {
alignSelf: "center",
color: "#1467ff",
fontSize: 20,
},
textStyle: {
flex: 3,
fontSize: 20,
},
})
export default InputBox
\ No newline at end of file
import React, { useEffect, useRef } from 'react';
import { Animated, Text, View, StyleSheet } from 'react-native';
const Notification = (props) => {
const opacity = useRef(new Animated.Value(0)).current;
useEffect(() => {
if (props.notification !== '') {
Animated.sequence([
Animated.timing(opacity, {
toValue: 1,
duration: 500,
useNativeDriver: true,
}),
Animated.delay(2500),
Animated.timing(opacity, {
toValue: 0,
duration: 500,
useNativeDriver: true,
}),
]).start(() => {
props.setNotification('');
})
}
}, [props.notification])
return (
<View style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
}}>
<Animated.View
style={[
{
opacity: opacity
},
{
transform: [{
translateY: opacity.interpolate({
inputRange: [0, 1],
outputRange: [-20, 0],
})
}],
},
style.msgBox
]}
>
<Text style={style.textStyle}>
{props.notification}
</Text>
</Animated.View>
</View >
);
};
const style = StyleSheet.create({
msgBox: {
margin: 10,
marginBottom: 5,
backgroundColor: 'white',
padding: 15,
borderRadius: 4,
shadowColor: 'black',
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.3,
shadowRadius: 5,
elevation: 6,
},
textStyle: {
fontSize: 20
}
})
export default Notification
\ No newline at end of file
import React, { useState, useEffect } from 'react';
import { TouchableOpacity } from 'react-native';
import { StyleSheet, TouchableWithoutFeedback, View, Text, Modal, FlatList, Animated } from 'react-native';
import Notification from './Notification';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
const SelectForm = (props) => {
const [option, setOption] = useState([])
const [optionId, setOptionId] = useState(0)
const [optionValue, setOptionValue] = useState('')
const [subOption, setSubOption] = useState([])
const [subOptionId, setSubOptionId] = useState(0)
const [text, setText] = useState('')
const [subOptionShow, setSubOptionShow] = useState(false)
const [modalOpen, setModalOpen] = useState(false)
const [notification, setNotification] = useState('')
const onPressSelectBox = () => { setModalOpen(true) }
const modalClose = () => { setModalOpen(false) }
const onPressOption = (item) => {
if (subOption !== undefined) {
if (subOptionShow) {
setSubOptionId(item.id)
props.onValueChange(optionId)
props.onSubValueChange(subOptionId)
setText(optionValue + ` > ${item.value}`)
modalClose()
} else {
setOptionId(item.id)
setOptionValue(item.value)
setSubOptionByOptionId(item)
}
} else {
props.onValueChange(item.id)
setOptionId(item.id)
setOptionValue(item.value)
setText(item.value)
modalClose()
}
}
const setSubOptionByOptionId = (item) => {
const newOption = props.subData.filter((subItem) => {
if (subItem.foreign_id === item.id)
return true;
})
if (newOption.length === 0) {
setNotification(`${item.value}의 세부 카테고리가 존재하지 않습니다.`)
} else {
setSubOption(newOption)
setSubOptionShow(true)
}
}
const renderOptionItem = ({ item }) => (
<TouchableOpacity onPress={() => onPressOption(item)} style={style.option}>
<Text style={style.optionText} >
{item.value}
</Text>
</TouchableOpacity>
);
useEffect(() => {
setOption(props.data)
setSubOption(props.subData)
setSubOptionShow(false)
}, [modalOpen])
return (
<View>
<View style={style.container}>
<View style={style.inputTitleArea}>
<Text style={style.inputTitle}>{props.inputTitle}</Text>
</View>
<View style={style.selectBox}>
<TouchableWithoutFeedback onPress={onPressSelectBox}>
<Text style={style.textStyle}>
{text ? text : props.placeholder}
</Text>
</TouchableWithoutFeedback>
</View>
</View>
<Modal
transparent
swipeDirection="down"
animationType="slide"
visible={modalOpen}
onRequestClose={modalClose}
>
<View style={style.selectModalContainer}>
<TouchableWithoutFeedback onPress={modalClose}>
<View style={{ flex: 1 }}>
<Notification notification={notification} setNotification={setNotification} />
</View>
</TouchableWithoutFeedback>
<View style={style.selectModal}>
<View style={style.modalHeader}>
{subOptionShow ?
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }} >
<MaterialCommunityIcons name='arrow-left' size={35} color='white' onPress={() => { setSubOptionShow(false); }} />
<Text style={style.modalHeaderText}>{optionValue}</Text>
</View>
:
<Text style={style.modalHeaderText}>{props.inputTitle}</Text>}
<View style={{ flexDirection: "row" }}>
<MaterialCommunityIcons name='playlist-edit' size={35} color='white' onPress={() => console.log('카테고리 편집')} />
<MaterialCommunityIcons name='close' size={35} color='white' onPress={modalClose} />
</View>
</View>
<View style={[style.modalBody, props.backdropStyle]}>
<FlatList
data={subOptionShow ? subOption : option}
renderItem={renderOptionItem}
numColumns={3}
keyExtractor={item => item.id.toString()}
/>
</View>
</View>
</View>
</Modal>
</View>
);
};
const style = StyleSheet.create({
container: {
height: 50,
flexDirection: 'row',
alignItems: "center",
marginHorizontal: 10,
marginVertical: 3,
borderWidth: 1.5,
borderStyle: "solid",
borderColor: "#1467ff",
borderRadius: 5,
backgroundColor: "#f5f5f5",
},
inputTitleArea: {
flex: 1,
},
inputTitle: {
alignSelf: "center",
color: "#1467ff",
fontSize: 20,
},
selectStyle: {
flex: 3,
fontSize: 20,
},
selectBox: {
flex: 3,
},
textStyle: {
fontSize: 20,
},
selectModalContainer: {
flex: 1,
justifyContent: 'flex-end',
},
selectModal: {
flex: 1,
},
modalHeader: {
flex: 1,
backgroundColor: '#4f4f4f',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
modalHeaderText: {
color: 'white',
marginLeft: 25,
fontSize: 20,
},
modalBody: {
flex: 5,
flexDirection: 'row',
backgroundColor: '#f0f0f0',
},
option: {
flex: 1,
height: 50,
borderWidth: 0.8,
borderStyle: 'solid',
borderColor: '#575757',
backgroundColor: '#adadad',
justifyContent: 'center',
alignItems: 'center',
},
optionText: {
fontSize: 20,
}
})
export default SelectForm
\ No newline at end of file
import React from 'react';
import { StyleSheet, Pressable, Text, View } from 'react-native';
const StyledButton = (props) => {
return (
<Pressable
style={({ pressed }) => [
{
backgroundColor: pressed ? '#437dd9' : '#4e8ff5',
},
style.pressableStyle,
props.style
]}
onPress={props.onPress}>
<Text style={style.buttonText}>{props.name}</Text>
</Pressable>
);
};
const style = StyleSheet.create({
pressableStyle: {
alignItems: "center",
justifyContent: "center",
marginRight: 3,
borderRadius: 2,
},
buttonText: {
fontSize: 20,
},
})
export default StyledButton
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment