diff --git a/node_modules/react-native/index.js b/node_modules/react-native/index.js index 6939b48..23679a1 100644 --- a/node_modules/react-native/index.js +++ b/node_modules/react-native/index.js @@ -756,4 +756,4 @@ if (__DEV__) { ); }, }); -} +} \ No newline at end of file diff --git a/package.json b/package.json index 0f3bf83..33e8e98 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "react-native-bouncy-checkbox": "^3.0.7", "react-native-collapsible-tab-view": "^6.2.1", "react-native-date-picker": "^5.0.0", - "react-native-document-picker": "^9.1.1", + "react-native-document-picker": "^9.3.0", "react-native-dotenv": "^3.4.9", "react-native-dropdown-picker": "^5.4.6", "react-native-gesture-handler": "^2.15.0", diff --git a/src/common/FileBox.tsx b/src/common/FileBox.tsx index 2433e10..61e1316 100644 --- a/src/common/FileBox.tsx +++ b/src/common/FileBox.tsx @@ -1,14 +1,22 @@ -import { View, TextInput, TextStyle, StyleSheet } from 'react-native'; +import { + View, + TextInput, + TextStyle, + StyleSheet, + TouchableOpacity, +} from 'react-native'; import styled from 'styled-components/native'; -import { BLACK2 } from '../styles/GlobalColor'; +import { BLACK, BLACK2 } from '../styles/GlobalColor'; import { Body14M } from '../styles/GlobalText'; import PlusIcon from '../assets/common/Plus.svg'; -import RightArrowIcon from '../assets/common/RightArrow.svg'; -import DownArrowIcon from '../assets/common/DownArrow.svg'; +import DeleteIcon from '../assets/header/Close.svg'; + import FilePicker from './FilePicker'; +import { Files } from '../types/UserTypes'; export interface FileBoxProps { - data: any[]; + data: Files; + setData: (r: Files) => void; max: number; } @@ -26,36 +34,77 @@ const SelectView = styled.View` margin-bottom: 5px; `; -const FileBox = ({ data, max }: FileBoxProps) => { +const FileBox = ({ data, setData, max }: FileBoxProps) => { + const handleFileDelete = (index: number) => { + const newData = data.filter((v, i) => i !== index); + setData(newData); + }; + return ( - - {}} - disabled={data.length >= max} - style={styles.BoxView}> - {data.length >= max ? ( - 더 이상 추가할 수 없습니다. - ) : ( - <> - 추가해 주세요 - - - )} - - + + + { + console.log(r); + setData([{ name: r.name ? r.name : 'noname', uri: r.uri }]); + }} + disabled={data.length >= max} + style={styles.BoxView}> + {data.length >= max ? ( + + 더 이상 추가할 수 없습니다 + + ) : ( + + 추가해 주세요 + + + )} + + + + {data.map((v, index) => { + return ( + + {v.name} + handleFileDelete(index)}> + + + + ); + })} + + ); }; const styles = StyleSheet.create({ BoxView: { display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', + justifyContent: 'center', alignItems: 'center', width: '100%', height: 44, paddingLeft: 16, paddingRight: 16, + gap: 10, + }, + ListView: { + display: 'flex', + alignItems: 'center', + width: '100%', + height: 44, + paddingLeft: 16, + paddingRight: 16, + marginTop: 10, + gap: 15, + }, + ItemView: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', }, }); diff --git a/src/common/FilePicker.tsx b/src/common/FilePicker.tsx index fc7df62..2833ed9 100644 --- a/src/common/FilePicker.tsx +++ b/src/common/FilePicker.tsx @@ -1,15 +1,14 @@ -import { ReactNode } from 'react'; -import { TouchableOpacity, ViewStyle } from 'react-native'; +import { Alert, TouchableOpacity, ViewStyle } from 'react-native'; import { - DocumentPickerOptions, DocumentPickerResponse, pick, + types, + isCancel, } from 'react-native-document-picker'; interface FilePickerProps { style?: ViewStyle; children?: any; - options?: DocumentPickerOptions<'android' | 'ios'>; callback: (r: DocumentPickerResponse) => void; disabled: boolean; } @@ -17,16 +16,21 @@ interface FilePickerProps { const FilePicker = ({ children, style, - options, callback, disabled, }: FilePickerProps) => { + const MEGABYTE = 1000000; + const handleFile = async () => { try { - const [selectedFile] = await pick(options); - callback(selectedFile); + const [selectedFile] = await pick({ type: [types.pdf] }); + if (selectedFile.size !== null && selectedFile.size > 20 * MEGABYTE) { + Alert.alert('크기 제한을 초과하는 파일입니다.'); + } else { + callback(selectedFile); + } } catch (e: unknown) { - console.log(e); + if (!isCancel(e)) Alert.alert('파일 업로드에 실패했습니다.'); } }; diff --git a/src/common/InputView.tsx b/src/common/InputView.tsx index 9846b04..95b3274 100644 --- a/src/common/InputView.tsx +++ b/src/common/InputView.tsx @@ -13,6 +13,7 @@ interface InputViewProps extends InputBoxProps { info?: string; caption?: { none?: false | string; + default?: false | string; invalid?: false | string; }; } @@ -73,6 +74,9 @@ const InputView = ({ {value === '' && caption?.none && ( {caption.none} )} + {caption?.default && ( + {caption.default} + )} {caption?.invalid && ( {caption.invalid} )} diff --git a/src/components/Auth/BasicForm.tsx b/src/components/Auth/BasicForm.tsx index 4bd17f0..37e822d 100644 --- a/src/components/Auth/BasicForm.tsx +++ b/src/components/Auth/BasicForm.tsx @@ -97,11 +97,26 @@ export default function BasicForm({ navigation, route }: FormProps) { d: false, }); const [checkPw, setCheckPw] = useState(''); - const [domainOpen, setDomainOpen] = useState(false); + const [invalidPw, setInvalidPw] = useState(undefined); const [modalOpen, setModalOpen] = useState(false); const [splash, setSplash] = useState(false); const request = Request(); + const passwordRegExp = new RegExp( + '^(?=.*[a-zA-Z])(?=.*[!@#$%^*+=-])(?=.*[0-9]).{8,15}$', + ); + + const passwordValidation = (callback: () => void) => { + if (passwordRegExp.exec(form.password)) { + callback(); + } else { + Alert.alert('비밀번호가 올바르지 않습니다.'); + setForm(prev => { + return { ...prev, password: '' }; + }); + setCheckPw(''); + } + }; const handleSubmit = async () => { const params = { @@ -199,11 +214,8 @@ export default function BasicForm({ navigation, route }: FormProps) { style={{ height: 44, marginTop: 8 }} secure={true} caption={{ - none: '비밀번호 조건', - invalid: - form.password !== '' && - form.password.length < 7 && - '비밀번호가 올바르지 않습니다.', + default: + '숫자, 영문, 특수문자를 하나 이상 포함해 8자 이상 16자 이하로 설정해 주세요.', }} /> @@ -303,7 +315,7 @@ export default function BasicForm({ navigation, route }: FormProps) { } value="다음" pressed={false} - onPress={handleSubmit} + onPress={() => passwordValidation(handleSubmit)} style={{ width: '75%', alignSelf: 'center', diff --git a/src/components/Auth/Reformer/CareerModal.tsx b/src/components/Auth/Reformer/CareerModal.tsx index 682614a..da6c9a1 100644 --- a/src/components/Auth/Reformer/CareerModal.tsx +++ b/src/components/Auth/Reformer/CareerModal.tsx @@ -92,7 +92,7 @@ export default function CareerModal({ const handleContentChange = (v: any, t: string) => { const prevCareer = form.career; prevCareer[index] = { ...prevCareer[index], [t]: v }; - // console.log(prevCareer[index]); + console.log(prevCareer[index]); setForm(prev => { return { ...prev, career: prevCareer }; }); @@ -357,9 +357,17 @@ export default function CareerModal({ 증빙자료첨부 - 선택사항 + + 선택사항 (pdf, 최대 20MB) + - + { + handleContentChange(r, 'file'); + }} + max={1} + /> diff --git a/src/types/UserTypes.ts b/src/types/UserTypes.ts index 327b15e..61975d5 100644 --- a/src/types/UserTypes.ts +++ b/src/types/UserTypes.ts @@ -1,6 +1,10 @@ type Styles = '빈티지' | '미니멀' | '캐주얼'; type Materials = '가죽' | '스웨이드' | '벨벳' | '데님' | '퍼' | '실크' | '울'; -type File = any[]; +interface File { + name: string; + uri: string; +} +export type Files = File[]; export type StyleType = Styles[]; export type MaterialType = Materials[]; @@ -9,13 +13,13 @@ export type EducType = { school: string; major: string; status: string | undefined; - file: File; + file: Files; // 파일 형식 추가 }; export type Careers = { name: string; - file: File; + file: Files; type: string | undefined; team?: string; position?: string; diff --git a/yarn.lock b/yarn.lock index acd563c..38d714e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6522,10 +6522,10 @@ react-native-date-picker@^5.0.0: resolved "https://registry.npmjs.org/react-native-date-picker/-/react-native-date-picker-5.0.0.tgz" integrity sha512-ApTKpZocalFCDMfczY34ugo85oQJfYO4VKqAxrtSFolzJdUqIJXa8ot0PIINokVI1O2X2L5hLboeqrM84GNfpQ== -react-native-document-picker@^9.1.1: - version "9.1.1" - resolved "https://registry.npmjs.org/react-native-document-picker/-/react-native-document-picker-9.1.1.tgz" - integrity sha512-BW+7DbsILuFThlBm7NUFVUmKKf6Awkcf9R0q8wiCU2DlGGtAKQTt2iHpO5+Dn/7WMPB+rqNv3X1HsmJQ0t5R3g== +react-native-document-picker@^9.3.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/react-native-document-picker/-/react-native-document-picker-9.3.0.tgz#4651d354623367d06397fe6dbf4a496f7d92ca6b" + integrity sha512-X/j0xKn8cObckpHTNwE/hW9WzBiP6oKx820FYu1Nat43QnnHmmT6uozFgAUDcJfxmZGcEdLlbv0lNhnyRXJyyA== dependencies: invariant "^2.2.4"