juni
WelKo_비밀번호 변경 및 네이버 지도 API 본문
검색해서 알아보기
- 제네릭 빈 배열
- types/supabase.ts에 public 스키마에 모든 테이블 , 컬럼 불러오기
- npx supabase login -> npx supabase init -> n / n -> yarn add supabase --dev
- types/supabase.ts에 public 스키마에 모든 테이블 , 컬럼 불러오기
const [reviews, setReviews] = useState<Tables<'reviews'>[]>([]);
router.push() ( next/navigation )
router.push()는 Next.js의 useRouter 훅을 사용하여 프로그래밍 방식으로 내비게이션을 수행할 때 사용합니다.
장점
- 프로그램적 내비게이션: 내비게이션을 함수 내에서 조건적으로 실행할 수 있습니다. 예를 들어, 폼 제출 후 특정 조건에 따라 페이지를 이동시키는 경우에 유용합니다.
- 동적 경로: 특정 이벤트나 사용자 상호작용 후에 경로를 변경할 수 있습니다.
단점
- 명시적인 코드 필요: 각 내비게이션마다 함수를 작성해야 하므로 코드가 다소 복잡해질 수 있습니다.
- 유지보수: 내비게이션 로직이 여러 컴포넌트에 분산될 수 있어 유지보수가 어려워질 수 있습니다.
Link 태그
Link 태그는 Next.js의 next/link 컴포넌트를 사용하여 내비게이션 링크를 생성합니다.
장점
- 간결한 문법: 내비게이션을 위한 선언적 문법을 제공하여 코드가 간결해집니다.
- SEO 최적화: Link 컴포넌트는 Next.js의 최적화 기능과 함께 사용되어 SEO 친화적인 내비게이션을 제공합니다.
- 자동 프리페칭: 기본적으로 Next.js는 Link 컴포넌트를 사용할 때 해당 페이지를 미리 가져오는 기능을 제공합니다.
단점
- 유연성 부족: 조건부 내비게이션이나 복잡한 내비게이션 로직을 처리하기에는 적합하지 않습니다.
- 기본 동작 제한: Link 컴포넌트는 특정 동작(예: 모달 창 닫기 등)을 실행하면서 내비게이션을 수행해야 하는 경우에는 불편할 수 있습니다.
결론
- router.push(): 동적, 조건부, 프로그래밍 방식 내비게이션에 유리합니다. 특정 이벤트 후에 페이지를 이동시키는 경우에 적합합니다.
- Link 태그: 정적, 선언적, 간단한 내비게이션에 유리합니다. 페이지 내에서 간단한 내비게이션 링크를 생성하는 경우에 적합합니다.
- 서버 측 (password/route.ts)
- PUT 메소드 핸들러는 요청에서 현재 비밀번호와 새로운 비밀번호를 가져옵니다.
- supabase.auth.signInWithPassword 메소드를 사용하여 현재 비밀번호의 유효성을 확인합니다. 이 메소드는 제공된 이메일과 비밀번호로 사용자를 인증합니다.
- 인증에 성공하면, supabase.auth.updateUser 메소드를 사용하여 새로운 비밀번호로 업데이트합니다.
- 인증에 실패하면, 오류 메시지를 반환합니다.
import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/utils/supabase/server';
export async function PUT(req: NextRequest, { params }: { params: { id: string } }) {
const supabase = createClient();
const { id: user_id } = params;
const { currentPassword, newPassword } = await req.json();
try {
// 현재 비밀번호 확인
const {
data: { session },
error: signInError
} = await supabase.auth.signInWithPassword({
email: req.headers.get('email') || '', // 헤더에서 이메일 가져오기, 프론트엔드에서 제공
password: currentPassword
});
if (signInError || !session) {
// 현재 비밀번호가 일치하지 않으면 오류 반환
return NextResponse.json({ error: 'Current password is incorrect' }, { status: 401 });
}
// 비밀번호 변경
const { error: updatePasswordError } = await supabase.auth.updateUser({
password: newPassword
});
if (updatePasswordError) {
return NextResponse.json({ error: updatePasswordError.message }, { status: 500 });
}
return NextResponse.json({ message: 'Password updated successfully' }, { status: 200 });
} catch (error) {
return NextResponse.json({ error: 'Unexpected error occurred' }, { status: 500 });
}
}
- 클라이언트 측 (PasswordChangeForm.tsx)
- 사용자는 현재 비밀번호와 새로운 비밀번호를 입력합니다.
- 폼이 제출되면, Axios를 사용하여 서버에 PUT 요청을 보냅니다. 이 요청은 현재 비밀번호와 새로운 비밀번호를 포함하며, 헤더에 사용자의 이메일을 포함합니다.
- 서버에서 비밀번호 변경이 성공적으로 이루어지면, 사용자에게 알림을 표시합니다. 오류가 발생하면, 오류 메시지를 표시합니다.
'use client';
import axios from 'axios';
import { useState } from 'react';
import { API_MYPAGE_PROFILE_PASSWORD } from '@/utils/apiConstants';
type PasswordChangeFormProps = {
userId: string;
email: string;
};
const PasswordChangeForm = ({ userId, email }: PasswordChangeFormProps) => {
const [currentPassword, setCurrentPassword] = useState('');
const [newPassword, setNewPassword] = useState('');
const handlePasswordChange = async (event: React.FormEvent) => {
event.preventDefault();
try {
await axios.put(
API_MYPAGE_PROFILE_PASSWORD(userId),
{ currentPassword, newPassword },
{
headers: {
email: email
}
}
);
alert('Password changed successfully');
} catch (error) {
alert('Error changing password');
}
};
return (
<form onSubmit={handlePasswordChange} className="mt-4">
<div>
<input
className="w-full rounded border px-3 py-2 text-black"
type="password"
value={currentPassword}
onChange={(e) => setCurrentPassword(e.target.value)}
placeholder="Current Password"
/>
</div>
<div className="mt-4">
<input
className="w-full rounded border px-3 py-2 text-black"
type="password"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
placeholder="New Password"
/>
</div>
<button type="submit" className="mt-4 rounded bg-black px-4 py-2 text-white">
Change Password
</button>
</form>
);
};
export default PasswordChangeForm;
- 현재 비밀번호 불일치 및 변경 비밀번호가 규칙을 벗어날 경우
- 현재 비밀번호 및 변경 비밀번호 규칙이 모두 문제 없을 경우
내 위치 불러오기 ( 네이버 지도 API 사용 )
- PC 환경에서 내 위치가 정확히 나오지 않는 경우가 존재
- Wi-Fi 기반 위치 추적: PC에서는 GPS가 없기 때문에 Wi-Fi를 기반으로 위치를 추적합니다. Wi-Fi 신호의 세기와 위치 정보의 정확도에 따라 오차가 발생할 수 있습니다.
- IP 주소 기반 위치 추적: 일부 경우에는 Wi-Fi 대신 IP 주소를 사용하여 위치를 추적할 수도 있습니다. 이 방법은 정확도가 낮습니다.
- 브라우저 권한 설정: 브라우저의 위치 정보 권한 설정에 따라 정확도가 달라질 수 있습니다. 위치 정보 권한이 정확하게 설정되어 있는지 확인해야 합니다.
- 지오코딩 (Geocoding)예시:
- 입력: "서울특별시 중구 세종대로 110"
- 출력: 위도 37.5665, 경도 126.9780
- 입력: 위도 37.5665, 경도 126.9780
- 출력: "서울특별시 중구 세종대로 110"
- 역지오코딩은 지오코딩의 반대 과정으로, 위도와 경도 좌표를 주소(또는 장소명)로 변환하는 과정입니다. 예를 들어, 위도 37.5665와 경도 126.9780을 입력하면 해당 좌표의 주소를 반환하는 작업입니다.
- 지오코딩은 주소(또는 장소명)를 위도(latitude)와 경도(longitude)와 같은 좌표로 변환하는 과정입니다. 예를 들어, "서울특별시 중구 세종대로 110"이라는 주소를 입력하면 해당 주소의 위도와 경도를 반환하는 작업입니다.
- naver 지도에서 제공해주는 지오코딩 및 역지오코딩을 활용하여 구현
'use client';
import { useEffect, useState } from 'react';
import { useRouter, usePathname } from 'next/navigation';
import { toast } from 'react-toastify';
const RegionForm = () => {
const [isScriptLoaded, setIsScriptLoaded] = useState(false);
const [position, setPosition] = useState<{ latitude: number; longitude: number } | null>(null);
const [region, setRegion] = useState<string | null>(null);
const router = useRouter();
const pathname = usePathname();
// URL 경로에서 userId 추출
const userId = pathname.split('/')[1];
const loadNaverMapScript = () => {
const script = document.createElement('script');
script.src = `https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${process.env.NEXT_PUBLIC_NCP_CLIENT_ID}&submodules=geocoder`;
script.async = true;
script.onload = () => {
if (window.naver && window.naver.maps) {
setIsScriptLoaded(true);
} else {
toast.error('네이버 맵 스크립트 로드 실패');
}
};
script.onerror = () => {
toast.error('네이버 맵 스크립트 로드 실패');
};
document.body.appendChild(script);
};
const getCurrentPosition = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(pos) => {
const { latitude, longitude } = pos.coords;
setPosition({ latitude, longitude });
},
(error) => {
toast.error(`Error occurred while retrieving location: ${error.message}`);
}
);
} else {
toast.error('Geolocation is not supported by this browser.');
}
};
const getRegionName = (latitude: number, longitude: number) => {
if (!window.naver) return;
const coord = new window.naver.maps.LatLng(latitude, longitude);
window.naver.maps.Service.reverseGeocode(
{
location: coord,
coordType: window.naver.maps.Service.CoordType.LatLng
},
(status: any, response: any) => {
if (status === 200) {
if (response.result.items && response.result.items.length > 0) {
const address = response.result.items[0].address;
setRegion(address);
} else {
toast.error('주소를 찾을 수 없습니다.');
}
} else {
toast.error('Failed to get the location name.');
}
}
);
};
const initializeMap = () => {
if (position) {
const map = new window.naver.maps.Map('map', {
center: new window.naver.maps.LatLng(position.latitude, position.longitude),
zoom: 15
});
new window.naver.maps.Marker({
position: new window.naver.maps.LatLng(position.latitude, position.longitude),
map: map
});
getRegionName(position.latitude, position.longitude); // Rename getLocationName to getRegionName
}
};
const handleSave = () => {
if (region && userId) {
router.push(`/${userId}/profilepage`);
}
};
const handleBack = () => {
router.push(`/${userId}/profilepage`);
};
useEffect(() => {
loadNaverMapScript();
}, []);
useEffect(() => {
if (isScriptLoaded) {
getCurrentPosition();
}
}, [isScriptLoaded]);
useEffect(() => {
if (position) {
initializeMap();
}
}, [position]);
return (
<>
<button onClick={handleBack}>Go Back</button>
<div className="mt-4" id="map" style={{ width: '100%', height: '400px' }}></div>
{region && <p>현재 위치: {region}</p>}
<button className="my-4 rounded bg-black p-2 text-white" onClick={handleSave}>
저장하기
</button>
</>
);
};
export default RegionForm;
'프로젝트 > WelKo' 카테고리의 다른 글
WelKo_상세페이지에서 메시지 보내기 (0) | 2024.07.28 |
---|---|
WelKo_ReactQuery 카테고리 분류 (0) | 2024.07.26 |
WelKo_리뷰 별점 및 1:1 채팅 기능 (4) | 2024.07.24 |
WelKo_프로필 수정 및 내 게시글 리스트 확인 , 상세페이지 이동 (1) | 2024.07.23 |
WelKo_와이어프레임 및 기능 구체화 (3) | 2024.07.22 |