Skip to content

Commit

Permalink
feat: 오픈지역추가 - 행정구역단위로
Browse files Browse the repository at this point in the history
  • Loading branch information
FourwingsY committed Mar 20, 2024
1 parent 1329f89 commit 844338c
Show file tree
Hide file tree
Showing 16 changed files with 56,219 additions and 146 deletions.
9 changes: 9 additions & 0 deletions app/(api)/data/geojson/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import data from "./sgg.json"

export function GET(request: Request) {
const { searchParams } = new URL(request.url)
const id = searchParams.get("id") ?? ""

const geoData = data as { [key: string]: any }
return Response.json(geoData[id])
}
55,987 changes: 55,987 additions & 0 deletions app/(api)/data/geojson/sgg.json

Large diffs are not rendered by default.

64 changes: 0 additions & 64 deletions app/(private)/region/draw/page.style.ts

This file was deleted.

52 changes: 0 additions & 52 deletions app/(private)/region/draw/page.tsx

This file was deleted.

16 changes: 16 additions & 0 deletions app/(private)/region/page.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,19 @@ export const ListButton = styled("button", {
cursor: "pointer",
},
})

export const Loading = styled("div", {
base: {
position: "absolute",
zIndex: 100,
top: "0",
left: "0",
width: "full",
height: "full",
display: "flex",
alignItems: "center",
justifyContent: "center",
background: "rgba(0, 0, 0, 0.3)",
color: "white",
},
})
80 changes: 68 additions & 12 deletions app/(private)/region/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Script from "next/script"
import { useEffect, useRef, useState } from "react"
import { useMediaQuery } from "react-responsive"

import { useRegions } from "@/lib/apis/api"
import { createRegion, useRegions } from "@/lib/apis/api"

import { useModal } from "@/hooks/useModal"

Expand All @@ -19,7 +19,8 @@ export default function Page() {
const mapElement = useRef<HTMLDivElement>(null)
const mapRef = useRef<kakao.maps.Map>()
const shapesRef = useRef<kakao.maps.Polygon[]>([])
const { data } = useRegions()
const newShape = useRef<kakao.maps.Polygon>()
const { data, refetch } = useRegions()
const [scriptLoaded, setScriptLoaded] = useState(false)
const isMobile = useMediaQuery({ maxWidth: 800 })
const regions = data ?? []
Expand All @@ -28,13 +29,18 @@ export default function Page() {
// 데이터가 바뀌어도 초기화는 한 번만 합니다.
useEffect(() => {
if (!scriptLoaded) return
if (regions.length === 0) return
kakao.maps.load(() => {
console.log("map loaded")
closeAll()
initializeMap()
drawRegions()
})
}, [regions.length, scriptLoaded, isMobile])
}, [scriptLoaded, isMobile])

useEffect(() => {
if (!scriptLoaded) return
drawRegions()
}, [data])

