diff --git a/components/common/FacilitiesIcons.tsx b/components/common/FacilitiesIcons.tsx
new file mode 100644
index 0000000..30027f6
--- /dev/null
+++ b/components/common/FacilitiesIcons.tsx
@@ -0,0 +1,63 @@
+import Image from 'next/image'
+import styled from '@emotion/styled'
+import { PlaceInfoType } from '../../types'
+
+type FacilitiesIconsType = {
+ place: PlaceInfoType
+ size: number
+ hasDescription?: boolean
+}
+
+type IconImageType = {
+ src: string
+ description: string
+}
+
+// 시설 정보 아이콘 뷰
+const FacilitiesIcons = ({
+ place,
+ size,
+ hasDescription = false,
+}: FacilitiesIconsType) => {
+ const IconImage = ({ src, description }: IconImageType) => (
+
+
+ {hasDescription && {description}}
+
+ )
+
+ return (
+
+ {place.isToiletExists && (
+
+ )}
+ {place.isChargerExists && (
+
+ )}
+ {place.isElevatorExists && (
+
+ )}
+ {place.isSlopeExists && (
+
+ )}
+
+ )
+}
+
+const IconsSection = styled.section`
+ display: flex;
+ margin-top: 0.5rem;
+ justify-content: flex-end;
+`
+const IconWrapper = styled.div<{ hasDescription: boolean }>`
+ margin: 0 ${({ hasDescription }) => (hasDescription ? 0.4 : 0.1)}rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+`
+const DescriptionText = styled.div`
+ margin-top: 0.4rem;
+ font-size: 0.7rem;
+`
+
+export default FacilitiesIcons
diff --git a/components/common/PlaceInfo.tsx b/components/common/PlaceInfo.tsx
index 964f3d1..bb48a4a 100644
--- a/components/common/PlaceInfo.tsx
+++ b/components/common/PlaceInfo.tsx
@@ -1,17 +1,11 @@
-import Image from 'next/image'
import Link from 'next/link'
import styled from '@emotion/styled'
import { PlaceInfoType } from '../../types'
import { conceptColors } from './BaseLayout'
import Text from './Text'
+import FacilitiesIcons from './FacilitiesIcons'
const PlaceInfo = ({ place }: { place: PlaceInfoType }) => {
- const IconImage = ({ src }: { src: string }) => (
-
-
-
- )
-
return (
@@ -29,12 +23,7 @@ const PlaceInfo = ({ place }: { place: PlaceInfoType }) => {
{place.address}
-
- {place.isToiletExists && }
- {place.isChargerExists && }
- {place.isElevatorExists && }
- {place.isSlopeExists && }
-
+
)
@@ -42,7 +31,8 @@ const PlaceInfo = ({ place }: { place: PlaceInfoType }) => {
const PlaceInfoContainer = styled.div`
margin: 0.2rem;
- div {
+ div,
+ p {
margin-bottom: 0.2rem;
}
`
@@ -55,17 +45,11 @@ const NameTypeSection = styled.section`
display: flex;
flex-wrap: wrap;
align-items: center;
- div:last-child {
- margin-left: 0.4rem;
+ p:first-of-type {
+ margin-right: 0.4rem;
}
`
-const IconsSection = styled.section`
- display: flex;
- margin-top: 0.5rem;
- justify-content: flex-end;
-`
-const IconWrapper = styled.div`
- margin: 0 0.1rem;
-`
+
+export { NameTypeSection }
export default PlaceInfo
diff --git a/components/common/Text.tsx b/components/common/Text.tsx
index 4c0b95c..bd69844 100644
--- a/components/common/Text.tsx
+++ b/components/common/Text.tsx
@@ -16,10 +16,12 @@ const Text = ({ children, color, size = 1, bold }: TextType) => {
)
}
-const StyledText = styled.div`
+export const StyledText = styled.p`
color: ${({ color }) => color};
font-size: ${({ size }) => size}rem;
font-weight: ${({ bold }) => bold && 'bold'};
+ margin-block-start: 0;
+ margin-block-end: 0;
`
export default Text
diff --git a/components/common/ToggleView.tsx b/components/common/ToggleView.tsx
new file mode 100644
index 0000000..244dcac
--- /dev/null
+++ b/components/common/ToggleView.tsx
@@ -0,0 +1,54 @@
+import React, { useState } from 'react'
+import { styled } from '@mui/material/styles'
+import MuiAccordion, { AccordionProps } from '@mui/material/Accordion'
+import AccordionDetails from '@mui/material/AccordionDetails'
+import MuiAccordionSummary, {
+ AccordionSummaryProps,
+} from '@mui/material/AccordionSummary'
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
+
+type ToggleViewType = {
+ children: React.ReactNode
+ title: string
+}
+
+const ToggleView = ({ children, title }: ToggleViewType) => {
+ const [isExpanded, setIsExpanded] = useState(false)
+
+ return (
+ setIsExpanded(!isExpanded)}
+ >
+ }>
+ {title}
+
+ {children}
+
+ )
+}
+
+const Accordion = styled((props: AccordionProps) => (
+
+))(() => ({
+ border: 'none',
+}))
+
+const AccordionSummary = styled((props: AccordionSummaryProps) => (
+
+))(() => ({
+ flexDirection: 'row-reverse',
+ minHeight: '0px',
+ '& .MuiAccordionSummary-expandIconWrapper': {
+ transform: 'rotate(-90deg)',
+ },
+ '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
+ transform: 'rotate(0deg)',
+ },
+ '& .MuiAccordionSummary-content': {
+ margin: '0.4rem',
+ flexGrow: 'inherit',
+ },
+}))
+
+export default ToggleView
diff --git a/components/detail/ChargerInfoToggle.tsx b/components/detail/ChargerInfoToggle.tsx
new file mode 100644
index 0000000..4d01490
--- /dev/null
+++ b/components/detail/ChargerInfoToggle.tsx
@@ -0,0 +1,74 @@
+import styled from '@emotion/styled'
+import { chargerDetail } from '../../data'
+import Text from '../common/Text'
+import ToggleView from '../common/ToggleView'
+
+const ChargerInfoToggle = () => {
+ const charger = chargerDetail.data
+
+ type ChargerInfoType = {
+ title: string
+ data: string
+ }
+
+ const ChargerInfoList: ChargerInfoType[] = [
+ {
+ title: '설치 장소',
+ data: charger.instllcdesc,
+ },
+ {
+ title: '공기 주입 가능',
+ data: charger.airinjectoryn,
+ },
+ {
+ title: '휴대전화 충전',
+ data: charger.moblphonchrstnyn,
+ },
+ { title: '동시 사용 가능 대수', data: charger.smtmuseco },
+ {
+ title: '평일 운영 시간',
+ data: `${charger.weekdayoperopenhhmm} ~ ${charger.weekdayopercolsehhmm}`,
+ },
+ {
+ title: '토요일 운영 시간',
+ data: `${charger.satoperoperopenhhmm} ~ ${charger.satoperclosehhmm}`,
+ },
+ {
+ title: '공휴일 운영 시간',
+ data: `${charger.holidayoperopenhhmm} ~ ${charger.holidaycloseopenhhmm}`,
+ },
+ { title: '시설명', data: charger.fcltynm },
+ { title: '관리기관명', data: charger.institutionnm },
+ { title: '관리기관 번호', data: charger.institutionphonenumber },
+ { title: '데이터 기준 일자', data: charger.referencedate },
+ ]
+
+ return (
+
+
+ {ChargerInfoList.map((chargerInfo: ChargerInfoType, index: number) => (
+
+ {chargerInfo.title}
+ {chargerInfo.data}
+
+ ))}
+
+
+ )
+}
+
+const ChargerInfoToggleSection = styled.section`
+ display: flex;
+ justify-content: center;
+ margin: 1rem 0;
+`
+const ChargerInfoWrapper = styled.div`
+ display: flex;
+ justify-content: space-between;
+ margin: 0.1rem;
+`
+const ChargerDataText = styled.div`
+ margin-left: 3rem;
+`
+
+export default ChargerInfoToggle
diff --git a/components/detail/index.tsx b/components/detail/index.tsx
new file mode 100644
index 0000000..4f8bf35
--- /dev/null
+++ b/components/detail/index.tsx
@@ -0,0 +1,64 @@
+import Link from 'next/link'
+import styled from '@emotion/styled'
+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'
+
+const Detail = () => {
+ const place: PlaceInfoType = placeDetail.response
+ // TODO: 동적 id와 실데이터 연결
+
+ return (
+
+ ◀ 뒤로 가기
+ {/* TODO: 모바일 환경에서는 /list (리스트로 가기) */}
+
+
+
+ {place.name}
+
+
+ {place.locationType}
+
+
+
+ {place.address}
+
+ {reviewAverageCount && (
+
+ {reviewAverageCount.average}
+
+ (리뷰 {reviewAverageCount.count}
+ 개)
+
+
+ )}
+
+
+
+ {/* */}
+
+ )
+}
+
+const DetailContainer = styled.article`
+ margin-top: 0.4rem;
+`
+const DetailInfoSection = styled.section`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin: 0.4rem 0;
+`
+const AddressText = styled(StyledText)`
+ margin-top: 0.4rem;
+`
+const ReviewAverageCountSection = styled.section`
+ display: flex;
+ margin: 1rem 0;
+`
+
+export default Detail
diff --git a/data.ts b/data.ts
index f7efed8..8a3906b 100644
--- a/data.ts
+++ b/data.ts
@@ -5,7 +5,7 @@ export const places = {
nextUrl: '?page=2',
results: [
{
- _id: '123',
+ _id: 123,
locationType: '음식점',
name: '몬플몬플 숙대점',
address: '서울특별시 용산구 청파동 청파로',
@@ -19,7 +19,7 @@ export const places = {
googlePlaceId: 'ChIJN2x0fu2ifDUR51BupseGYmE',
},
{
- _id: '124',
+ _id: 124,
locationType: '음식점',
name: '육쌈냉면 숙대점',
address: '서울특별시 용산구 청파동 청파로',
@@ -33,7 +33,7 @@ export const places = {
googlePlaceId: 'ChIJN2x0fu2ifDUR51BupseGYmE',
},
{
- _id: '125',
+ _id: 125,
locationType: '음식점',
name: '코피티암 숙대점',
address: '서울특별시 용산구 청파동 청파로',
@@ -48,3 +48,51 @@ export const places = {
},
],
}
+
+// 장소 디테일
+export const placeDetail = {
+ message: 'Retrieve Location By Id Success',
+ response: {
+ _id: 1,
+ locationType: 'subway',
+ name: '국립중앙박물관',
+ address: '137 Seobinggo-ro',
+ latitude: 37.5238506,
+ longitude: 126.9804702,
+ distance: 1.5,
+ isToiletExists: true,
+ isChargerExists: true,
+ isElevatorExists: true,
+ isSlopeExists: true,
+ googlePlaceId: 'ChIJN2x0fu2ifDUR51BupseGYmE',
+ },
+}
+
+// 충전기 디테일
+export const chargerDetail = {
+ message: 'get charger info success',
+ data: {
+ locationId: 12,
+ airinjectoryn: 'Y',
+ moblphonchrstnyn: 'Y',
+ smtmuseco: '2',
+ weekdayoperopenhhmm: '09:00',
+ weekdayopercolsehhmm: '18:00',
+ satoperoperopenhhmm: '00:00',
+ satoperclosehhmm: '00:00',
+ holidayoperopenhhmm: '00:00',
+ holidaycloseopenhhmm: '00:00',
+ fcltynm: '용산행복장애인자립생활센터',
+ institutionnm: '용산행복장애인자립생활센터',
+ institutionphonenumber: '02-704-0420',
+ instllcdesc: '센터 1층',
+ work_dttm: '1646631453000',
+ referencedate: '2021-09-15',
+ },
+}
+
+// 리뷰 평균 및 개수
+export const reviewAverageCount = {
+ count: 5,
+ average: 4.5,
+}
diff --git a/package.json b/package.json
index 4fffd0e..0c85500 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"dependencies": {
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
+ "@mui/icons-material": "^5.10.9",
"@mui/material": "^5.9.2",
"@react-google-maps/api": "^2.12.1",
"axios": "^0.27.2",
diff --git a/pages/detail/[id].tsx b/pages/detail/[id].tsx
new file mode 100644
index 0000000..984fd83
--- /dev/null
+++ b/pages/detail/[id].tsx
@@ -0,0 +1,13 @@
+import type { NextPage } from 'next'
+import BaseLayout from '../../components/common/BaseLayout'
+import Detail from '../../components/detail'
+
+const DetailPage: NextPage = () => {
+ return (
+
+
+
+ )
+}
+
+export default DetailPage
diff --git a/pages/list.tsx b/pages/list.tsx
index 55bdd1b..0efdcb3 100644
--- a/pages/list.tsx
+++ b/pages/list.tsx
@@ -12,8 +12,8 @@ const ListPage: NextPage = () => {
View Map
{places?.results?.map((place) => (
-
-
+
+
))}
diff --git a/types/index.ts b/types/index.ts
index 3652704..ac02fe6 100644
--- a/types/index.ts
+++ b/types/index.ts
@@ -1,6 +1,6 @@
// 장소 리스트
export interface PlaceInfoType {
- _id: string
+ _id: number
locationType: string
name: string
address: string
@@ -20,3 +20,40 @@ export interface PlaceListType {
nextUrl: string
results: PlaceInfoType[]
}
+
+// 장소 디테일
+export interface PlaceDetailType {
+ message: string
+ response: PlaceInfoType
+}
+
+// 충전기 디테일
+export interface chargerDataType {
+ locationId: number
+ airinjectoryn: string
+ moblphonchrstnyn: string
+ smtmuseco: string
+ weekdayoperopenhhmm: string
+ weekdayopercolsehhmm: string
+ satoperoperopenhhmm: string
+ satoperclosehhmm: string
+ holidayoperopenhhmm: string
+ holidaycloseopenhhmm: string
+ fcltynm: string
+ institutionnm: string
+ institutionphonenumber: string
+ instllcdesc: string
+ work_dttm: string
+ referencedate: string
+}
+
+export interface chargerDetailType {
+ message: string
+ data: chargerDataType
+}
+
+// 리뷰 평균 및 개수
+export interface ReviewAverageCountType {
+ count: number
+ average: number
+}
diff --git a/yarn.lock b/yarn.lock
index d6905ed..2a1f23a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -57,6 +57,13 @@
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.19.0":
+ version "7.20.1"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9"
+ integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==
+ dependencies:
+ regenerator-runtime "^0.13.10"
+
"@babel/types@^7.18.6":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f"
@@ -224,6 +231,13 @@
prop-types "^15.8.1"
react-is "^18.2.0"
+"@mui/icons-material@^5.10.9":
+ version "5.10.9"
+ resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.10.9.tgz#f9522c49797caf30146acc576e37ecb4f95bbc38"
+ integrity sha512-sqClXdEM39WKQJOQ0ZCPTptaZgqwibhj2EFV9N0v7BU1PO8y4OcX/a2wIQHn4fNuDjIZktJIBrmU23h7aqlGgg==
+ dependencies:
+ "@babel/runtime" "^7.19.0"
+
"@mui/material@^5.9.2":
version "5.9.2"
resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.9.2.tgz#2526c33568b4c785b0784b0714a8f613cd9dcd46"
@@ -1962,6 +1976,11 @@ react@17.0.0:
loose-envify "^1.1.0"
object-assign "^4.1.1"
+regenerator-runtime@^0.13.10:
+ version "0.13.10"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee"
+ integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==
+
regenerator-runtime@^0.13.4:
version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"