From 5bddaaf3148cedf3244ba53c9c3ea37ac64dda91 Mon Sep 17 00:00:00 2001 From: MinSeo <138097126+m1nse0kim@users.noreply.github.com> Date: Mon, 27 May 2024 13:52:55 +0900 Subject: [PATCH] =?UTF-8?q?Kan=2083:=20=EA=B0=80=EA=B2=8C=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EB=B0=8F=20=EB=A6=AC=EB=B7=B0=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#19)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 리뷰 작성 페이지 UI 작업 * feat: 가게 상세 페이지 ui * feat: 가게 상세 페이지 정보(메뉴, 리뷰) 로딩 및 전화 모달 창 추가 * feat: 가게 상세 및 리뷰 작성 페이지 기능 추가 --------- Co-authored-by: MinseoKim --- src/screens/detail/ReviewWriteScreen.js | 84 ++++++++++++++++++++++- src/screens/detail/StoreDetailScreen.js | 91 ++++++++++++++++++------- 2 files changed, 149 insertions(+), 26 deletions(-) diff --git a/src/screens/detail/ReviewWriteScreen.js b/src/screens/detail/ReviewWriteScreen.js index 63e7a27..aeb0be6 100644 --- a/src/screens/detail/ReviewWriteScreen.js +++ b/src/screens/detail/ReviewWriteScreen.js @@ -58,7 +58,89 @@ export default function ReviewWriteScreen(props) { const [showImageError, setShowImageError] = useState(false); const [reviewImage, setReviewImage] = useState([]); - console.log('storeData:', storeData); + console.log('storeData:', 2); + + const handleReviewSubmit = async () => { + if (rating === 0) { + setShowRatingError(true); + return; + } + if (reviewContent.trim() === '') { + setShowContentError(true); + return; + } + + try { + const response = await axios.post( + `${API_URL}/v1/restaurants/${storeData.id}/reviews`, + { + content: reviewContent, + imageUrls: reviewImage, + rating: rating, + }, + { + headers: { Authorization: `Bearer ${context.accessToken}` }, + }, + ); + console.log('Review submitted successfully:', response.data); + navigation.goBack(); + } catch (error) { + console.error('Error submitting review:', error); + } + }; + + const uploadImage = async (image) => { + if (reviewImage.length >= 3) { + setShowImageError(true); + return; + } + + let imageData = ''; + await RNFS.readFile(image.path, 'base64') + .then((data) => { + console.log('encoded', data); + imageData = data; + }) + .catch((err) => { + console.error(err); + }); + + try { + const response = await axios.post(`${IMG_URL}/v1/upload-image`, { + images: [ + { + imageData: imageData, + location: 'test', + }, + ], + }); + + console.log('response image:', response.data); + + if (response.data.result != 'SUCCESS') { + console.log('Error: No return data'); + return; + } + + setReviewImage((prevImages) => [...prevImages, response.data.data[0].imageUrl]); + } catch (error) { + console.log('Error:', error); + } + }; + + const removeImage = (index) => { + setReviewImage((prevImages) => prevImages.filter((_, i) => i !== index)); + }; + + const DottedLine = () => { + return ( + + {[...Array(20)].map((_, index) => ( + + ))} + + ); + }; const handleReviewSubmit = async () => { if (rating === 0) { diff --git a/src/screens/detail/StoreDetailScreen.js b/src/screens/detail/StoreDetailScreen.js index 44a14dd..68cf8fc 100644 --- a/src/screens/detail/StoreDetailScreen.js +++ b/src/screens/detail/StoreDetailScreen.js @@ -28,9 +28,10 @@ import { COLOR_TEXT_BLACK, COLOR_LIGHTGRAY, COLOR_ORANGE, + COLOR_SECONDARY, } from '../../assets/color'; import AnimatedButton from '../../components/AnimationButton'; -import {useNavigation} from '@react-navigation/native'; +import {useNavigation, useFocusEffect} from '@react-navigation/native'; import {SvgXml} from 'react-native-svg'; import {svgXml} from '../../assets/svg'; import Header from '../../components/Header'; @@ -47,7 +48,7 @@ export default function StoreDetailScreen(props) { const navigation = useNavigation(); const context = useContext(AppContext); const { route } = props; - const restaurantId = route.params?.data?.id || 1; + const restaurantId = route.params?.data?.id || 2; const [restaurant, setRestaurant] = useState(null); const [isHearted, setIsHearted] = useState(false); const [heartCount, setHeartCount] = useState(0); @@ -63,7 +64,11 @@ export default function StoreDetailScreen(props) { restaurantDetail(); handleHeartPress(); }, []); - + useFocusEffect( + useCallback(() => { + restaurantDetail(); + }, []) + ); useEffect(() => { setDisplayedMenuList(menuList.slice(0, menuCount)); }, [menuList, menuCount]); @@ -84,9 +89,6 @@ export default function StoreDetailScreen(props) { const data = response.data.data; const dataReview = responseReview.data.data; - console.log('data: ', data.restaurant.isLike); - console.log('review: ', dataReview); - setRestaurant(data); setIsHearted(data.restaurant.isLike); setHeartCount(data.restaurant.likeCount); @@ -102,7 +104,6 @@ export default function StoreDetailScreen(props) { const newHeartedState = !isHearted; setIsHearted(newHeartedState); setHeartCount(newHeartedState ? heartCount + 1 : heartCount - 1); - await axios.post( `${API_URL}/v1/restaurants/${restaurantId}/like`, { @@ -112,12 +113,12 @@ export default function StoreDetailScreen(props) { headers: { Authorization: `Bearer ${context.accessToken}` }, }, ); + setIsHearted(newHeartedState); + setHeartCount(newHeartedState ? heartCount + 1 : heartCount - 1); console.log('isLike: ', newHeartedState); } catch (error) { console.error('Error updating heart count:', error); - setIsHearted(!newHeartedState); - setHeartCount(newHeartedState ? heartCount - 1 : heartCount + 1); } }; @@ -140,7 +141,7 @@ export default function StoreDetailScreen(props) { ) : ( - (빈 이미지) + 음식 사진 준비중 )} @@ -231,9 +232,16 @@ export default function StoreDetailScreen(props) { {restaurant.restaurant.categories} - 찜 {heartCount} - · - 리뷰 {restaurant.restaurant.reviewCount} + + 찜 {heartCount} + · + 리뷰 {restaurant.restaurant.reviewCount} + + + {"("} 네이버 평점 {restaurant.restaurant.naverRatingAvg} + · + 리뷰 {restaurant.restaurant.naverReviewCount} {")"} + @@ -334,14 +342,21 @@ export default function StoreDetailScreen(props) { > 전화번호: {restaurant.restaurant.detailInfo.contactNumber} - { - setModalVisible(!modalVisible); - }} - > - 닫기 - + + + 전화 + + { + setModalVisible(!modalVisible); + }} + > + 닫기 + + @@ -361,6 +376,7 @@ export default function StoreDetailScreen(props) { storeImage: { width: '100%', height: '100%', + resizeMode: 'cover', }, storeInfo: { width: '100%', @@ -389,6 +405,12 @@ export default function StoreDetailScreen(props) { marginBottom: 16, marginRight: 6, }, + storeReviewNaver: { + fontSize: 15, + color: COLOR_GRAY, + marginBottom: 16, + marginRight: 6, + }, contactContainer: { flexDirection: 'row', justifyContent: 'space-around', @@ -423,6 +445,7 @@ export default function StoreDetailScreen(props) { fontSize: 15, color: COLOR_TEXT_DARKGRAY, marginVertical: 8, + flex: 1, }, storeHours: { fontSize: 15, @@ -480,21 +503,27 @@ export default function StoreDetailScreen(props) { justifyContent: 'center', }, menuImagePlaceholderText: { - color: COLOR_LIGHTGRAY, + textAlign: 'center', + color: COLOR_SECONDARY, fontSize: 16, + margin: 5, }, menuTextContainer: { marginLeft: 10, + marginVertical: 5, justifyContent: 'center', + flex: 1, }, menuTitle: { fontSize: 18, color: COLOR_TEXT_BLACK, fontWeight: '500', + flexWrap: 'wrap', }, menuDescription: { fontSize: 16, color: COLOR_TEXT_DARKGRAY, + flexWrap: 'wrap', }, menuPrice: { fontSize: 17, @@ -556,12 +585,13 @@ export default function StoreDetailScreen(props) { marginTop: 10, }, modalView: { + top: 350, margin: 20, backgroundColor: "white", borderRadius: 20, - padding: 35, + padding: 20, alignItems: "center", - shadowColor: "#000", + shadowColor: "#000000", shadowOffset: { width: 0, height: 2, @@ -570,10 +600,19 @@ export default function StoreDetailScreen(props) { shadowRadius: 4, elevation: 5, }, + callButton: { + borderRadius: 20, + paddingHorizontal: 10, + paddingVertical: 5, + marginHorizontal: 10, + elevation: 2, + }, closeButton: { backgroundColor: COLOR_PRIMARY, borderRadius: 20, - padding: 10, + paddingHorizontal: 10, + paddingVertical: 5, + marginHorizontal: 10, elevation: 2, }, textStyle: { @@ -584,5 +623,7 @@ export default function StoreDetailScreen(props) { modalText: { marginBottom: 15, textAlign: "center", + fontSize: 17, + color: COLOR_TEXT_BLACK, }, });