function initializeMap() {
const mapContainer = mapElement.current!
Expand Down Expand Up @@ -74,11 +80,7 @@ export default function Page() {
polygon.setMap(mapRef.current!)

// 라벨을 표시할 bound rect의 중심점을 구한다
const bounds = new kakao.maps.LatLngBounds()
region.boundaryVertices.forEach((v) => bounds.extend(new kakao.maps.LatLng(v.lat, v.lng)))
const centerLat = (bounds.getNorthEast().getLat() + bounds.getSouthWest().getLat()) / 2
const centerLng = (bounds.getNorthEast().getLng() + bounds.getSouthWest().getLng()) / 2
const center = new kakao.maps.LatLng(centerLat, centerLng)
const center = getCenterOf(region.boundaryVertices)

const overlay = new kakao.maps.CustomOverlay({
map: mapRef.current!,
Expand All @@ -94,8 +96,53 @@ export default function Page() {
})
}

function createNewRegion() {
openModal({ type: "RegionCreate" })
function selectHowToCreateRegion() {
openModal({ type: "RegionDraw", props: { onSelect: handleNewRegionSelected } })
}
async function createNewRegion({ name, vertices }: { name: string; vertices: { lat: number; lng: number }[] }) {
await createRegion({ name, boundaryVertices: vertices })
}

function handleNewRegionSelected(name: string | null, vertices: { lat: number; lng: number }[]) {
const path = vertices.map((v) => new kakao.maps.LatLng(v.lat, v.lng))
const polygon = new kakao.maps.Polygon({
map: mapRef.current,
path,
strokeWeight: 3,
strokeColor: "#f43",
strokeOpacity: 1,
fillColor: "#f43",
fillOpacity: 0.2,
})

polygon.setMap(mapRef.current!)

// 라벨을 표시할 bound rect의 중심점을 구한다
const center = getCenterOf(vertices)
const overlay = new kakao.maps.CustomOverlay({
map: mapRef.current!,
content: `<div style="padding:5px;background:rgba(255,255,255,0.5)"><b>${name}</b></div>`,
position: center,
zIndex: 3,
})
const newBounds = mapRef.current!.getBounds().extend(center)
mapRef.current!.setBounds(newBounds!)
newShape.current = polygon
openModal({
type: "RegionCreate",
props: {
defaultName: name ?? undefined,
onConfirm: async (name) => {
await createNewRegion({ name, vertices })
polygon.setMap(null)
refetch()
},
onCancel: () => {
polygon.setMap(null)
overlay.setMap(null)
},
},
})
}

function showList() {
Expand All @@ -105,16 +152,25 @@ export default function Page() {
return (
<S.Page>
<S.Header>
오픈 지역 관리<S.PageAction onClick={createNewRegion}>오픈 지역 추가</S.PageAction>
오픈 지역 관리<S.PageAction onClick={selectHowToCreateRegion}>오픈 지역 추가</S.PageAction>
</S.Header>
<Script
id="kakao-map-script"
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${KAKAO_APP_KEY}&autoload=false`}
onReady={() => setScriptLoaded(true)}
onError={(e) => alert(`지도를 불러올 수 없습니다.`)}
/>
{!scriptLoaded && <S.Loading>지도를 불러오는 중입니다...</S.Loading>}
<S.Map id="map" ref={mapElement} />
<S.ListButton onClick={showList}>목록 보기</S.ListButton>
</S.Page>
)
}

function getCenterOf(vertices: { lat: number; lng: number }[]) {
const bounds = new kakao.maps.LatLngBounds()
vertices.forEach((v) => bounds.extend(new kakao.maps.LatLng(v.lat, v.lng)))
const centerLat = (bounds.getNorthEast().getLat() + bounds.getSouthWest().getLat()) / 2
const centerLng = (bounds.getNorthEast().getLng() + bounds.getSouthWest().getLng()) / 2
return new kakao.maps.LatLng(centerLat, centerLng)
}
43 changes: 26 additions & 17 deletions app/modals/RegionCreate/RegionCreate.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
import { TextInput } from "@reactleaf/input/hookform"
import { BasicModalProps } from "@reactleaf/modal"
import { useRouter } from "next/navigation"
import { toast } from "react-toastify"
import { FormProvider, useForm } from "react-hook-form"

import RightSheet from "@/modals/_template/RightSheet"
import RightSheet from "../_template/RightSheet"

import * as S from "./RegionCreate.style"

interface Props extends BasicModalProps {}
export default function RegionCreate({ visible, close }: Props) {
const router = useRouter()
interface Props extends BasicModalProps {
defaultName?: string
onConfirm?: (name: string) => void
onCancel?: () => void
}
export default function RegionCreate({ defaultName, onConfirm, onCancel, visible, close }: Props) {
const form = useForm<{ name: string }>({ defaultValues: { name: defaultName } })

function openRegionSelector() {
return toast.error("준비중인 기능입니다.")
function onSubmit(value: { name: string }) {
onConfirm?.(value.name)
close()
}

const goToDraw = (type: "circle" | "polygon") => () => {
router.push(`/region/draw?type=${type}`)
function handleCancel() {
onCancel?.()
close()
}

return (
<RightSheet title="오픈 지역 추가" visible={visible} close={close}>
<S.ButtonsWrapper>
<S.Button onClick={openRegionSelector}>행정구역 단위로 추가</S.Button>
<S.Button onClick={goToDraw("circle")}>원형 그리기</S.Button>
<S.Button onClick={goToDraw("polygon")}>폴리곤 그리기</S.Button>
</S.ButtonsWrapper>
<form style={{ width: 260, padding: "0 20px" }} onSubmit={form.handleSubmit(onSubmit)}>
<FormProvider {...form}>
<TextInput label="지역명" name="name" />
</FormProvider>
<div>
<button onClick={handleCancel} type="button">
취소
</button>
<button>추가하기</button>
</div>
</form>
</RightSheet>
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { styled } from "@/styles/jsx"

export const Modal = styled("div", {
base: {
padding: 20,
borderRadius: 8,
background: "white",
boxShadow: "0 0 10px rgba(0,0,0,0.1)",
},
})

export const ButtonsWrapper = styled("div", {
base: {
display: "flex",
Expand Down
Loading

0 comments on commit 844338c

Please sign in to comment.