Skip to content

Commit

Permalink
#77 feat: add common dropdown component (#80)
Browse files Browse the repository at this point in the history
* #77 feat: add ComponentsTest page at Home

* #77 refactor: refactor dropdown component

* #77 fix: set overlap order between dropdowns at same level

* #77 feat: add dropdown with write option

* #77 feat: replace dropdown component
  • Loading branch information
eujin-shin authored Jun 22, 2024
1 parent c3298cc commit 6ac2a6e
Show file tree
Hide file tree
Showing 5 changed files with 257 additions and 99 deletions.
137 changes: 98 additions & 39 deletions src/common/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,116 @@
import { Dispatch, SetStateAction } from 'react';
import { View, TouchableOpacity, ViewStyle } from 'react-native';
import { Dispatch, SetStateAction, useState } from 'react';
import {
View,
TouchableOpacity,
ViewStyle,
StyleSheet,
DimensionValue,
ScrollView,
} from 'react-native';
import { Body14M } from '../styles/GlobalText';
import { BLACK, BLACK2, GRAY } from '../styles/GlobalColor';
import ArrowIcon from '../assets/common/Arrow.svg';

export interface DropdownProps {
items: string[];
value: string | undefined | null;
interface DropdownProps {
title: string;
value: string | undefined;
setValue: (text: string) => void;
setOpen: Dispatch<SetStateAction<boolean>>;
open: boolean;
items: string[];
index?: number | undefined; // 동일 레벨에서 dropdown을 여러번 사용할 경우 z-index 사용
width?: DimensionValue;
style?: ViewStyle;
}
const ITEM_HEIGHT = 40;

export default function Dropdown({
items,
value,
setValue,
setOpen,
open,
title,
style,
setValue,
value,
items,
index = undefined,
width = '90%',
}: DropdownProps) {
const handleSelect = (text: string) => {
setValue(text);
const [open, setOpen] = useState(false);

const handlePress = () => {
setOpen(prev => !prev);
};

const handleSelect = (value: string) => {
setValue(value);
setOpen(false);
};

return (
<View
style={{
position: 'absolute',
display: 'flex',
flexDirection: 'column',
borderBottomWidth: 0,
zIndex: 1,
...style,
position: 'relative',
height: ITEM_HEIGHT + 4,
marginVertical: 8,
zIndex: index,
}}>
{open &&
items.map((item, index) => {
return (
<View key={index}>
<TouchableOpacity
onPress={() => {
handleSelect(item);
}}
style={{
backgroundColor: 'white',
paddingLeft: 16,
height: 30,
borderWidth: 1,
}}>
<Body14M>{item}</Body14M>
</TouchableOpacity>
</View>
);
})}
<View
style={{
width: width,
...style,
...Styles.container,
}}>
<View style={{ ...Styles.item }}>
<TouchableOpacity
style={{
...Styles.pressArea,
}}
onPress={handlePress}>
<Body14M>{value !== undefined ? value : title}</Body14M>
<ArrowIcon
color={BLACK2}
style={{ transform: [{ rotate: open ? '270deg' : '180deg' }] }}
/>
</TouchableOpacity>
</View>
<ScrollView
style={{
maxHeight: open ? ITEM_HEIGHT * 3 : ITEM_HEIGHT + 4,
borderTopWidth: open ? 2 : 0,
borderColor: BLACK2,
}}>
{open &&
items.map((value, index) => {
return (
<View style={Styles.item} key={index}>
<TouchableOpacity
style={Styles.pressArea}
onPress={() => handleSelect(value)}>
<Body14M>{value}</Body14M>
</TouchableOpacity>
</View>
);
})}
</ScrollView>
</View>
</View>
);
}

const Styles = StyleSheet.create({
container: {
position: 'absolute',
alignSelf: 'center',
borderWidth: 2,
borderRadius: 5,
borderColor: BLACK2,
backgroundColor: 'white',
},
item: {
height: ITEM_HEIGHT,
paddingHorizontal: 16,
borderColor: BLACK2,
},
pressArea: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
flex: 1,
},
});
113 changes: 113 additions & 0 deletions src/common/DropdownWrite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { useState } from 'react';
import {
View,
TouchableOpacity,
StyleSheet,
ScrollView,
TextInput,
} from 'react-native';
import { Body14M } from '../styles/GlobalText';
import { BLACK2 } from '../styles/GlobalColor';
import Dropdown from './Dropdown';
import ArrowIcon from '../assets/common/Arrow.svg';

const ITEM_HEIGHT = 40;

export default function DropdownWrite({
title,
style,
setValue,
value,
items,
index = undefined,
width = '90%',
}: Parameters<typeof Dropdown>[0]) {
const [open, setOpen] = useState(false);

const handlePress = () => {
setOpen(prev => !prev);
};

const handleSelect = (value: string) => {
setValue(value);
setOpen(false);
};

return (
<View
style={{
width: width,
position: 'relative',
height: ITEM_HEIGHT + 4,
marginVertical: 8,
zIndex: index,
}}>
<View
style={{
...style,
...Styles.container,
}}>
<View style={{ ...Styles.pressArea, ...Styles.item }}>
<TextInput
defaultValue={value}
onChangeText={setValue}
placeholderTextColor={BLACK2}
placeholder={title}
autoCapitalize="none"
autoCorrect={false}
style={{ flex: 1 }}
/>
<TouchableOpacity onPress={handlePress}>
<ArrowIcon
color={BLACK2}
style={{ transform: [{ rotate: open ? '270deg' : '180deg' }] }}
/>
</TouchableOpacity>
</View>
<ScrollView
style={{
maxHeight: open ? ITEM_HEIGHT * 3 : ITEM_HEIGHT + 4,
borderTopWidth: open ? 2 : 0,
borderColor: BLACK2,
}}>
{open &&
items.map((value, index) => {
return (
<View style={Styles.item} key={index}>
<TouchableOpacity
style={Styles.pressArea}
onPress={() => handleSelect(value)}>
<Body14M>{value}</Body14M>
</TouchableOpacity>
</View>
);
})}
</ScrollView>
</View>
</View>
);
}

const Styles = StyleSheet.create({
container: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
alignSelf: 'center',
borderWidth: 2,
borderRadius: 5,
borderColor: BLACK2,
backgroundColor: 'white',
},
item: {
height: ITEM_HEIGHT,
paddingHorizontal: 16,
},
pressArea: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
flex: 1,
},
});
62 changes: 22 additions & 40 deletions src/components/Auth/BasicForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
import SelectBox from '../../common/SelectBox';
import BasicSignupSplash from './BasicSignupSplash';
import CustomScrollView from '../../common/CustomScrollView';
import DropdownWrite from '../../common/DropdownWrite';

