Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/detail/add review #14

Merged
merged 13 commits into from
Dec 23, 2022
59 changes: 59 additions & 0 deletions components/detail/ReviewContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import styled from '@emotion/styled'
import { useState } from 'react'
import { reviewAverageCount } from '../../data'
import Text from '../common/Text'
import ReviewInput from './ReviewInput'
import ReviewList from './ReviewList'

// TODO: set location id
const ReviewContainer = () => {
const [sort, setSort] = useState('recommended')

return (
<>
<ReviewContainerHeader>
<Text size={1.2} bold>
{reviewAverageCount.count} 개의 리뷰
</Text>
<ReviewSortContainer>
<SelectSort
sort={sort}
name={'recommended'}
onClick={() => setSort('recommended')}
>
추천순
</SelectSort>
<SelectSort
sort={sort}
name={'createdAt'}
onClick={() => setSort('createdAt')}
>
최신순
</SelectSort>
</ReviewSortContainer>
</ReviewContainerHeader>
<ReviewInput />
<ReviewList />
</>
)
}

const ReviewContainerHeader = styled.header`
display: flex;
justify-content: space-around;
align-items: flex-end;
flex-direction: row;
`
const SelectSort = styled.div<{ sort: string; name: string }>`
font-weight: ${({ sort, name }) => (sort === name ? 'bold' : 'normal')};
padding: 0 0.5rem;
cursor: pointer;
`
const ReviewSortContainer = styled.div`
display: flex;
${SelectSort}:first-of-type {
border-right: 1px solid black;
}
`

export default ReviewContainer
112 changes: 112 additions & 0 deletions components/detail/ReviewInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import styled from '@emotion/styled'
import React, { useState, useEffect } from 'react'
import Text, { StyledText } from '../common/Text'

import Radio from '@mui/material/Radio'
import RadioGroup from '@mui/material/RadioGroup'
import FormControlLabel from '@mui/material/FormControlLabel'
import FormControl from '@mui/material/FormControl'
import Rating from '@mui/material/Rating'

const ReviewInput = () => {
const [userType, setUserType] = useState('anonymous')
Copy link
Collaborator

@nami-koko nami-koko Dec 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

state들 다 타입 지정(inputValue - string 등)하는게 좋을거같고 userType이나 Sort는 enum으로 타입 처리 하면 좋을거같아요!

const [inputValue, setInputValue] = useState('')
const [rate, setRate] = useState<number | null>(0)

return (
<ReviewInputContainer>
<ReviewInputHeader>
<UserInfo>
<Text>평점</Text>
<Rating
value={rate}
precision={0.5}
onChange={(_, newRate) => {
setRate(newRate)
}}
/>
</UserInfo>
<FormControl>
<RadioGroup
row
value={userType}
onChange={(e) => setUserType(e.target.value)}
>
<FormControlLabel
value="disabled"
control={<Radio size="small" />}
label="장애인"
/>
<FormControlLabel
value="able"
control={<Radio size="small" />}
label="비장애인"
/>
<FormControlLabel
value="anonymous"
control={<Radio size="small" />}
label="익명"
/>
</RadioGroup>
</FormControl>
</ReviewInputHeader>

<ReviewInputArea
onChange={(e) => setInputValue(e.target.value)}
placeholder="리뷰는 익명으로 등록됩니다."
value={inputValue}
/>
<ReviewInputButton
onClick={() => {
// postReview(userType, locationId, inputValue, rating)
setInputValue('')
setRate(0)
}}
>
등록
</ReviewInputButton>
</ReviewInputContainer>
)
}

const ReviewInputContainer = styled.section`
display: flex;
flex-direction: column;
margin-top: 1rem;
`
const ReviewInputHeader = styled.div`
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
`
const UserInfo = styled.div`
display: flex;
align-items: center;
justify-content: center;
${StyledText} {
margin-right: 0.2rem;
}
`
const ReviewInputArea = styled.textarea`
border: 2px solid #9d9d9d;
border-radius: 10px;
font-size: 1rem;
min-height: 5rem;
padding: 0.3rem;
margin-top: 0.4rem;
resize: none;
`
const ReviewInputButton = styled.button`
display: flex;
background-color: #e599b3;
color: white;
font-size: 0.9rem;
margin-top: 0.6rem;
padding: 0.4rem;
justify-content: center;
align-items: center;
border-radius: 5px;
`

export default ReviewInput
112 changes: 112 additions & 0 deletions components/detail/ReviewList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import styled from '@emotion/styled'
import Image from 'next/image'
import { reviews } from '../../data'
import Text, { StyledText } from '../common/Text'

import Rating from '@mui/material/Rating'

