juni
WelKo_상세페이지에서 메시지 보내기 본문
투어 상세 페이지에서 가이드에게 메시지 보내기
과정에서 팀원의 코드를 기반으로 추가 및 수정을 진행해야 하다보니 어려움이 많았음
사용중인 api부터 코드 스타일 등등 로직을 이해하여 구현에 성공
1:1 실시간 채팅은 확인해보고 개선해야함
기존에 가이드 일부 정보만 받아오던 코드에서
가이드 고유id , 위치 정보 등 더 필요한 정보를 받아오고 투어 내용도 받아와서 params를 통해 채팅 페이지로 전달
'use client';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import Image from 'next/image';
import { useParams, useRouter } from 'next/navigation';
import React, { useEffect, useState } from 'react';
import { createClient } from '@/utils/supabase/client';
import { API_MYPAGE_PROFILE, API_POST_DETAILS } from '@/utils/apiConstants';
interface User {
name: string;
avatar: string;
id: string;
region: string;
}
type Post = {
id: string;
title: string;
image: string;
};
export const Guide = () => {
const { id: postId } = useParams() as { id: string };
const supabase = createClient();
const router = useRouter();
const [customerUser, setCustomerUser] = useState<User | null>(null);
// 작성자 데이터를 가져오는 함수
const fetchUser = async (): Promise<User> => {
const response = await axios.get(`/api/detail/guide/${postId}`);
return response.data.user; // response.data에서 user 객체를 반환
};
const {
data: user,
isPending,
error
} = useQuery<User>({
queryKey: ['user', postId],
queryFn: fetchUser,
enabled: !!postId
});
const fetchPostDetails = async (): Promise<Post> => {
const response = await axios.get(API_POST_DETAILS(postId));
return response.data;
};
const {
data: post,
isPending: isPostPending,
error: postError
} = useQuery<Post>({
queryKey: ['post', postId],
queryFn: fetchPostDetails,
enabled: !!postId
});
const fetchCustomerUser = async () => {
const { data, error } = await supabase.auth.getUser();
if (error) throw new Error(error.message);
if (data.user) {
const userId = data.user.id;
const response = await axios.get(API_MYPAGE_PROFILE(userId));
const profileData = response.data;
const customerUserData: User = {
id: profileData.id,
name: profileData.name,
avatar: profileData.avatar,
region: profileData.region
};
setCustomerUser(customerUserData);
}
};
const handleChat = () => {
if (!customerUser || !user || !post) {
throw new Error('Customer user, guide user, or post details are missing.');
}
const senderId = customerUser.id;
const receiverId = user.id;
const query = new URLSearchParams({
postId,
postTitle: post.title,
postImage: post.image
}).toString();
router.push(`/${senderId}/${receiverId}/chatpage?${query}`);
};
useEffect(() => {
fetchCustomerUser();
}, [supabase]);
if (isPending) return <div>Loading...</div>;
if (error) return <div>Error fetching user data</div>;
return (
<div>
<h3>투어 가이드</h3>
<div>
{user && (
<>
<Image
src={user.avatar}
alt={`${user.name}의 아바타`}
width={96}
height={96}
className="mr-2 h-24 w-24 rounded-full object-cover"
/>
<p>{user.region}</p>
<h4>{user.name}</h4>
<h5>투어 지역은 보류</h5>
<button className="mb-6 border" onClick={handleChat}>
메시지 보내기
</button>
</>
)}
</div>
</div>
);
};
params를 통해 내id , 가이드id , 게시글 정보를 받아와서 채팅 페이지 구현
'use client';
import React, { useEffect } from 'react';
import { useParams, useRouter, useSearchParams } from 'next/navigation';
import Image from 'next/image';
import { createClient } from '@/utils/supabase/client';
import Chat from '@/components/Chat';
const ChatPage = () => {
const { id: senderId, receiverid } = useParams() as { id: string; receiverid: string };
const searchParams = useSearchParams();
const router = useRouter();
const supabase = createClient();
const handleBack = () => {
router.back();
};
const checkAccess = async () => {
const { data, error } = await supabase.auth.getUser();
if (error) throw new Error(error.message);
if (data.user.id !== senderId && data.user.id !== receiverid) {
alert('접근 권한이 없습니다.');
router.push('/');
}
};
useEffect(() => {
checkAccess();
}, [senderId, receiverid, router, supabase]);
const postTitle = searchParams.get('postTitle') || '제목 없음';
const postImage = searchParams.get('postImage') || '';
return (
<div>
<div className="mb-4 flex justify-around">
<button onClick={handleBack}>Go Back</button>
<p className="font-bold">message</p>
</div>
<div className="flex">
<Image
className="mb-[20px] mr-2"
src={postImage ?? '/icons/upload.png'}
alt={postTitle ?? 'Default title'}
width={40}
height={40}
/>
<p className="text-[14px] font-bold">Title: {postTitle}</p>
</div>
<Chat senderId={senderId} receiverId={receiverid} />
</div>
);
};
export default ChatPage;
관련하여 새로운 api 파일 생성
import { NextRequest, NextResponse } from 'next/server';
import { createClient } from '@/utils/supabase/server';
export async function GET(request: NextRequest, { params }: { params: { id: string } }) {
const supabase = createClient();
const { id: postId } = params;
try {
const { data: post, error } = await supabase.from('posts').select('*').eq('id', postId).single();
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
return NextResponse.json(post, { status: 200 });
} catch (error) {
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
}
}
구현 과정에서 사용된 URL 라우팅 정리
URL 라우팅의 개념
URL 라우팅은 웹 애플리케이션에서 특정 URL에 대한 요청을 적절한 컴포넌트로 매핑하는 과정입니다. Next.js에서는 클라이언트 측 라우팅과 서버 측 라우팅을 모두 지원하며, 다양한 훅과 API를 제공하여 이를 쉽게 관리할 수 있습니다.
주요 개념 및 기능
1. URLSearchParams
URLSearchParams는 URL의 쿼리 문자열을 다루기 위한 브라우저 내장 API입니다. 이를 통해 쿼리 문자열을 쉽게 생성, 수정, 삭제 및 검색할 수 있습니다.
- 생성: 쿼리 매개변수를 설정하여 새로운 쿼리 문자열을 생성합니다.
- 수정: 기존 쿼리 문자열의 매개변수를 수정할 수 있습니다.
- 삭제: 특정 매개변수를 삭제할 수 있습니다.
- 검색: 특정 매개변수의 값을 검색할 수 있습니다.
const params = new URLSearchParams({
key1: 'value1',
key2: 'value2'
});
console.log(params.toString()); // "key1=value1&key2=value2"
2. useSearchParams (Next.js)
useSearchParams는 Next.js에서 제공하는 훅으로, 현재 URL의 쿼리 매개변수를 읽는 데 사용됩니다. 이를 통해 클라이언트 컴포넌트에서 URL 쿼리 매개변수를 쉽게 액세스할 수 있습니다.
- 읽기: 현재 URL에서 쿼리 매개변수를 읽습니다.
- 검색: 특정 쿼리 매개변수의 값을 검색할 수 있습니다.
3. useParams (Next.js)
useParams는 Next.js에서 동적 경로 매개변수를 읽는 데 사용되는 훅입니다. 동적 라우팅을 처리할 때 유용하며, URL 경로에서 특정 매개변수를 추출합니다.
- 동적 경로 매개변수: URL 경로의 특정 부분을 변수로 처리하여 동적 매개변수를 추출합니다.
// URL이 /posts/[id]인 경우
const { id } = useParams(); // id는 동적 경로 매개변수
4. useRouter (Next.js)
useRouter는 Next.js에서 라우팅과 관련된 다양한 기능을 제공하는 훅입니다. 이를 통해 클라이언트 측에서 URL 변경, 뒤로 가기, 페이지 이동 등을 제어할 수 있습니다.
- router.push: 사용자를 새로운 URL로 이동시킵니다. 브라우저 히스토리에 새 항목이 추가되어 뒤로 가기 버튼을 사용할 수 있습니다.
- router.replace: 사용자를 새로운 URL로 이동시키지만, 현재 페이지를 대체하여 브라우저 히스토리에 새 항목을 추가하지 않습니다.
- router.back: 사용자를 브라우저 히스토리에서 이전 페이지로 이동시킵니다. 이는 브라우저의 뒤로 가기 버튼과 동일한 효과를 가집니다.
실제 사용 코드
const handleChat = () => {
if (!customerUser || !user || !post) {
throw new Error('Customer user, guide user, or post details are missing.');
}
const senderId = customerUser.id;
const receiverId = user.id;
const query = new URLSearchParams({
postTitle: post.title,
postImage: post.image
}).toString();
router.push(`/${senderId}/${receiverId}/chatpage?${query}`);
};
const postTitle = searchParams.get('postTitle') || '제목 없음';
const postImage = searchParams.get('postImage') || '';
라우팅의 활용
Next.js에서 제공하는 라우팅 기능을 통해 URL 경로와 쿼리 매개변수를 손쉽게 다루고, 클라이언트 측에서 동적으로 페이지를 이동할 수 있습니다. 이러한 기능들을 활용하면 사용자 경험을 향상시키고, 애플리케이션의 내비게이션을 더 효과적으로 관리할 수 있습니다.
'프로젝트 > WelKo' 카테고리의 다른 글
WelKo_채팅 로직 개선 (0) | 2024.07.30 |
---|---|
WelKo_채팅 UI 및 로직 개선 (0) | 2024.07.29 |
WelKo_ReactQuery 카테고리 분류 (0) | 2024.07.26 |
WelKo_비밀번호 변경 및 네이버 지도 API (0) | 2024.07.25 |
WelKo_리뷰 별점 및 1:1 채팅 기능 (4) | 2024.07.24 |