Skip to content

Commit

Permalink
#25 feat: add photo options component (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
SJ-Kwak authored Feb 14, 2024
1 parent 6e104b6 commit dbbd3ac
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 18 deletions.
28 changes: 26 additions & 2 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -944,12 +944,24 @@ PODS:
- React-Mapbuffer (0.73.2):
- glog
- React-debug
- react-native-image-picker (7.1.0):
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- react-native-pager-view (6.2.3):
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- react-native-safe-area-context (4.8.2):
- React-Core
- react-native-slider (4.5.0):
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- react-native-webview (13.7.1):
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
- React-nativeconfig (0.73.2)
- React-NativeModulesApple (0.73.2):
- glog
Expand Down Expand Up @@ -1190,8 +1202,11 @@ DEPENDENCIES:
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
- react-native-pager-view (from `../node_modules/react-native-pager-view`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-webview (from `../node_modules/react-native-webview`)
- React-nativeconfig (from `../node_modules/react-native/ReactCommon`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
Expand Down Expand Up @@ -1291,10 +1306,16 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/logger"
React-Mapbuffer:
:path: "../node_modules/react-native/ReactCommon"
react-native-image-picker:
:path: "../node_modules/react-native-image-picker"
react-native-pager-view:
:path: "../node_modules/react-native-pager-view"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-slider:
:path: "../node_modules/@react-native-community/slider"
react-native-webview:
:path: "../node_modules/react-native-webview"
React-nativeconfig:
:path: "../node_modules/react-native/ReactCommon"
React-NativeModulesApple:
Expand Down Expand Up @@ -1363,7 +1384,7 @@ SPEC CHECKSUMS:
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
FlipperKit: 37525a5d056ef9b93d1578e04bc3ea1de940094f
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: 035f1e36e53b355cf70f6434d161b36e7d21fecd
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
hermes-engine: 34df9d5034e90bd9bf1505e1ca198760373935af
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
Expand All @@ -1388,8 +1409,11 @@ SPEC CHECKSUMS:
React-jsinspector: 03644c063fc3621c9a4e8bf263a8150909129618
React-logger: 66b168e2b2bee57bd8ce9e69f739d805732a5570
React-Mapbuffer: 9ee041e1d7be96da6d76a251f92e72b711c651d6
react-native-image-picker: 6c51359eca7a7df9f07e297218c25696eb9da976
react-native-pager-view: d81ab2060b9caf57ca8c3a0d57467ff407cdb825
react-native-safe-area-context: 0ee144a6170530ccc37a0fd9388e28d06f516a89
react-native-slider: 7d387c7e8dd0b4c12bf49c975c8666435f082a33
react-native-webview: d35380fcc2e1385cebc5b90fb96eebcdd1f2548e
React-nativeconfig: d753fbbc8cecc8ae413d615599ac378bbf6999bb
React-NativeModulesApple: 964f4eeab1b4325e8b6a799cf4444c3fd4eb0a9c
React-perflogger: 29efe63b7ef5fbaaa50ef6eaa92482f98a24b97e
Expand Down Expand Up @@ -1420,4 +1444,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: eb490ed861c0caf2f2649ac9503532c4cce2d3d8

COCOAPODS: 1.12.1
COCOAPODS: 1.14.3
12 changes: 10 additions & 2 deletions ios/upcy.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,11 @@
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
OTHER_LDFLAGS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down Expand Up @@ -759,7 +763,11 @@
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
OTHER_LDFLAGS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"react-native-collapsible-tab-view": "^6.2.1",
"react-native-dotenv": "^3.4.9",
"react-native-gesture-handler": "^2.14.0",
"react-native-image-picker": "^7.1.0",
"react-native-keychain": "^8.1.2",
"react-native-pager-view": "^6.2.3",
"react-native-pell-rich-editor": "^1.9.0",
Expand Down
154 changes: 154 additions & 0 deletions src/common/PhotoOptions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import React, {
Dispatch,
ReactElement,
ReactNode,
SetStateAction,
useCallback,
} from 'react';
import { Alert, TouchableOpacity, View, Text } from 'react-native';
import * as ImagePicker from 'react-native-image-picker';
import styled from 'styled-components/native';
import PhotoIcon from '../assets/common/Photo.svg';
import { Body14M } from '../styles/GlobalText';
import { LIGHTGRAY } from '../styles/GlobalColor';

const PhotosInput = styled.View`
display: flex;
flex-flow: row wrap;
`;

interface Action {
title: string;
type: 'capture' | 'library';
options: ImagePicker.CameraOptions | ImagePicker.ImageLibraryOptions;
}

interface PhotoProps {
buttonLabel: string;
photo: any;
setPhoto: Dispatch<SetStateAction<any>>;
max: number;
}

export interface PhotoResultProps {
fileName: string;
width: number;
height: number;
uri: string;
}

const PhotoOptions = ({ buttonLabel, photo, setPhoto, max }: PhotoProps) => {
const CameraActions: Action[] = [
//카메라 & 갤러리 세팅
{
title: "카메라",
type: "capture",
options: {
selectionLimit: max,
mediaType: "photo",
includeBase64: false,
maxHeight: 300,
maxWidth: 300,
},
},
{
title: "앨범",
type: "library",
options: {
selectionLimit: max,
mediaType: "photo",
includeBase64: false,
maxHeight: 300,
maxWidth: 300,
},
},
];
// const onButtonPress = useCallback(
// (
// type: string,
// options: ImagePicker.CameraOptions | ImagePicker.ImageLibraryOptions
// ) => {
// //카메라 & 갤러리 열기
// if (type === "capture") {
// ImagePicker.launchCamera(options, (response) =>
// setPhoto([...photo, response.assets])
// );
// } else {
// ImagePicker.launchImageLibrary(options, (response) =>
// setPhoto([...photo, response.assets])
// );
// }
// },
// []
// );

const onButtonPress = useCallback(
(
type: string,
options: ImagePicker.CameraOptions | ImagePicker.ImageLibraryOptions
) => {
if (type === "capture") {
ImagePicker.launchCamera(options, (response) => {
if (!response.didCancel) {
const selectedPhotos = response.assets!.map((asset) => ({
fileName: asset.fileName,
width: asset.width,
height: asset.height,
uri: asset.uri,
}));
setPhoto((prevPhotos: any[]) => prevPhotos.concat(selectedPhotos));
}
});
} else {
ImagePicker.launchImageLibrary(options, (response) => {
if (!response.didCancel) {
const selectedPhotos = response.assets!.map((asset) => ({
fileName: asset.fileName,
width: asset.width,
height: asset.height,
uri: asset.uri,
}));
setPhoto((prevPhotos: any[]) => prevPhotos.concat(selectedPhotos));
}
});
}
},
[]
);

return (
<PhotosInput>
<PhotoButton
style={{paddingVertical: 6}}
onPress={() => {
Alert.alert("사진 선택", "", [
{
text: "카메라",
onPress: () => onButtonPress(CameraActions[0].type, CameraActions[0].options)
},
{
text: "앨범",
onPress: () => onButtonPress(CameraActions[1].type, CameraActions[1].options)
},
{ text: "취소", style: "destructive" },
]);
}}
>
<PhotoIcon />
<Body14M style={{marginLeft: 10}}>{buttonLabel}</Body14M>
</PhotoButton>
</PhotosInput>
);
}

const PhotoButton = styled.TouchableOpacity`
display: flex;
flex-direction: row;
align-items: center;
padding-horizontal: 16px;
background: ${LIGHTGRAY};
border-radius: 6px;
margin-bottom: 20px;
`

export default PhotoOptions;
97 changes: 83 additions & 14 deletions src/components/Home/Quotation/QuotationForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SetStateAction, useState, Dispatch } from 'react';
import { SetStateAction, useState, Dispatch, useEffect } from 'react';
import { ScrollView, View, Text, TouchableOpacity, ImageBackground } from 'react-native';
import styled from 'styled-components/native';
import { BLACK, LIGHTGRAY, PURPLE } from '../../../styles/GlobalColor';
Expand All @@ -16,6 +16,8 @@ import { HomeStackParams } from '../../../pages/Home';
import Arrow from '../../../assets/common/Arrow.svg';
import Search from '../../../assets/common/Search.svg';
import Photo from '../../../assets/common/Photo.svg';
import PhotoOptions, { PhotoResultProps } from '../../../common/PhotoOptions';
import Carousel from '../../../common/Carousel';

const statusBarHeight = getStatusBarHeight(true);

Expand Down Expand Up @@ -45,6 +47,21 @@ const QuotationForm = ({ navigation, route }: StackScreenProps<HomeStackParams,
const sizes = ['XS(85)', 'S(90)', 'M(95)', 'L(100)', 'XL(105)', 'XXL(110)']
const options = ['프릴 추가', '단추 추가', '지퍼 추가', '주머니 추가']
const [text, setText] = useState<string>('');
const [photos, setPhotos] = useState<PhotoResultProps[]>([]);
const [refPhotos, setRefPhotos] = useState<PhotoResultProps[]>([]);

// 한 줄에 2개씩 아이템 배치
const splitArrayIntoPairs = (arr: any[], pairSize: number) => {
return arr.reduce((result, item, index) => {
if (index % pairSize === 0) {
result.push([]);
}
result[result.length - 1].push(item);
return result;
}, []);
};
const splitPhotos = splitArrayIntoPairs(photos, 2);
const splitRefPhotos = splitArrayIntoPairs(refPhotos, 2);

return (
<ScrollView>
Expand All @@ -65,25 +82,77 @@ const QuotationForm = ({ navigation, route }: StackScreenProps<HomeStackParams,
<Body16M style={{color: 'white'}}>마켓 소개글</Body16M>
</View>
</ImageBackground>
<View style={{alignItems: 'center', justifyContent: 'center'}}>
<Subtitle16B style={{paddingVertical: 20}}>견적서 작성</Subtitle16B>
<PhotoButton style={{paddingVertical: 12}}>
<Photo />
<Body14M style={{marginLeft: 10}}>작업할 사진 첨부</Body14M>
</PhotoButton>
<View style={{justifyContent: 'center'}}>
<Subtitle16B style={{textAlign: 'center', paddingVertical: 20}}>견적서 작성</Subtitle16B>
{photos.length > 0 &&
<Carousel
data={splitPhotos}
renderItem={({item}: any) => {
return (
<View style={{ flexDirection: 'row' }}>
{item.map((subItem: any) => (
<View style={{width: '50%', paddingHorizontal: 20}}>
<ImageBackground
key={subItem.id}
source={{uri: subItem.uri}}
style={{width: '100%', height: 170 }}
alt={subItem.fileName}
/>
</View>
))}
</View>
)
}}
slider
/>
}
<View style={{alignSelf: 'center', marginTop: 10}}>
<PhotoOptions
max={4}
photo={photos}
setPhoto={setPhotos}
buttonLabel='작업할 사진 첨부'
/>
</View>
</View>
<View style={{height: 8, backgroundColor: '#F4F4F4'}} />
<FilterSection label='재질 선택' items={materials} />
<FilterSection label='희망 사이즈 선택' items={sizes} />
<FilterSection label='옵션 선택' items={options} />
<View style={{height: 8, backgroundColor: '#F4F4F4'}} />
<View style={{paddingHorizontal: 15, paddingVertical: 20, alignItems: 'flex-start', borderBottomWidth: 0.5, borderColor: '#D9D9D9'}}>
<Subtitle18M style={{marginBottom: 10}}>추가 요청사항</Subtitle18M>
<PhotoButton style={{paddingVertical: 6}}>
<Photo />
<Body14M style={{marginLeft: 10}}>참고 사진 첨부</Body14M>
</PhotoButton>
<InputBox value={text} setValue={setText} placeholder='입력해주세요' long />
<View style={{paddingVertical: 20, borderBottomWidth: 0.5, borderColor: '#D9D9D9'}}>
<Subtitle18M style={{paddingHorizontal: 15, marginBottom: 5}}>추가 요청사항</Subtitle18M>
{refPhotos.length > 0 &&
<Carousel
data={splitRefPhotos}
renderItem={({item}: any) => {
return (
<View style={{ flexDirection: 'row' }}>
{item.map((subItem: any) => (
<View style={{width: '50%', paddingHorizontal: 20}}>
<ImageBackground
key={subItem.id}
source={{uri: subItem.uri}}
style={{width: '100%', height: 170 }}
alt={subItem.fileName}
/>
</View>
))}
</View>
)
}}
slider
/>
}
<View style={{paddingHorizontal: 15, marginTop: 15}}>
<PhotoOptions
max={4}
photo={refPhotos}
setPhoto={setRefPhotos}
buttonLabel='참고 사진 첨부'
/>
<InputBox value={text} setValue={setText} placeholder='입력해주세요' long />
</View>
</View>
<View style={{paddingHorizontal: 15, paddingVertical: 20, borderBottomWidth: 8, borderColor: '#F4F4F4'}}>
<Subtitle18M style={{marginBottom: 10}}>포트폴리오 사용 가능 여부</Subtitle18M>
Expand Down
Loading

0 comments on commit dbbd3ac

Please sign in to comment.