interface SignupProps {
mail: string;
domain: string;
domain: string | undefined;
password: string;
region: string;
}
Expand Down Expand Up @@ -85,7 +86,7 @@ export default function BasicForm({ navigation, route }: FormProps) {
const { width, height } = Dimensions.get('window');
const [form, setForm] = useState<SignupProps>({
mail: '',
domain: '',
domain: undefined,
password: '',
region: '',
});
Expand Down Expand Up @@ -155,7 +156,13 @@ export default function BasicForm({ navigation, route }: FormProps) {
}}>
<SectionView style={{ zIndex: 1 }}>
<Body16B>이메일</Body16B>
<MailView>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
}}>
<InputBox
value={form.mail}
setValue={text =>
Expand All @@ -167,43 +174,18 @@ export default function BasicForm({ navigation, route }: FormProps) {
style={{ height: 44, marginTop: 8, width: '44%' }}
/>
<Body16M style={{ color: BLACK2 }}>@</Body16M>
<SelectView>
<TextInput
value={form.domain}
onChangeText={text =>
setForm(prev => {
return { ...prev, domain: text };
})
}
style={{ width: '70%' }}
placeholder="직접 입력"
placeholderTextColor={BLACK2}
readOnly={false}
autoCapitalize="none"
autoCorrect={false}
/>
<Dropdown
open={domainOpen}
setOpen={setDomainOpen}
value={form.domain}
setValue={text =>
setForm(prev => {
return { ...prev, domain: text };
})
}
items={['gmail.com', 'naver.com', 'kakao.com']}
style={{ width: '100%', top: 44 }}
/>
<TouchableOpacity
onPress={() =>
setDomainOpen(prev => {
return !prev;
})
}>
<DownArrow />
</TouchableOpacity>
</SelectView>
</MailView>
<DropdownWrite
title="직접 입력"
width="44%"
value={form.domain}
setValue={text =>
setForm(prev => {
return { ...prev, domain: text };
})
}
items={['gmail.com', 'naver.com', 'kakao.com']}
/>
</View>
</SectionView>
<InputView
title="비밀번호"
Expand Down
11 changes: 9 additions & 2 deletions src/components/Auth/Reformer/CareerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,14 @@ export default function CareerModal({
</View>
<View style={{ zIndex: 1 }}>
<Body16B>분류</Body16B>
<SelectBox
<Dropdown
title="선택하기"
width="100%"
value={form.career[index].type}
items={statusList}
setValue={handleTypeChange}
/>
{/* <SelectBox
value={form.career[index].type}
onPress={() => {
setDropdown(prev => {
Expand All @@ -343,7 +350,7 @@ export default function CareerModal({
top: 80,
}}
/>
)}
)} */}
</View>
{detailSection()}
<View style={{ marginVertical: 10 }}>
Expand Down
Loading

0 comments on commit 6ac2a6e

Please sign in to comment.