const ReviewList = () => {
return (
<ReviewListContainer>
{reviews?.data?.map((review) => (
<ReviewContainer key={review._id}>
<ReviewInfoWrapper>
<ReviewStarUserTypeWrapper>
<Rating
value={review.star}
precision={0.5}
size="small"
readOnly
/>
<Text color="#f0a044" size={0.9}>
{review.userType}
</Text>
</ReviewStarUserTypeWrapper>
<Text color="#9d9d9d" size={0.7}>
{review.createdAt.substring(0, 10)}
</Text>
</ReviewInfoWrapper>
<ReviewText>{review.detail}</ReviewText>
<HelpButtonWrapper>
<HelpButton
// onClick={() => {
// postReviewRecommend(review._id)
// }}
>
<Image
src={'/images/thumbs_up.svg'}
width={15}
height={15}
></Image>
<ButtonDescriptionText>도움이 돼요</ButtonDescriptionText>
<Text color="#cb3267" size={1} bold>
{review.good}
</Text>
</HelpButton>
<HelpButton
// onClick={() => postReviewDiscourage(review._id)}
>
<Image
src={'/images/thumbs_down.svg'}
width={15}
height={15}
></Image>
<ButtonDescriptionText>도움이 안 돼요</ButtonDescriptionText>
<Text color="#cb3267" size={1} bold>
{review.bad}
</Text>
</HelpButton>
</HelpButtonWrapper>
</ReviewContainer>
))}
</ReviewListContainer>
)
}

const ReviewListContainer = styled.section``
const ReviewContainer = styled.div`
margin-top: 1rem;
padding-bottom: 1rem;
border-bottom: #9d9d9d;
border-bottom-width: 0.08rem;
border-bottom-style: solid;
`
const ReviewInfoWrapper = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
`
const ReviewStarUserTypeWrapper = styled.div`
display: flex;
align-items: center;
${StyledText} {
margin-left: 0.4rem;
}
`
const ReviewText = styled.p`
font-size: 1rem;
align-items: center;
margin-left: 0.5rem;
margin-top: 0.5rem;
`
const HelpButtonWrapper = styled.div`
display: flex;
justify-content: space-between;
`
const HelpButton = styled.button`
display: flex;
font-weight: bold;
font-size: 0.8rem;
height: 1.7rem;
align-items: center;
border: 1px solid #f0a044;
border-radius: 10px;
background-color: #ffffff;
padding-left: 1rem;
padding-right: 1rem;
`
const ButtonDescriptionText = styled.p`
margin: 0 0.5rem 0 0.2rem;
`

export default ReviewList
26 changes: 20 additions & 6 deletions components/detail/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import styled from '@emotion/styled'
import { Dispatch, SetStateAction } from 'react'
import { useRouter } from 'next/router'
import { placeDetail, reviewAverageCount } from '../../data'
import { PlaceInfoType } from '../../types'
import FacilitiesIcons from '../common/FacilitiesIcons'
import { NameTypeSection } from '../common/PlaceInfo'
import Text, { StyledText } from '../common/Text'
import ChargerInfoToggle from './ChargerInfoToggle'
import { Dispatch, SetStateAction } from 'react'
import { useRouter } from 'next/router'
import ReviewContainer from './ReviewContainer'

import Rating from '@mui/material/Rating'

type DetailPropsType = {
setIsDetailOpen?: Dispatch<SetStateAction<boolean>>
}

const Detail = ({ setIsDetailOpen }: DetailPropsType) => {
const place: PlaceInfoType = placeDetail.response
// TODO: 동적 id와 실데이터 연결
const router = useRouter()

return (
<DetailContainer>
<button onClick={() => (setIsDetailOpen ? setIsDetailOpen(false) : router.push('/'))}>
Expand All @@ -35,17 +40,22 @@ const Detail = ({ setIsDetailOpen }: DetailPropsType) => {
</AddressText>
{reviewAverageCount && (
<ReviewAverageCountSection>
{reviewAverageCount.average}
<Rating
value={reviewAverageCount.average}
precision={0.1}
size="small"
readOnly
/>
<Text size={0.8}>({reviewAverageCount.average})</Text>
<Text>
(리뷰 <b>{reviewAverageCount.count}</b>
개)
리뷰 <b>{reviewAverageCount.count}</b>
</Text>
</ReviewAverageCountSection>
)}
<FacilitiesIcons place={place} size={50} hasDescription />
</DetailInfoSection>
<ChargerInfoToggle />
{/* <ReviewPage locationId={id} /> */}
<ReviewContainer />
</DetailContainer>
)
}
Expand All @@ -65,6 +75,10 @@ const AddressText = styled(StyledText)`
const ReviewAverageCountSection = styled.section`
display: flex;
margin: 1rem 0;
align-items: center;
${StyledText}:last-of-type {
margin-left: 0.6rem;
}
`

export default Detail
31 changes: 31 additions & 0 deletions data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,34 @@ export const reviewAverageCount = {
count: 5,
average: 4.5,
}

// 리뷰 리스트
export const reviews = {
message: 'List Review of location number 1 Success',
data: [
{
_id: '62343510c3dd5a345c6431d4',
locationId: 1,
userId: null,
userType: 'anonymous',
good: 1,
bad: 2,
detail:
'매장이 넓고 경사로가 있어서 이용하기 편리했어요 카페 내부도 예뻐요! 입구는 하나라 경사로 찾기 쉬울 것 같아요',
star: 4.5,
createdAt: '2022-03-18T09:40:53.077Z',
},
{
_id: '62343510c3dd5a345c6431d5',
locationId: 2,
userId: null,
userType: 'anonymous',
good: 1,
bad: 3,
detail:
'매장이 넓고 경사로가 있어서 이용하기 편리했어요 카페 내부도 예뻐요!',
star: 4.2,
createdAt: '2022-03-19T09:40:53.077Z',
},
],
}
3 changes: 3 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
compiler: {
emotion: true,
},
}

module.exports = nextConfig
Loading