diff --git a/src/@types/auth.types.ts b/src/@types/auth.types.ts index 03d9bf8e..b6e1ac93 100644 --- a/src/@types/auth.types.ts +++ b/src/@types/auth.types.ts @@ -13,6 +13,7 @@ export interface AuthRequest { export interface SignupFormValue extends AuthRequest { passwordCheck: string; + checkbox: boolean; } export interface EditPassword { diff --git a/src/@types/service.ts b/src/@types/service.ts new file mode 100644 index 00000000..9651b8f2 --- /dev/null +++ b/src/@types/service.ts @@ -0,0 +1,97 @@ +export type subInfoRes = { + status: number; + message: string; + data: { + tripId: number; + startDate: string; + endDate: string; + numberOfPeople: number; + tripName: string; + tripStatus: string; + area: string; + subarea: string; + budget: number; + } | null; +}; + +export type subItemRes = { + status: number; + message: string; + data: { + tripId: number; + visitDate: string; + tripItems: TripItem[]; + } | null; +}; + +export type TripItem = { + tripItemId: number; + tourItemId: number; + name: string; + thumbnailUrl: string; + category: string; + transportation: string; + seqNum: number; + visitDate: string; + price: number; +}; + +export type subPathRes = { + status: number; + message: string; + data: { + tripId: number; + visitDate: string; + paths: { + fromSeqNum: number; + toSeqNum: number; + fromLongitude: string; + fromLatitude: string; + toLongitude: string; + toLatitude: string; + transportation: string; + pathInfo: { + price: number; + totalDistance: number; + totalTime: number; + }; + }[]; + } | null; +}; + +export type subMemberRes = { + status: number; + message: string; + data: { + tripId: number; + connectedMembers: { + memberId: number; + name: string; + thumbnailUrl: string; + }[]; + tripMembers: { + memberId: number; + name: string; + thumbnailUrl: string; + }[]; + numberOfPeople: number; + } | null; +}; +export type subBudgetRes = { + status: number; + message: string; + data: { + tripId: number; + budget: number; + calculatedPrice: number; + } | null; +}; + +export type SocketContextType = { + tripInfo: subInfoRes | null; + tripItem: subItemRes | null; + tripPath: subPathRes | null; + tripMember: subMemberRes | null; + tripBudget: subBudgetRes | null; + callBackPub: (callback: () => void) => void; +}; diff --git a/src/@types/socket.types.ts b/src/@types/socket.types.ts new file mode 100644 index 00000000..3634d2c4 --- /dev/null +++ b/src/@types/socket.types.ts @@ -0,0 +1,130 @@ +interface pubInfo { + startDate: string; + endDate: string; + numberOfPeople: number; + tripName: string; + tripStatus: 'BEFORE' | 'DURING' | 'AFTER'; + area: string; + subarea: string; + budget: number; +} + +interface pubAddTripItem { + visitDate: string; + newTripItems: { + tourItemId: number; + }[]; +} + +interface pubUpdateTripItem { + visitDate: string; + tripItemOrder: { + tripItemId: number; + seqNum: number; + }[]; +} + +interface pubVisitDate { + // visitDate: '2024-01-07', + visitDate: string; +} + +interface pubUpdatePrice { + price: number; +} + +interface pubUpdateTransportation { + transportation: 'CAR' | 'PUBLIC_TRANSPORTATION'; +} + +interface pubMember { + memberId: number; +} + +type subInfoMessage = (message: { + status: number; + message: string; + data: { + tripId: number; + startDate: string; + endDate: string; + numberOfPeople: number; + tripName: string; + tripStatus: string; + area: string; + subarea: string; + budget: number; + } | null; +}) => void; + +type subItemMessage = (response: { + status: number; + message: string; + data: { + tripId: number; + visitDate: string; + tripItems: { + tripItemId: number; + tourItemId: number; + name: string; + thumbnailUrl: string; + category: string; + transportation: string; + seqNum: number; + visitDate: string; + price: number; + }[]; + }; +}) => void; + +type subPathMessage = (response: { + status: number; + message: string; + data: { + tripId: number; + visitDate: string; + paths: { + fromSeqNum: number; + toSeqNum: number; + fromLongitude: string; + fromLatitude: string; + toLongitude: string; + toLatitude: string; + transportation: string; + pathInfo: { + price: number; + totalDistance: number; + totalTime: number; + }; + }[]; + }; +}) => void; + +type subMemberMessage = (response: { + status: number; + message: string; + data: { + tripId: number; + connectedMembers: { + memberId: number; + name: string; + thumbnailUrl: string; + }[]; + tripMembers: { + memberId: number; + name: string; + thumbnailUrl: string; + }[]; + numberOfPeople: number; + }; +}) => void; + +type subBudgetMessage = (response: { + status: number; + message: string; + data: { + tripId: number; + budget: number; + calculatedPrice: number; + }; +}) => void; diff --git a/src/@types/trips.types.ts b/src/@types/trips.types.ts index accc7011..cfbfac0f 100644 --- a/src/@types/trips.types.ts +++ b/src/@types/trips.types.ts @@ -1,10 +1,10 @@ interface TripRequest { tripName: string; numberOfPeople: number; - startDate: string; - endDate: string; - area: string; - subarea: string; + startDate: string | null; + endDate: string | null; + area: string | null; + subarea: string | null; } interface MyTripType { diff --git a/src/api/member.ts b/src/api/member.ts index 0a5e6093..e7c702de 100644 --- a/src/api/member.ts +++ b/src/api/member.ts @@ -44,7 +44,7 @@ export const deleteMember = async () => { }; // 나의 여정 조회 -export const getMemberTrips = async (page?: number, size?: number) => { +export const getMemberTrips = async (page = 0, size = 10) => { try { const res = await authClient.get(`trips?&page=${page}&size=${size}`); return res.data; diff --git a/src/api/socket.ts b/src/api/socket.ts index a35d44e9..b24503c0 100644 --- a/src/api/socket.ts +++ b/src/api/socket.ts @@ -3,3 +3,164 @@ import * as StompJs from '@stomp/stompjs'; export const socketClient = new StompJs.Client({ brokerURL: import.meta.env.VITE_SOCKET_URL, }); + +// 소켓 구독 +// 여정 기본 정보 +export const subInfo = (tripId: string, subInfoMessage: subInfoMessage) => { + socketClient.subscribe(`/sub/${tripId}/info`, (message) => { + const res = JSON.parse(message.body); + subInfoMessage(res); + }); +}; + +// 방문 날짜별 여정 여행 아이템 정보 +export const subItem = ( + tripId: string, + visitDate: string, + subItemMessage: subItemMessage, +) => { + socketClient.subscribe(`/sub/${tripId}/tripItems/${visitDate}`, (message) => { + const res = JSON.parse(message.body); + subItemMessage(res); + }); +}; + +// 방문 날짜별 여정 경로 정보 +export const subPath = ( + tripId: string, + visitDate: string, + subPathMessage: subPathMessage, +) => { + socketClient.subscribe(`/sub/${tripId}/path/${visitDate}`, (message) => { + const res = JSON.parse(message.body); + subPathMessage(res); + }); +}; + +// 연결된 멤버 정보 +export const subMember = ( + tripId: string, + subMemberMessage: subMemberMessage, +) => { + socketClient.subscribe(`/sub/${tripId}/connectedMember`, (message) => { + const res = JSON.parse(message.body); + subMemberMessage(res); + }); +}; + +// 목표 경비, 실제 발생 비용 +export const subBudget = ( + tripId: string, + subBudgetMessage: subBudgetMessage, +) => { + socketClient.subscribe(`/sub/${tripId}/budget`, (message) => { + const res = JSON.parse(message.body); + subBudgetMessage(res); + }); +}; + +// 소켓 전송 +// 여정 기본 정보 변경 이벤트 발생시 +export const pubInfo = (pubInfo: pubInfo, tripId: string) => { + socketClient.publish({ + destination: `/pub/trips/${tripId}/info`, + body: JSON.stringify(pubInfo), + }); +}; + +// 여정에 여행 아이템 추가 이벤트 발생시 +export const pubAddTripItem = ( + pubAddTripItem: pubAddTripItem, + tripId: string, +) => { + socketClient.publish({ + destination: `/pub/trips/${tripId}/addTripItems`, + body: JSON.stringify(pubAddTripItem), + }); +}; + +// 여행 아이템 예상 가격 업데이트 이벤트 발생시 +export const pubUpdatePrice = ( + pubUpdatePrice: pubUpdatePrice, + tripItemId: string, +) => { + socketClient.publish({ + destination: `/pub/tripItems/${tripItemId}/updatePrice`, + body: JSON.stringify(pubUpdatePrice), + }); +}; + +// 여행 아이템 방문 순서 변경 이벤트 발생시 +export const pubUpdateTripItem = ( + pubUpdateTripItem: pubUpdateTripItem, + tripId: string, +) => { + socketClient.publish({ + destination: `/pub/trips/${tripId}/updateTripItemOrder`, + body: JSON.stringify(pubUpdateTripItem), + }); +}; + +// 여행 아이템 방문 교통 수단 변경 이벤트 발생시 +export const pubUpdateTransportation = ( + pubUpdateTransportation: pubUpdateTransportation, + tripItemId: number, +) => { + socketClient.publish({ + destination: `/pub/tripItems/${tripItemId}/updateTransportation`, + body: JSON.stringify(pubUpdateTransportation), + }); +}; + +// 여행 아이템 방문 날짜 변경 이벤트 발생시 +export const pubUpdateVisitDate = ( + pubUpdateVisitDate: pubVisitDate, + tripItemId: number, +) => { + socketClient.publish({ + destination: `/pub/tripItems/${tripItemId}/updateVisitDate`, + body: JSON.stringify(pubUpdateVisitDate), + }); +}; + +// 여행 아이템 삭제 이벤트 발생시 +export const pubDeleteItem = (tripItemId: number) => { + socketClient.publish({ + destination: `/pub/tripItems/${tripItemId}/deleteItem`, + }); +}; + +// 멤버 여정 페이지로 입장 이벤트 발생시 +export const pubConnectMember = (pubMember: pubMember, tripId: string) => { + socketClient.publish({ + destination: `/pub/trips/${tripId}/connectMember`, + body: JSON.stringify(pubMember), + }); +}; + +// 멤버 여정 페이지 퇴장 이벤트 발생시 +export const pubDisconnectMember = (pubMember: pubMember, tripId: string) => { + socketClient.publish({ + destination: `/pub/trips/${tripId}/disconnectMember`, + body: JSON.stringify(pubMember), + }); +}; + +// 여정 편집 페이지 입장 이벤트 발생시(모든 sub 다받음) +export const pubEnterMember = (pubMember: pubMember, tripId: string) => { + socketClient.publish({ + destination: `/pub/trips/${tripId}/enterMember`, + body: JSON.stringify(pubMember), + }); +}; + +// 날짜별 여행 아이템 & 경로 조회 +export const pubGetPathAndItems = ( + pubGetPathAndItems: pubVisitDate, + tripId: string, +) => { + socketClient.publish({ + destination: `/pub/trips/${tripId}/getPathAndItems`, + body: JSON.stringify(pubGetPathAndItems), + }); +}; diff --git a/src/api/trips.ts b/src/api/trips.ts index 7d7aeb81..3cb10b13 100644 --- a/src/api/trips.ts +++ b/src/api/trips.ts @@ -1,4 +1,5 @@ import client from './client'; +import authClient from './authClient'; // 여정 관련 API @@ -22,7 +23,7 @@ export const deleteTrips = async (tripId: number) => { // 여정 생성 export const postTrips = async (tripsData: TripRequest) => { - const res = await client.post(`trips`, tripsData); + const res = await authClient.post(`trips`, tripsData); return res; }; diff --git a/src/components/Auth/AuthSurvey/AuthSurvey.tsx b/src/components/Auth/AuthSurvey/AuthSurvey.tsx index 94811ff6..7486b522 100644 --- a/src/components/Auth/AuthSurvey/AuthSurvey.tsx +++ b/src/components/Auth/AuthSurvey/AuthSurvey.tsx @@ -16,9 +16,8 @@ const AuthSurvey = ({ path }: Props) => { const { register, handleSubmit, - watch, setValue, - formState: { isDirty }, + formState: { isDirty, isValid }, } = useForm(); const navigate = useNavigate(); const [userInfo, _] = useRecoilState(UserInfoState); @@ -72,9 +71,7 @@ const AuthSurvey = ({ path }: Props) => { ))} - - 완료 - + 완료 ); }; diff --git a/src/components/Auth/AuthSurvey/AuthSurveyOption.tsx b/src/components/Auth/AuthSurvey/AuthSurveyOption.tsx index 774317ff..309a6d07 100644 --- a/src/components/Auth/AuthSurvey/AuthSurveyOption.tsx +++ b/src/components/Auth/AuthSurvey/AuthSurveyOption.tsx @@ -40,7 +40,9 @@ const AuthSurveyOption = ({ content, name, register }: Props) => { type="radio" id={content} className={`hidden peer/${content.replace(' ', '')}`} - {...register(name)} + {...register(name, { + required: true, + })} value={content} />