Commit 777c9deb authored by Soo Hyun Kim's avatar Soo Hyun Kim
Browse files

0802 카테고리 추가수정삭제 및 width 통일, getDate 수정

parent e69de6a5
......@@ -13,7 +13,7 @@ import DeptPage from './DeptPage';
import InfoDetails from './screens/InfoDetails';
import MemoPage from './MemoPage';
import MemoDetails from './screens/MemoDetails';
import CatEdit from './CatEdit';
import EditOption from './EditOption';
const Tab = createBottomTabNavigator();
const Stack = createStackNavigator();
......@@ -81,7 +81,11 @@ function App() {
component={MemoDetails}
options={{ title: "상세내용" }} />
<Stack.Screen name="DetailInfo" component={DetailInfo} />
<Stack.Screen name="CatEdit" component={CatEdit} />
<Stack.Screen
name="EditOption"
component={EditOption}
options={{ title: "편집" }}
/>
</Stack.Navigator>
</NavigationContainer>
);
......
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const CatEdit = ({ route }) => {
console.log('route', route.params)
console.log('---------------------------')
return (
<>
<View style={{ padding: '10%' }}>
<Text style={style.Font}>수입</Text>
<Text style={{ color: '#1E90FF' }}>{route.params?.input}</Text>
<Text>수입 내역들을 보여줄 예정입니다.</Text>
</View>
<View style={{ padding: '10%' }}>
<Text style={style.Font}>지출</Text>
<Text style={{ color: '#DC143C' }}>{route.params?.output}</Text>
<Text>지출 내역들을 보여줄 예정입니다.</Text>
</View>
</>
)
}
const style = StyleSheet.create({
Font: {
fontSize: 24
}
});
export default CatEdit;
\ No newline at end of file
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, FlatList, Modal, Pressable } from 'react-native';
import editApi from './db/editOption.api';
import AntDesign from 'react-native-vector-icons/AntDesign';
import InputBox from './components/InputBox';
import StyledButton from './components/StyledButton';
import Accordion from './components/Accordion';
const INIT_OPTION = { id: 0, value: '' }
const TEST_OPTION = { id: 15, value: 'testtest' }
const TEST_SUB = [{
id: 1, value: 'test1',
},
{
id: 2, value: 'test2'
}]
const EditOption = ({ route }) => {
console.log('catEdit: type_id ', route.params)
const type_id = route.params
const [options, setOptions] = useState([])
const [option, setOption] = useState(INIT_OPTION)
const [modalOpen, setModalOpen] = useState(false)
const modalClose = () => { setModalOpen(false); setOption(INIT_OPTION) }
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
if (type_id > 0) {
loadCat()
} else {
loadAsset()
}
}, [])
const loadCat = async () => {
try {
const catArray = await editApi.selectCategories(type_id)
setOptions(catArray)
} catch (error) {
}
}
const loadAsset = async () => {
try {
const assetArray = await editApi.selectAssetsType()
setOptions(assetArray)
} catch (error) {
}
}
const handleUpdate = () => {
if (type_id > 0) {
updateCat()
} else {
updateAsset()
}
}
const updateAsset = async () => {
try {
const res = await editApi.updateOption('assets_type', { id: option.id, name: 'assets', value: option.value })
console.log(res)
loadAsset()
modalClose()
} catch (error) {
}
}
const updateCat = async () => {
try {
const res = await editApi.updateOption('categories', { id: option.id, name: 'category', value: option.value })
console.log(res)
loadCat()
modalClose()
} catch (error) {
}
}
const handleDelete = (item) => {
if (type_id > 0) {
deleteCat(item)
} else {
deleteAsset(item)
}
}
const deleteAsset = async (item) => {
try {
const res = await editApi.deleteOption('assets_type', { id: item.id, name: 'assets' })
console.log(res)
loadAsset()
modalClose()
} catch (error) {
}
}
const deleteCat = async (item) => {
try {
const res = await editApi.deleteOption('categories', { id: item.id, name: 'category' })
console.log(res)
loadCat()
modalClose()
} catch (error) {
}
}
const handleAdd = () => {
if (type_id > 0) {
addCat()
} else {
addAsset()
}
}
const addAsset = async () => {
try {
const res = await editApi.addOption('assets_type', { name: 'assets', value: option.value })
console.log(res)
loadAsset()
modalClose()
} catch (error) {
}
}
const addCat = async () => {
try {
const res = await editApi.addOption('categories', { name: 'category', value: option.value, foreign_name: 'type', foreign_id: type_id })
console.log(res)
loadCat()
modalClose()
} catch (error) {
}
}
const renderOptionItem = ({ item }) => (
<View style={[style.flexRow, style.catBox]}>
<View style={style.flexRow}>
{item.deletable && <AntDesign name='minuscircle' style={style.cancelIcon} onPress={() => { handleDelete(item) }} />}
<Text style={style.optionText} >
{item.value}
</Text>
</View>
<View style={[style.flexRow, style.flexCenter]}>
{item.deletable && <AntDesign name='edit' style={style.icon} onPress={() => { setOption(item); setModalOpen(true) }} />}
<AntDesign name='right' style={style.rightIcon} onPress={() => console.log('서브 카테고리 더보기')} />
</View>
</View>
);
return (
<>
{console.log(option)}
<View>
<FlatList
data={options}
renderItem={renderOptionItem}
keyExtractor={item => item.id.toString()}
/>
<Accordion subItems={TEST_SUB}>
<View style={[style.flexRow, style.catBox]}>
<View style={style.flexRow}>
<AntDesign name='minuscircle' style={style.cancelIcon} onPress={() => { handleDelete({ TEST_OPTION }) }} />
<Text style={style.optionText} >
{TEST_OPTION.value}
</Text>
</View>
<View style={[style.flexRow, style.flexCenter]}>
<AntDesign name='edit' style={style.icon} onPress={() => { setOption(TEST_OPTION); setModalOpen(true) }} />
<AntDesign name='right' style={style.rightIcon} onPress={() => console.log('서브 카테고리 더보기')} />
</View>
</View>
</Accordion>
<Pressable style={style.addButton} onPress={() => setModalOpen(true)}>
<AntDesign name='plus' style={style.icon} />
<Text style={style.optionText} >추가하기</Text>
</Pressable>
</View>
<Modal
transparent
swipeDirection="down"
animationType_id="fade"
visible={modalOpen}
onRequestClose={modalClose}
>
<View style={style.modalContainer}>
<View style={style.modalHeader}>
<View style={{ flexDirection: "row" }}>
<AntDesign name='caretleft' style={style.icon} onPress={() => modalClose()} />
<Text style={style.Font}>{option.id === 0 ? '추가' : '수정'}</Text>
</View>
</View>
<View style={style.modalBody}>
<InputBox
placeholder="이름을 입력하세요."
onChangeText={
(name) => setOption({ ...option, value: name })
}
value={option.value}
maxLength={30}
/>
<View style={style.buttonRow}>
<StyledButton
name="저장하기"
onPress={option.id === 0 ? handleAdd : handleUpdate}
style={style.submitButton}
/>
</View>
</View>
</View>
</Modal>
</>
)
}
const style = StyleSheet.create({
flexRow: {
flexDirection: 'row',
},
flexCenter: {
justifyContent: 'center',
alignItems: 'center',
},
catBox: {
justifyContent: 'space-between',
paddingVertical: 10,
backgroundColor: 'lightgray',
},
Font: {
fontSize: 24
},
icon: {
marginHorizontal: 5,
fontSize: 30,
color: 'black',
},
cancelIcon: {
marginHorizontal: 5,
fontSize: 30,
color: 'red',
},
rightIcon: {
marginHorizontal: 5,
fontSize: 20,
color: 'black',
},
optionText: {
fontSize: 20,
marginHorizontal: 10,
},
addButton: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
paddingVertical: 10,
backgroundColor: 'gray',
margin: 15
},
modalContainer: {
flex: 1,
backgroundColor: 'white',
},
modalHeader: {
padding: 10,
},
modalBody: {
},
buttonRow: {
flexDirection: 'row',
alignItems: "center",
marginHorizontal: 10,
marginVertical: 3,
},
submitButton: {
flex: 1,
height: 50,
},
});
export default EditOption;
\ No newline at end of file
......@@ -6,11 +6,7 @@ import SelectForm from './components/SelectForm';
import StyledButton from './components/StyledButton';
import DatePicker from './components/DatePicker';
import moneyApi from './db/postMoney.api';
const getDate = () => {
var date = new Date();
return (String(date.toJSON()).split(/T/)[0])
}
import { getDate } from './utils/dateFunction'
const INIT_ASSETSTYPE = {
id: 0,
......@@ -28,13 +24,14 @@ const INIT_SUBCATEGORY = {
foreign_id: 0,
}
const PostMoney = () => {
const PostMoney = ({navigation}) => {
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(INIT_ASSETSTYPE)
const [selected_deposit_asset_type, setSelected_deposit_asset_type] = useState(INIT_ASSETSTYPE)
const [categories, setCategories] = useState([])
const [selected_cat, setSelected_cat] = useState(INIT_CATEGORY)
const [subcategories, setSubcategories] = useState([])
......@@ -56,11 +53,19 @@ const PostMoney = () => {
setSelected_subcat(INIT_SUBCATEGORY)
}
console.log('type: ', selectedIndex, '| date: ', date, '| contents: ', contents, '| price: ', price, '| selected_asset_type: ', selected_asset_type.id, '| selected_cat: ', selected_cat.id, '| selected_subcat: ', selected_subcat.id)
console.log(
'type: ', selectedIndex,
'| date: ', date,
'| contents: ', contents,
'| price: ', price,
'| selected_asset_type: ', selected_asset_type.id,
(selectedIndex === 2 ? { ['selected_deposit_asset_type']: selected_deposit_asset_type.id } : null),
'| selected_cat: ', selected_cat.id,
'| selected_subcat: ', selected_subcat.id)
const insertData = async () => {
try {
let type = selectedIndex+1;
let type = selectedIndex + 1;
const result = await moneyApi.insertMoney([type, date, contents, price, selected_asset_type.id, selected_cat.id, selected_subcat.id])
console.log(result)
} catch (error) {
......@@ -70,7 +75,7 @@ const PostMoney = () => {
const loadCat = async () => {
try {
const catArray = await moneyApi.selectCategories(selectedIndex+1)
const catArray = await moneyApi.selectCategories(selectedIndex + 1)
console.log('catload', catArray)
setCategories(catArray);
} catch (error) {
......@@ -97,6 +102,14 @@ const PostMoney = () => {
}
}
const onUpdateCatPress = () => {
navigation.navigate('EditOption', selectedIndex+1)
}
const onUpdateAssetPress = () => {
navigation.navigate('EditOption', 0)
}
return (
<View>
<View>
......@@ -127,12 +140,22 @@ const PostMoney = () => {
maxLength={30}
/>
<SelectForm
inputTitle="자산"
inputTitle={selectedIndex === 2 ? "출금" : "자산"}
placeholder="자산 선택"
data={asset_type}
selectedData={selected_asset_type}
onValueChange={(asset) => setSelected_asset_type(asset)}
onUpdateDataPress={onUpdateAssetPress}
/>
{selectedIndex === 2 &&
<SelectForm
inputTitle="입금"
placeholder="자산 선택"
data={asset_type}
selectedData={selected_deposit_asset_type}
onValueChange={(deposit_asset) => setSelected_deposit_asset_type(deposit_asset)}
onUpdateDataPress={onUpdateAssetPress}
/>}
<SelectForm
inputTitle="구분"
placeholder="카테고리 선택"
......@@ -142,6 +165,7 @@ const PostMoney = () => {
subData={subcategories}
selectedSubData={selected_subcat}
onSubValueChange={(subcat) => setSelected_subcat(subcat)}
onUpdateDataPress={onUpdateCatPress}
/>
</View>
<View style={style.buttonRow}>
......
import React, { useEffect, useRef, useState } from 'react';
import { Animated, Text, View, StyleSheet, TouchableOpacity, FlatList } from 'react-native';
const renderOptionItem = ({ item }) => (
<View style={[style.flexRow, style.catBox]}>
<View style={style.flexRow}>
{/* { item.deletable && <AntDesign name='minuscircle' style={style.cancelIcon} onPress={() => { handleDelete(item) }} />} */}
<Text style={style.optionText} >
{item.value}
</Text>
</View>
{/* <View style={[style.flexRow, style.flexCenter]}>
{ item.deletable && <AntDesign name='edit' style={style.icon} onPress={() => { setOption(item); setModalOpen(true) }} /> }
<AntDesign name='right' style={style.rightIcon} onPress={() => console.log('서브 카테고리 더보기')}/>
</View> */}
</View>
);
const Accordion = ({
item,
subItems,
children
}) => {
let layoutHeight = 0;
const [bodyMounted, setBodyMounted] = useState(false);
const [bodyHeight, setBodyHeight] = useState(0);
let dropDownAnimValueList = useRef(new Animated.Value(0)).current;
const handleBodyLayout = (e) => {
if (bodyMounted) return;
console.log(e.nativeEvent.layout)
const { height } = e.nativeEvent.layout;
layoutHeight = height;
setBodyMounted(true);
setBodyHeight(height);
}
const [open, setOpen] = useState(false);
// const openList = () => {
// Animated.timing(dropDownAnimValueList, {
// toValue: 0,
// duration: 500,
// useNativeDriver: true,
// })
// }
// const closeList = () => {
// Animated.timing(dropDownAnimValueList, {
// toValue: -bodyHeight,
// duration: 500,
// useNativeDriver: true,
// })
// }
useEffect(() => {
if (bodyMounted) dropDownAnimValueList.setValue(open ? -layoutHeight : 0);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [bodyMounted]);
useEffect(() => {
// if (shouldAnimate) {
// if (!opened) {
// Animated.timing(dropDownAnimValueList, {
// toValue: 0,
// duration: animDuration || 300,
// useNativeDriver: true,
// }).start();
// return;
// }
// Animated.timing(dropDownAnimValueList, {
// toValue: -bodyHeight,
// duration: animDuration || 300,
// useNativeDriver: true,
// }).start();
// } else {
const targetValue = open ? -bodyHeight : 0;
dropDownAnimValueList.setValue(targetValue);
// }
// if (open) dropDownAnimValueList.setValue(open ? -layoutHeight : 0);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open]);
console.log(open)
return (
<Animated.View style={[
{
overflow: 'hidden',
transform: [{
translateY: 0,
}],
},
]}>
<View style={[style.boxContainer]}>
<Text>D</Text>
<TouchableOpacity style={style.zIndex} onPress={() => { setOpen(!open) }}>
{children}
</TouchableOpacity>
</View>
<Animated.View style={{
height: !bodyMounted ? undefined : bodyHeight,
transform: [
{
translateY: dropDownAnimValueList,
},
],
}}
onLayout={handleBodyLayout}>
<Text style={{ backgroundColor: 'red' }}>테스트</Text>
<FlatList
data={subItems}
renderItem={renderOptionItem}
keyExtractor={item => item.id.toString()}
/>
</Animated.View>
</Animated.View>
)
}
const style = StyleSheet.create({
boxContainer: {
width: '100%',
position: 'relative',
},
flexRow: {
flexDirection: 'row',
},
flexCenter: {
justifyContent: 'center',
alignItems: 'center',
},
catBox: {
justifyContent: 'space-between',
paddingVertical: 10,
backgroundColor: 'lightgray',
},
zIndex: {
position: 'absolute',
zIndex: 15,
elevation: 1000,
},
icon: {
marginHorizontal: 5,
fontSize: 30,
color: 'black',
},
cancelIcon: {
marginHorizontal: 5,
fontSize: 30,
color: 'red',
},
rightIcon: {
marginHorizontal: 5,
fontSize: 20,
color: 'black',
},
optionText: {
fontSize: 20,
marginHorizontal: 10,
},
items: {
overflow: "hidden"
}
})
export default Accordion
\ No newline at end of file
......@@ -4,9 +4,11 @@ import { StyleSheet, Text, View, TextInput } from 'react-native';
const InputBox = (props) => {
return (
<View style={style.container}>
{props.inputTitle &&
<View style={style.inputTitleArea}>
<Text style={style.inputTitle}>{props.inputTitle}</Text>
</View>
}
<TextInput
underlineColorAndroid="transparent"
placeholder={props.placeholder}
......
import React, { useState, useEffect } from 'react';
import { TouchableOpacity } from 'react-native';
import { StyleSheet, TouchableWithoutFeedback, View, Text, Modal, FlatList } from 'react-native';
import { StyleSheet, TouchableOpacity, TouchableWithoutFeedback, View, Text, Modal, FlatList } from 'react-native';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
const INIT_SUBCATEGORY = {
......@@ -18,6 +17,7 @@ const SelectForm = ({
subData,
selectedSubData,
onSubValueChange,
onUpdateDataPress,
}) => {
const [option, setOption] = useState([])
const [subOption, setSubOption] = useState([])
......@@ -32,6 +32,9 @@ const SelectForm = ({
const modalClose = () => { setModalOpen(false); }
const onPressOption = (item) => {
if (item.id === 0) {
return null
}
if (subOption !== undefined) {
if (subOptionShow) {
onValueChange(selectedOption)
......@@ -57,10 +60,19 @@ const SelectForm = ({
onSubValueChange(INIT_SUBCATEGORY)
modalClose()
} else {
if (newOption.length % 3 == 0) {
setSubOption(newOption)
setSubOptionShow(true)
} else {
for (let i = 0; i < (newOption.length % 3); i++) {
newOption.push(INIT_SUBCATEGORY)
}
setSubOption(newOption)
setSubOptionShow(true)
}
}
}
const renderOptionItem = ({ item }) => (
<TouchableOpacity onPress={() => onPressOption(item)} style={style.option}>
<Text style={style.optionText} >
......@@ -115,7 +127,7 @@ const SelectForm = ({
:
<Text style={style.modalHeaderText}>{inputTitle}</Text>}
<View style={{ flexDirection: "row" }}>
<MaterialCommunityIcons name='playlist-edit' size={35} color='white' onPress={() => console.log('카테고리 편집')} />
<MaterialCommunityIcons name='playlist-edit' size={35} color='white' onPress={() => { modalClose(); setTimeout(() => { onUpdateDataPress() }, 500) }} />
<MaterialCommunityIcons name='close' size={35} color='white' onPress={modalClose} />
</View>
</View>
......
import { DEBUG, enablePromise } from 'react-native-sqlite-storage';
import getDb from './moneyDB'
DEBUG(true);
enablePromise(true);
const CAT_LIMIT_ID = 14
const ASSET_LIMIT_ID = 10
const selectCategories = async (type_id) => {
const db = await getDb();
return new Promise((resolve, reject) => {
db.transaction(async (tx) => {
console.log("카테고리 부르기");
const [txn, results] = await tx.executeSql(`SELECT * FROM categories WHERE type_id=${type_id}`);
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;
if (tempId < CAT_LIMIT_ID) {
temp.push({ id: tempId, value: tempName, deletable: false });
} else {
temp.push({ id: tempId, value: tempName, deletable: true });
}
}
console.log(temp)
resolve(temp);
})
})
}
const selectAssetsType = async () => {
const db = await getDb();
return new Promise((resolve, reject) => {
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;
if (tempId < ASSET_LIMIT_ID) {
temp.push({ id: tempId, value: tempName, deletable: false });
} else {
temp.push({ id: tempId, value: tempName, deletable: true });
}
}
console.log(temp)
resolve(temp);
})
})
}
const deleteOption = async (table, data) => {
const db = await getDb();
const { id, name } = data
return new Promise((resolve, reject) => {
db.transaction((tx) => {
console.log("데이터 삭제하기");
tx.executeSql(`DELETE FROM ${table} WHERE ${name}_id = ${id};`)
resolve(`${name} 데이터 삭제 완료`);
})
})
}
const updateOption = async (table, data) => {
const db = await getDb();
const { id, name, value } = data
console.log(table, id, value)
return new Promise((resolve, reject) => {
db.transaction((tx) => {
console.log("데이터 수정하기");
tx.executeSql(`UPDATE ${table} set ${name}_name =? where ${name}_id =${id};`,
[value],
(error) => console.log(error))
resolve(`${name} 데이터 변경 완료`);
})
})
};
const addOption = async (table, data) => {
const db = await getDb();
const { name, value, foreign_name = null, foreign_id } = data;
let insertQeury = '';
let queryData = [];
if (foreign_name === null) {
insertQeury = `INSERT INTO ${table} (${name}_name) VALUES (?);`
queryData = [value]
} else {
insertQeury = `INSERT INTO ${table} (${name}_name, ${foreign_name}_id) VALUES (?,?);`
queryData = [value, foreign_id]
}
// console.log(insertQuery, queryData)
return new Promise((resolve, reject) => {
db.transaction((tx) => {
console.log("데이터 삽입하기");
tx.executeSql(insertQeury,
queryData,
(error) => console.log(error))
resolve('데이터 삽입 카테고리 카테고리 완료');
})
})
};
const editApi = {
selectCategories,
selectAssetsType,
deleteOption,
updateOption,
addOption,
}
export default editApi;
\ No newline at end of file
......@@ -25,10 +25,14 @@ const selectCategories = async (type_id) => {
const [txn, results] = await tx.executeSql(`SELECT * FROM categories WHERE type_id=${type_id}`);
console.log('item length', results.rows.length);
const temp = [];
for (let i = 0; i < results.rows.length; i++) {
for (let i = 0; i < 3*(Math.ceil(results.rows.length/3)); i++) {
if (i<results.rows.length){
const tempId = results.rows.item(i).category_id;
const tempName = results.rows.item(i).category_name;
temp.push({ id: tempId, value: tempName });
} else {
temp.push({ id: 0, value: '' });
}
}
console.log(temp)
resolve(temp);
......@@ -64,10 +68,14 @@ const selectAssetsType = async () => {
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++) {
for (let i = 0; i < 3*(Math.ceil(results.rows.length/3)); i++) {
if (i<results.rows.length){
const tempId = results.rows.item(i).assets_id;
const tempName = results.rows.item(i).assets_name;
temp.push({ id: tempId, value: tempName });
} else {
temp.push({ id: 0, value: '' });
}
}
console.log(temp)
resolve(temp);
......
export function getDate () {
const date = new Date();
const tempY = date.getFullYear();
let tempM = date.getMonth();
tempM = tempM > 9 ? tempM : "0" + tempM;
let tempD = date.getDate();
tempD = tempD > 9 ? tempD : "0" + tempD;
return `${tempY}-${tempM}-${tempD}`
}
\ 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