diff --git a/index.html b/index.html index a39119f2..c3bd5b82 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,29 @@ + + + + + 위플플 | 여정 공유 플랫폼 + + + + - -
- - - - \ No newline at end of file + +
+ + + diff --git a/package.json b/package.json index 10b3be84..b572eba0 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,15 @@ "@types/react-beautiful-dnd": "^13.1.8", "axios": "^1.6.2", "date-fns": "^3.1.0", + "lodash": "^4.17.21", "msw": "0.36.3", "path": "^0.12.7", "react": "^18.2.0", "react-beautiful-dnd": "^13.1.1", + "react-device-detect": "^2.2.3", "react-dom": "^18.2.0", "react-hook-form": "^7.49.2", + "react-icons": "^5.0.1", "react-infinite-scroller": "^1.2.6", "react-kakao-maps-sdk": "^1.1.24", "react-modal": "^3.16.1", @@ -52,6 +55,7 @@ "websocket": "^1.0.34" }, "devDependencies": { + "@types/lodash": "^4.14.202", "@types/react": "^18.2.43", "@types/react-date-range": "^1.4.9", "@types/react-dom": "^18.2.17", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0720f243..95225e8f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ dependencies: date-fns: specifier: ^3.1.0 version: 3.1.0 + lodash: + specifier: ^4.17.21 + version: 4.17.21 msw: specifier: 0.36.3 version: 0.36.3 @@ -71,12 +74,18 @@ dependencies: react-beautiful-dnd: specifier: ^13.1.1 version: 13.1.1(react-dom@18.2.0)(react@18.2.0) + react-device-detect: + specifier: ^2.2.3 + version: 2.2.3(react-dom@18.2.0)(react@18.2.0) react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) react-hook-form: specifier: ^7.49.2 version: 7.49.3(react@18.2.0) + react-icons: + specifier: ^5.0.1 + version: 5.0.1(react@18.2.0) react-infinite-scroller: specifier: ^1.2.6 version: 1.2.6(react@18.2.0) @@ -127,6 +136,9 @@ dependencies: version: 1.0.34 devDependencies: + '@types/lodash': + specifier: ^4.14.202 + version: 4.14.202 '@types/react': specifier: ^18.2.43 version: 18.2.45 @@ -3022,6 +3034,10 @@ packages: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true + /@types/lodash@4.14.202: + resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} + dev: true + /@types/node@20.10.5: resolution: {integrity: sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==} dependencies: @@ -5126,6 +5142,17 @@ packages: - react-native dev: false + /react-device-detect@2.2.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==} + peerDependencies: + react: '>= 0.14.0' + react-dom: '>= 0.14.0' + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + ua-parser-js: 1.0.37 + dev: false + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -5145,6 +5172,14 @@ packages: react: 18.2.0 dev: false + /react-icons@5.0.1(react@18.2.0): + resolution: {integrity: sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==} + peerDependencies: + react: '*' + dependencies: + react: 18.2.0 + dev: false + /react-infinite-scroller@1.2.6(react@18.2.0): resolution: {integrity: sha512-mGdMyOD00YArJ1S1F3TVU9y4fGSfVVl6p5gh/Vt4u99CJOptfVu/q5V/Wlle72TMgYlBwIhbxK5wF0C/R33PXQ==} peerDependencies: @@ -5879,6 +5914,10 @@ packages: engines: {node: '>=14.17'} hasBin: true + /ua-parser-js@1.0.37: + resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==} + dev: false + /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} dev: false diff --git a/public/mockServiceWorker.js b/public/mockServiceWorker.js deleted file mode 100644 index e180e4c6..00000000 --- a/public/mockServiceWorker.js +++ /dev/null @@ -1,338 +0,0 @@ -/* eslint-disable */ -/* tslint:disable */ - -/** - * Mock Service Worker (0.36.3). - * @see https://github.com/mswjs/msw - * - Please do NOT modify this file. - * - Please do NOT serve this file on production. - */ - -const INTEGRITY_CHECKSUM = '02f4ad4a2797f85668baf196e553d929'; -const bypassHeaderName = 'x-msw-bypass'; -const activeClientIds = new Set(); - -self.addEventListener('install', function () { - return self.skipWaiting(); -}); - -self.addEventListener('activate', async function (event) { - return self.clients.claim(); -}); - -self.addEventListener('message', async function (event) { - const clientId = event.source.id; - - if (!clientId || !self.clients) { - return; - } - - const client = await self.clients.get(clientId); - - if (!client) { - return; - } - - const allClients = await self.clients.matchAll(); - - switch (event.data) { - case 'KEEPALIVE_REQUEST': { - sendToClient(client, { - type: 'KEEPALIVE_RESPONSE', - }); - break; - } - - case 'INTEGRITY_CHECK_REQUEST': { - sendToClient(client, { - type: 'INTEGRITY_CHECK_RESPONSE', - payload: INTEGRITY_CHECKSUM, - }); - break; - } - - case 'MOCK_ACTIVATE': { - activeClientIds.add(clientId); - - sendToClient(client, { - type: 'MOCKING_ENABLED', - payload: true, - }); - break; - } - - case 'MOCK_DEACTIVATE': { - activeClientIds.delete(clientId); - break; - } - - case 'CLIENT_CLOSED': { - activeClientIds.delete(clientId); - - const remainingClients = allClients.filter((client) => { - return client.id !== clientId; - }); - - // Unregister itself when there are no more clients - if (remainingClients.length === 0) { - self.registration.unregister(); - } - - break; - } - } -}); - -// Resolve the "main" client for the given event. -// Client that issues a request doesn't necessarily equal the client -// that registered the worker. It's with the latter the worker should -// communicate with during the response resolving phase. -async function resolveMainClient(event) { - const client = await self.clients.get(event.clientId); - - if (client.frameType === 'top-level') { - return client; - } - - const allClients = await self.clients.matchAll(); - - return allClients - .filter((client) => { - // Get only those clients that are currently visible. - return client.visibilityState === 'visible'; - }) - .find((client) => { - // Find the client ID that's recorded in the - // set of clients that have registered the worker. - return activeClientIds.has(client.id); - }); -} - -async function handleRequest(event, requestId) { - const client = await resolveMainClient(event); - const response = await getResponse(event, client, requestId); - - // Send back the response clone for the "response:*" life-cycle events. - // Ensure MSW is active and ready to handle the message, otherwise - // this message will pend indefinitely. - if (client && activeClientIds.has(client.id)) { - (async function () { - const clonedResponse = response.clone(); - sendToClient(client, { - type: 'RESPONSE', - payload: { - requestId, - type: clonedResponse.type, - ok: clonedResponse.ok, - status: clonedResponse.status, - statusText: clonedResponse.statusText, - body: - clonedResponse.body === null ? null : await clonedResponse.text(), - headers: serializeHeaders(clonedResponse.headers), - redirected: clonedResponse.redirected, - }, - }); - })(); - } - - return response; -} - -async function getResponse(event, client, requestId) { - const { request } = event; - const requestClone = request.clone(); - const getOriginalResponse = () => fetch(requestClone); - - // Bypass mocking when the request client is not active. - if (!client) { - return getOriginalResponse(); - } - - // Bypass initial page load requests (i.e. static assets). - // The absence of the immediate/parent client in the map of the active clients - // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet - // and is not ready to handle requests. - if (!activeClientIds.has(client.id)) { - return await getOriginalResponse(); - } - - // Bypass requests with the explicit bypass header - if (requestClone.headers.get(bypassHeaderName) === 'true') { - const cleanRequestHeaders = serializeHeaders(requestClone.headers); - - // Remove the bypass header to comply with the CORS preflight check. - delete cleanRequestHeaders[bypassHeaderName]; - - const originalRequest = new Request(requestClone, { - headers: new Headers(cleanRequestHeaders), - }); - - return fetch(originalRequest); - } - - // Send the request to the client-side MSW. - const reqHeaders = serializeHeaders(request.headers); - const body = await request.text(); - - const clientMessage = await sendToClient(client, { - type: 'REQUEST', - payload: { - id: requestId, - url: request.url, - method: request.method, - headers: reqHeaders, - cache: request.cache, - mode: request.mode, - credentials: request.credentials, - destination: request.destination, - integrity: request.integrity, - redirect: request.redirect, - referrer: request.referrer, - referrerPolicy: request.referrerPolicy, - body, - bodyUsed: request.bodyUsed, - keepalive: request.keepalive, - }, - }); - - switch (clientMessage.type) { - case 'MOCK_SUCCESS': { - return delayPromise( - () => respondWithMock(clientMessage), - clientMessage.payload.delay, - ); - } - - case 'MOCK_NOT_FOUND': { - return getOriginalResponse(); - } - - case 'NETWORK_ERROR': { - const { name, message } = clientMessage.payload; - const networkError = new Error(message); - networkError.name = name; - - // Rejecting a request Promise emulates a network error. - throw networkError; - } - - case 'INTERNAL_ERROR': { - const parsedBody = JSON.parse(clientMessage.payload.body); - - console.error( - `\ -[MSW] Uncaught exception in the request handler for "%s %s": - -${parsedBody.location} - -This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error, as it indicates a mistake in your code. If you wish to mock an error response, please see this guide: https://mswjs.io/docs/recipes/mocking-error-responses\ -`, - request.method, - request.url, - ); - - return respondWithMock(clientMessage); - } - } - - return getOriginalResponse(); -} - -self.addEventListener('fetch', function (event) { - const { request } = event; - const accept = request.headers.get('accept') || ''; - - // Bypass server-sent events. - if (accept.includes('text/event-stream')) { - return; - } - - // Bypass navigation requests. - if (request.mode === 'navigate') { - return; - } - - // Opening the DevTools triggers the "only-if-cached" request - // that cannot be handled by the worker. Bypass such requests. - if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { - return; - } - - // Bypass all requests when there are no active clients. - // Prevents the self-unregistered worked from handling requests - // after it's been deleted (still remains active until the next reload). - if (activeClientIds.size === 0) { - return; - } - - const requestId = uuidv4(); - - return event.respondWith( - handleRequest(event, requestId).catch((error) => { - if (error.name === 'NetworkError') { - console.warn( - '[MSW] Successfully emulated a network error for the "%s %s" request.', - request.method, - request.url, - ); - return; - } - - // At this point, any exception indicates an issue with the original request/response. - console.error( - `\ -[MSW] Caught an exception from the "%s %s" request (%s). This is probably not a problem with Mock Service Worker. There is likely an additional logging output above.`, - request.method, - request.url, - `${error.name}: ${error.message}`, - ); - }), - ); -}); - -function serializeHeaders(headers) { - const reqHeaders = {}; - headers.forEach((value, name) => { - reqHeaders[name] = reqHeaders[name] - ? [].concat(reqHeaders[name]).concat(value) - : value; - }); - return reqHeaders; -} - -function sendToClient(client, message) { - return new Promise((resolve, reject) => { - const channel = new MessageChannel(); - - channel.port1.onmessage = (event) => { - if (event.data && event.data.error) { - return reject(event.data.error); - } - - resolve(event.data); - }; - - client.postMessage(JSON.stringify(message), [channel.port2]); - }); -} - -function delayPromise(cb, duration) { - return new Promise((resolve) => { - setTimeout(() => resolve(cb()), duration); - }); -} - -function respondWithMock(clientMessage) { - return new Response(clientMessage.payload.body, { - ...clientMessage.payload, - headers: clientMessage.payload.headers, - }); -} - -function uuidv4() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - const r = (Math.random() * 16) | 0; - const v = c == 'x' ? r : (r & 0x3) | 0x8; - return v.toString(16); - }); -} diff --git a/src/@types/detail.types.ts b/src/@types/detail.types.ts index bfb4bca8..71827919 100644 --- a/src/@types/detail.types.ts +++ b/src/@types/detail.types.ts @@ -1,5 +1,6 @@ interface tourDetail { id: number; + contentTypeId: number; title: string; liked: boolean; fullAddress: string; diff --git a/src/@types/review.types.ts b/src/@types/review.types.ts index 851b017b..6f6cf219 100644 --- a/src/@types/review.types.ts +++ b/src/@types/review.types.ts @@ -1,11 +1,34 @@ -interface ReviewRequest { - tourItemId: number; +interface Keyword { + keywordId: number; + content: string; + type?: string; +} + +interface CommentItemProps { + commentId: number; + authorNickname: string; + authorProfileImageUrl: string; + createdTime: string; + content: string; + onClick?: () => void; + isAuthor: boolean; +} + +interface MyReviewContent { + reviewId: number; + authorNickname: string; + authorProfileImageUrl: string; rating: number; - keywords: Keyword[]; + createdTime: string; content: string; + keywords: Keyword[]; + commentCount: number; + isAuthor?: boolean; } -interface Keyword { - keywordId: number; +interface ReviewRequest { + tourItemId: number; + rating: number; + keywords: Keyword[]; content: string; } diff --git a/src/@types/service.ts b/src/@types/service.ts index bae375b2..5f9ff5d2 100644 --- a/src/@types/service.ts +++ b/src/@types/service.ts @@ -97,12 +97,27 @@ export type subBudgetRes = { } | null; }; +export type subCursorRes = { + status: number; + message: string; + data: { + color: string; + tripId: string; + visitDate: string; + memberId: number; + name: string; + x: number; + y: number; + } | null; +}; + export type SocketContextType = { tripInfo: subInfoRes | null; tripItem: subItemRes | null; tripPath: subPathRes | null; tripMember: subMemberRes | null; tripBudget: subBudgetRes | null; + tripCursor: subCursorRes | null; tripId: string; callBackPub: (callback: () => void) => void; }; diff --git a/src/@types/socket.types.ts b/src/@types/socket.types.ts index a8167cc8..09e5e725 100644 --- a/src/@types/socket.types.ts +++ b/src/@types/socket.types.ts @@ -82,6 +82,20 @@ type subBudgetMessage = (response: { }; }) => void; +type subCursorMessage = (response: { + status: number; + message: string; + data: { + color: string; + tripId: string; + visitDate: string; + memberId: number; + name: string; + x: number; + y: number; + }; +}) => void; + interface pubInfo { startDate: string; endDate: string; @@ -138,3 +152,10 @@ interface pubGetPathAndItems { interface pubUpdateBudget { budget: number; } + +interface pubCursor { + token: string; + visitDate: string; + x: number; + y: number; +} diff --git a/src/@types/tours.types.ts b/src/@types/tours.types.ts index ccd95671..52776135 100644 --- a/src/@types/tours.types.ts +++ b/src/@types/tours.types.ts @@ -1,30 +1,30 @@ -export type TourKeywordInfo = { +interface TourKeywordInfo { keywordId: number; content: string; type: string; keywordCount: number; -}; +} -export interface RegionTypes { +interface RegionTypes { areaCode?: number; subAreaCode?: number; name: string; } -export interface ToursCategoryItemProps extends RegionTypes { +interface ToursCategoryItemProps extends RegionTypes { isSelected: boolean; onSelect: (name: string) => void; } -export interface ToursListProps { +interface ToursListProps { selectedRegion: string; } -export interface ToursCategoryProps extends ToursListProps { +interface ToursCategoryProps extends ToursListProps { setSelectedRegion: (region: string) => void; } -export interface TourType { +interface TourType { contentTypeId?: number; id: number; title: string; @@ -38,7 +38,7 @@ export interface TourType { latitude?: string; } -export interface LikedListType { +interface LikedListType { tripLikedItemId: number; tourItemId: number; contentTypeId: number; @@ -52,3 +52,25 @@ export interface LikedListType { preferTotalCount: number; notPreferTotalCount: number; } + +interface ReviewInfoItemProps { + reviewId: number; + authorNickname: string; + authorProfileImageUrl: string; + rating: number; + createdTime: string; + content: string; + keywords: Keyword[]; // keywordId, content, type + commentCount: number; + onClick?: () => void; + tourItemId?: number; + contentTypeId?: number; + canTextOverflow: boolean; + isAuthor?: boolean; +} + +interface Keyword { + keywordId: number; + content: string; + type?: string; +} diff --git a/src/@types/trips.types.ts b/src/@types/trips.types.ts index e2ebbb0c..71ab6a4f 100644 --- a/src/@types/trips.types.ts +++ b/src/@types/trips.types.ts @@ -51,3 +51,25 @@ interface AuthorityType { tripId: string; }; } +interface TripSurveySetMemberInfo { + memberId: number; + nickname: string; + thumbnail: string; +} + +interface TripMemeberInfo { + nickname: string; + profileImageUrl: string; +} + +interface Participant { + memberId: number; + nickname: string; + thumbnail: string; +} + +interface Participants { + tripSurveyMemberCount: number; + tripSurveySetMemberInfos: Participant[]; + nonTripSurveySetMemberInfos: Participant[]; +} diff --git a/src/App.tsx b/src/App.tsx index 909f6bac..030880f3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,3 @@ -import { ThemeProvider } from 'styled-components'; -import { GlobalStyle } from '@styles/globalStyles'; -import { theme } from '@styles/theme'; import { RecoilRoot } from 'recoil'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; @@ -17,11 +14,8 @@ const App = () => { - - - - - + + diff --git a/src/api/review.ts b/src/api/review.ts index 9c5e46df..33c11ba8 100644 --- a/src/api/review.ts +++ b/src/api/review.ts @@ -1,6 +1,5 @@ import client from './client'; import authClient from './authClient'; - // 리뷰 관련 API // 리뷰수정 diff --git a/src/api/socket.ts b/src/api/socket.ts index c5c437b4..978ae336 100644 --- a/src/api/socket.ts +++ b/src/api/socket.ts @@ -61,6 +61,18 @@ export const subBudget = ( }); }; +// 커서 공유 +export const subCursor = ( + tripId: string, + visitDate: string, + subCursorMessage: subCursorMessage, +) => { + socketClient.subscribe(`/sub/${tripId}/cursor/${visitDate}`, (message) => { + const res = JSON.parse(message.body); + subCursorMessage(res); + }); +}; + // 소켓 전송 // 여정 기본 정보 변경 이벤트 발생시 export const pubInfo = (pubInfo: pubInfo, tripId: string) => { @@ -101,6 +113,7 @@ export const pubUpdateTripItem = ( destination: `/pub/trips/${tripId}/updateTripItemOrder`, body: JSON.stringify(pubUpdateTripItem), }); + console.log('실행'); }; // 여행 날짜별 교통 수단 변경 이벤트 발생시 (01/16 업데이트) @@ -112,6 +125,7 @@ export const pubUpdateTransportation = ( destination: `/pub/trips/${tripId}/updateTransportation`, body: JSON.stringify(pubUpdateTransportation), }); + console.log('펍실행'); }; // 여행 아이템 방문 날짜 변경 이벤트 발생시 @@ -187,3 +201,11 @@ export const pubUpdateBudget = ( body: JSON.stringify(pubUpdateBudget), }); }; + +// 커서공유 +export const pubCursor = (pubCursor: pubCursor, tripId: string) => { + socketClient.publish({ + destination: `/pub/trips/${tripId}/cursor`, + body: JSON.stringify(pubCursor), + }); +}; diff --git a/src/api/trips.ts b/src/api/trips.ts index 0a89bb54..a33f5e38 100644 --- a/src/api/trips.ts +++ b/src/api/trips.ts @@ -21,7 +21,7 @@ export const putTrips = async ( // 여행 상세페이지에서 여정에 여행지 등록 export const postTripsItem = async ( tripId: string, - tourItemId: number, + tourItemId: string, visitDate: string, ) => { const requestBody = { diff --git a/src/components/Auth/AuthSurvey/AuthSurvey.tsx b/src/components/Auth/AuthSurvey/AuthSurvey.tsx index 7486b522..a4d02834 100644 --- a/src/components/Auth/AuthSurvey/AuthSurvey.tsx +++ b/src/components/Auth/AuthSurvey/AuthSurvey.tsx @@ -9,7 +9,7 @@ import { UserInfoState } from '@recoil/Auth.atom'; import { useRecoilState } from 'recoil'; interface Props { - path: string; + path?: string; } const AuthSurvey = ({ path }: Props) => { @@ -42,7 +42,11 @@ const AuthSurvey = ({ path }: Props) => { // newPrevUserInfo.survey = data; // return newPrevUserInfo; // }); - navigate(path); + if (path) { + navigate(path); + } else { + navigate(-1); + } } } catch (err) { console.error(err); diff --git a/src/components/DetailSectionBottom/DetailReviewStats.tsx b/src/components/DetailSectionBottom/DetailReviewStats.tsx index f87f181b..ade45a12 100644 --- a/src/components/DetailSectionBottom/DetailReviewStats.tsx +++ b/src/components/DetailSectionBottom/DetailReviewStats.tsx @@ -9,6 +9,7 @@ const DetailReviewStats = () => { const { reviewStats } = useGetToursReviews(); const { calculateWidth, getColor } = useReviewStatsCalculator(reviewStats); const [showAll, setShowAll] = useState(false); + console.log(reviewStats); return ( <> @@ -24,7 +25,7 @@ const DetailReviewStats = () => { backgroundColor: getColor(data.keywordCount), }} /> -
+

{getEmoji(data.content)}

{data.content}

diff --git a/src/components/DetailSectionBottom/DetailReviews.tsx b/src/components/DetailSectionBottom/DetailReviews.tsx index fe0e7e83..ddb3161c 100644 --- a/src/components/DetailSectionBottom/DetailReviews.tsx +++ b/src/components/DetailSectionBottom/DetailReviews.tsx @@ -27,11 +27,11 @@ import EditDelete from '@components/common/modal/children/EditDelete'; import MyAlert from '@components/common/modal/children/MyAlert'; import { alertTypeState } from '@recoil/modal'; -interface reviewProps { - reviewData: any; -} - -export default function DetailReviews({ reviewData }: reviewProps) { +export default function DetailReviews({ + reviewData, +}: { + reviewData: tourDetail; +}) { const [reviewDataLength, setReviewDataLength] = useState(0); const { title, contentTypeId } = reviewData; const params = useParams(); @@ -73,7 +73,7 @@ export default function DetailReviews({ reviewData }: reviewProps) { return
데이터를 불러오는 중 오류가 발생했습니다.
; } - const handleReviewClick = (item: any) => { + const handleReviewClick = (item: ReviewInfoItemProps) => { const reviewId = item.reviewId; navigate(`/reviewComment/${reviewId}`, { state: { item, tourItemId } }); }; @@ -101,7 +101,6 @@ export default function DetailReviews({ reviewData }: reviewProps) { }; useEffect(() => { - console.log('toursReviews', toursReviews); { toursReviews?.pages.map((group) => { setReviewDataLength(group?.data.data.reviewTotalCount); @@ -156,24 +155,26 @@ export default function DetailReviews({ reviewData }: reviewProps) { { return ( - {group?.data.data.reviewInfos.content.map((item: any) => ( - handleReviewClick(item)} - tourItemId={tourItemId} - contentTypeId={contentTypeId} - canTextOverflow={true} - isAuthor={item.isAuthor} - /> - ))} + {group?.data.data.reviewInfos.content.map( + (item: ReviewInfoItemProps) => ( + handleReviewClick(item)} + tourItemId={tourItemId} + contentTypeId={contentTypeId} + canTextOverflow={true} + isAuthor={item.isAuthor} + /> + ), + )} ); } @@ -188,7 +189,7 @@ export default function DetailReviews({ reviewData }: reviewProps) { {modalChildren === 'MyAlert' && alertType === 'LoginReview' && ( )} diff --git a/src/components/DetailSectionBottom/ReviewItem.tsx b/src/components/DetailSectionBottom/ReviewItem.tsx index 57a89c8c..2ff1c349 100644 --- a/src/components/DetailSectionBottom/ReviewItem.tsx +++ b/src/components/DetailSectionBottom/ReviewItem.tsx @@ -22,29 +22,7 @@ import { MouseEvent, useState } from 'react'; import { getEmoji } from '@utils/utils'; import { getStarFill } from '@utils/getStarFill'; -interface Keyword { - keywordId: number; - content: string; - type: string; -} - -interface ItemProps { - reviewId: number; - authorNickname: string; - authorProfileImageUrl: string; - rating: number; - createdTime: any; - content: string; - keywords: Keyword[]; // keywordId, content, type - commentCount: number; - onClick?: () => void; - tourItemId?: number; - contentTypeId?: number; - canTextOverflow: boolean; - isAuthor?: boolean; -} - -const Item: React.FC = (props: ItemProps) => { +const Item: React.FC = (props: ReviewInfoItemProps) => { const { reviewId, authorNickname, @@ -173,51 +151,41 @@ const Item: React.FC = (props: ItemProps) => {
{!showMoreKeywords && - keywords.slice(0, 2).map((keyword, idx) => ( + keywords.slice(0, 1).map((keyword, idx) => (
{getEmoji(keyword.content)} {keyword.content}
))} - {keywords.length > 2 && !showMoreKeywords && ( + {keywords.length > 1 && !showMoreKeywords && (
{ handleClickPlusButton(e); }}> - +{keywords.length - 2} + +{keywords.length - 1}
)}
+
- {showMoreKeywords && - Array.from({ length: Math.ceil(keywords.length / 2) }).map( - (_, lineIdx) => ( + {showMoreKeywords && ( +
+ {keywords.map((keyword, idx) => (
- {keywords - .slice(lineIdx * 2, lineIdx * 2 + 2) - .map((keyword, idx) => ( -
- {getEmoji(keyword.content)} {keyword.content} -
- ))} + key={idx} + className="rounded-md bg-gray1 px-2 py-1 text-xs text-gray6"> + {getEmoji(keyword.content)} {keyword.content}
- ), - )} + ))} +
+ )}
-
+
-
{commentCount}
+
{commentCount}
diff --git a/src/components/DetailSectionTop/DetailAddSchedule.tsx b/src/components/DetailSectionTop/DetailAddSchedule.tsx index 57880903..e976a48c 100644 --- a/src/components/DetailSectionTop/DetailAddSchedule.tsx +++ b/src/components/DetailSectionTop/DetailAddSchedule.tsx @@ -1,118 +1,283 @@ import * as Dialog from '@radix-ui/react-dialog'; -import { CalendarIcon } from '@components/common/icons/Icons'; +import { CalendarIcon, GrayCalendarIcon } from '@components/common/icons/Icons'; import Alert from '@components/common/alert/Alert'; import { useNavigate } from 'react-router-dom'; import { PlusIcon } from '@components/common/icons/Icons'; import { useGetMyTrips } from '@hooks/useGetMyTrips'; import { calculateTripDuration } from '@utils/calculateTripDuration'; import { calculateDayAndDate } from '@utils/utils'; +import Accordion from '@components/common/accordion/Accordion'; +import { useState, useEffect } from 'react'; +import { postTripsItem } from '@api/trips'; +import { useParams } from 'react-router-dom'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import ToastPopUp from '@components/common/toastpopup/ToastPopUp'; const DetailAddSchedule = () => { - const { myTrips } = useGetMyTrips(); + const token = localStorage.getItem('accessToken'); - const { SmallDayArr } = calculateDayAndDate( - myTrips[0]?.startDate, - myTrips[0]?.endDate, + const navigate = useNavigate(); + const { id: tourItemId } = useParams(); + const { myTrips } = useGetMyTrips(); + const [isOpen, setIsOpen] = useState(false); + const [openAccordion, setOpenAccordion] = useState(''); + const [isProcessing, setIsProcessing] = useState(false); + const [selectedVisitDate, setSelectedVisitDate] = useState( + null, + ); + const [selectedTripId, setSelectedTripId] = useState(null); + const [selectedButton, setSelectedButton] = useState(null); + const initialValue = myTrips.findIndex( + (trip) => trip.tripStatus !== '여행완료', ); - console.log(SmallDayArr); + const [toastPopUp, setToastPopUp] = useState({ + isPopUp: false, + noun: '', + verb: '', + }); - const navigate = useNavigate(); + const handleNavigate = (url: string) => { + navigate(url); + }; - const handleConfirm = () => { - navigate('/login'); + const handleDateButtonClick = ( + tripId: string | null, + visitDate: string | null, + index: number | null, + ) => { + setSelectedTripId(tripId); + setSelectedVisitDate(visitDate); + setSelectedButton(index); }; - const handleCreate = () => { - navigate('/create'); + const handleAccordion = (newValue: string) => { + setOpenAccordion(newValue); + setSelectedButton(null); }; - return ( - - - - + const handlePostTripsItem = async ( + tripId: string, + tourItemId: string, + visitDate: string, + ) => { + if (isProcessing) return; + setIsProcessing(true); + if (tripId && tourItemId && visitDate) { + try { + await postTripsItem(tripId, tourItemId, visitDate); + setIsOpen(false); + } catch (error) { + console.error('요청 실패:', error); + } finally { + setToastPopUp(() => ({ + isPopUp: true, + noun: '일정', + verb: '추가', + })); + setIsProcessing(false); + } + } + }; - - + useEffect(() => { + setOpenAccordion(`item-${initialValue}`); + }, [initialValue]); - - - - + useEffect(() => { + if (!isOpen) { + setOpenAccordion(`item-${initialValue}`); + setSelectedButton(null); + } + }, [isOpen]); - - {myTrips.map((trip, index) => { - // 각 여행에 대한 기간을 계산합니다. - const tripDuration = calculateTripDuration( - trip.startDate, - trip.endDate, - ); + useEffect(() => { + if (toastPopUp.isPopUp) { + const timer = setTimeout(() => { + setToastPopUp(() => ({ + isPopUp: false, + noun: '', + verb: '', + })); + }, 2000); + return () => clearTimeout(timer); + } + }, [toastPopUp]); - return ( -
-
-
- {`Thumbnail -
-
- {trip.tripName} -
-
- {trip.startDate?.replace(/-/g, '.')} -{' '} - {trip.endDate?.substring(5).replace(/-/g, '.')} ( - {tripDuration}) -
-
-
+ return ( + <> + {toastPopUp.isPopUp && ( + + )} + {token ? ( + + + + + + + 0 ? 'h-[392px]' : 'h-[276px]' + }`}> +
+
- ); - })} - -
-
-
- Day 1 -
+
-
- - - 일정 추가 시 로그인이 필요합니다. -
- 로그인 하시겠습니까? - - } - onConfirm={handleConfirm}> -
- -
-
-
-
-
+ {myTrips.length > 0 ? ( + + {myTrips.map((trip, index) => { + if (trip.tripStatus !== '여행완료') { + const tripDuration = calculateTripDuration( + trip.startDate, + trip.endDate, + ); + const { SmallDayArr, DateArr } = calculateDayAndDate( + trip.startDate, + trip.endDate, + ); + return ( + <> + +
+
+ {`Thumbnail +
+
+ {trip.tripName} +
+
+ {trip.startDate?.replace(/-/g, '.')} -{' '} + {trip.endDate + ?.substring(5) + .replace(/-/g, '.')}{' '} + {tripDuration === '0박 1일' + ? '' + : `(${tripDuration})`} +
+
+
+
+
+ } + content={ +
+ + {SmallDayArr.map((day, index) => ( + + + + ))} + +
+ } + /> + + ); + } + })} + + ) : ( + +
+ +

+ 참여하고 있는 여정이 없어요. +

+
+
+ )} + {myTrips.length > 0 ? ( +
+ +
+ ) : ( + '' + )} + + + + ) : ( + + 여정에 추가하려면 로그인이 필요해요. +
+ 로그인하러 가볼까요? + + } + onConfirm={() => handleNavigate('/login')}> + +
+ )} + ); }; diff --git a/src/components/DetailSectionTop/DetailSectionTop.tsx b/src/components/DetailSectionTop/DetailSectionTop.tsx index b6283042..7d4ad2c8 100644 --- a/src/components/DetailSectionTop/DetailSectionTop.tsx +++ b/src/components/DetailSectionTop/DetailSectionTop.tsx @@ -1,9 +1,7 @@ // import { useEffect, useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { useParams } from 'react-router-dom'; - import { getDetailTours, getToursReviews } from '@api/tours'; - import { DetailToursButtons, DetailToursInfo, diff --git a/src/components/DetailSectionTop/DetailToursButtons.tsx b/src/components/DetailSectionTop/DetailToursButtons.tsx index 8c9e01a6..d25e517d 100644 --- a/src/components/DetailSectionTop/DetailToursButtons.tsx +++ b/src/components/DetailSectionTop/DetailToursButtons.tsx @@ -10,11 +10,11 @@ import { useNavigate, useParams } from 'react-router-dom'; import { useSetRecoilState } from 'recoil'; import { getMember } from '@api/member'; -interface reviewProps { - reviewData: any; -} - -export default function DetailTourButtons({ reviewData }: reviewProps) { +export default function DetailTourButtons({ + reviewData, +}: { + reviewData: tourDetail; +}) { const { title, contentTypeId } = reviewData; const params = useParams(); const tourItemId = Number(params.id); @@ -48,8 +48,8 @@ export default function DetailTourButtons({ reviewData }: reviewProps) {
diff --git a/src/components/DetailSectionTop/DetailToursInfo.tsx b/src/components/DetailSectionTop/DetailToursInfo.tsx index 8af2a5ee..7b3eaba3 100644 --- a/src/components/DetailSectionTop/DetailToursInfo.tsx +++ b/src/components/DetailSectionTop/DetailToursInfo.tsx @@ -9,7 +9,7 @@ export default function DetailToursInfo({ infoData }: DetailToursInfoProps) { return ( <> -
+
tour-image
-

- {title} -

+

{title}

diff --git a/src/components/DetailSectionTop/DetailToursMap.tsx b/src/components/DetailSectionTop/DetailToursMap.tsx index 07871ac0..7bec6bc9 100644 --- a/src/components/DetailSectionTop/DetailToursMap.tsx +++ b/src/components/DetailSectionTop/DetailToursMap.tsx @@ -17,7 +17,7 @@ export default function DetailToursMap({ mapData }: DetailToursMapProps) { const MapStyle = { width: '100%', - height: '180px', + height: '160px', marginTop: '5px', marginBottom: '15px', }; @@ -42,7 +42,7 @@ export default function DetailToursMap({ mapData }: DetailToursMapProps) {
-

+

{fullAddress}

diff --git a/src/components/DetailSectionTop/DetailToursRating.tsx b/src/components/DetailSectionTop/DetailToursRating.tsx index 2be49e9c..4f10b83d 100644 --- a/src/components/DetailSectionTop/DetailToursRating.tsx +++ b/src/components/DetailSectionTop/DetailToursRating.tsx @@ -44,7 +44,7 @@ export default function DetailToursRating({
{STAR_IDX_ARR.map((item, idx) => { return ( - + ); })} - -
-

+

+

({reviewTotalCount})

diff --git a/src/components/MyTrip/MyTrip.tsx b/src/components/MyTrip/MyTrip.tsx index ae8ed92e..c80f12fc 100644 --- a/src/components/MyTrip/MyTrip.tsx +++ b/src/components/MyTrip/MyTrip.tsx @@ -32,7 +32,7 @@ const MyTrip = () => { return (
-

나의 여정

+

나의 여정

{data.length > 0 ? ( <> @@ -42,7 +42,7 @@ const MyTrip = () => { ) : ( } /> diff --git a/src/components/MyTrip/MyTripAfterList.tsx b/src/components/MyTrip/MyTripAfterList.tsx index ec33c2de..c5d65cb4 100644 --- a/src/components/MyTrip/MyTripAfterList.tsx +++ b/src/components/MyTrip/MyTripAfterList.tsx @@ -17,18 +17,22 @@ const MyTripAfterList: React.FC = ({ myTripsData }) => { new Date(a.startDate).getTime() - new Date(b.startDate).getTime(), ); - return ( - <> -
-

지난 여행

-
-
- {sortedTrips.map((myTripList: MyTripType) => ( - - ))} -
- - ); + if (sortedTrips.length > 0) { + return ( + <> +
+

지난 여행

+
+
+ {sortedTrips.map((myTripList: MyTripType) => ( + + ))} +
+ + ); + } else { + return null; + } }; export default MyTripAfterList; diff --git a/src/components/MyTrip/MyTripBeforeList.tsx b/src/components/MyTrip/MyTripBeforeList.tsx index e4d27037..88dc770f 100644 --- a/src/components/MyTrip/MyTripBeforeList.tsx +++ b/src/components/MyTrip/MyTripBeforeList.tsx @@ -14,8 +14,8 @@ const MyTripBeforeList: React.FC = ({ myTripsData }) => { return ( <> -
-

다가오는 여행

+
+

다가오는 여행

{myTripsData.map((myTripList: MyTripType) => ( diff --git a/src/components/MyTrip/MyTripIngItem.tsx b/src/components/MyTrip/MyTripIngItem.tsx index ca0d08d4..3ff6392c 100644 --- a/src/components/MyTrip/MyTripIngItem.tsx +++ b/src/components/MyTrip/MyTripIngItem.tsx @@ -16,27 +16,27 @@ const MyTripIngItem: React.FC = ({ myTripList }) => {
navigate(`/trip/${tripId}`)}> -
+
여행지 이미지
-
+
{tripStatus}
-
-
+
+
{tripName}
-
- {startDate.replace(/-/g, '.')} ~{' '} +
+ {startDate.replace(/-/g, '.')} -{' '} {endDate.replace(/-/g, '.').split('2024.')}{' '} {tripDuration === '0박 1일' ? null : ` (${tripDuration})`}
diff --git a/src/components/MyTrip/MyTripItem.tsx b/src/components/MyTrip/MyTripItem.tsx index 72375a66..b5878161 100644 --- a/src/components/MyTrip/MyTripItem.tsx +++ b/src/components/MyTrip/MyTripItem.tsx @@ -64,19 +64,19 @@ const MyTripItem: React.FC = ({ myTripList }) => { alt="여행지 이미지" />
-
-
-
+
+
+
{tripName}
-
+
{startDate.replace(/-/g, '.')} -{' '} {endDate.replace(/-/g, '.').split('2024.')} {tripDuration === '0박 1일' ? null : ` (${tripDuration})`}
-
+
{numberOfTripMember}명과 공유중
diff --git a/src/components/Mypage/LogoutButton.tsx b/src/components/Mypage/LogoutButton.tsx index 0e6666d7..c66aa282 100644 --- a/src/components/Mypage/LogoutButton.tsx +++ b/src/components/Mypage/LogoutButton.tsx @@ -34,7 +34,7 @@ const LogoutButton = () => { return (
-
+
img -
+
- {item.name.length > 17 - ? item.name.slice(0, 17) + '...' + {item.name.length > 16 + ? item.name.slice(0, 16) + '...' : item.name}
-
- {item.category} +
+
+ {item.category} +
-
+
{item.price} 원
@@ -171,7 +166,7 @@ const PlanEditItemBox = ({
선택한 장소를 삭제하시겠습니까?} + message={<>여정에서 이 장소를 삭제할까요?} onConfirm={handleConfirm} closeOnConfirm={true} isCheck={selectedItemId}> diff --git a/src/components/Plan/PlanItem.tsx b/src/components/Plan/PlanItem.tsx index 1de95e72..ebe35ae5 100644 --- a/src/components/Plan/PlanItem.tsx +++ b/src/components/Plan/PlanItem.tsx @@ -4,13 +4,14 @@ import { useNavigate } from 'react-router-dom'; import TripMap from './TripMap'; import PlanItemBox from './PlanItemBox'; import PlanEditItemBox from './PlanEditItemBox'; -import { useContext, useEffect } from 'react'; +import { useContext, useEffect, useCallback } from 'react'; import { socketContext } from '@hooks/useSocket'; import { useRecoilState, useRecoilValue } from 'recoil'; import { visitDateState, isEditState } from '@recoil/socket'; import { pubGetPathAndItems, pubUpdateTransportation } from '@api/socket'; import { tapState } from '@recoil/plan'; import { useGetTripsAuthority } from '@hooks/useGetTripsAuthority'; +import { debounce } from 'lodash'; type PlanItemProps = { date: string; @@ -40,37 +41,35 @@ const PlanItem: React.FC = ({ date, day }) => { setIsEdit((prev) => !prev); }; - const handleTranspo = ( - transportation: 'CAR' | 'PUBLIC_TRANSPORTATION', - date: string, - tripId: string, - ) => { - if (transportation !== transpo) { - callBackPub(() => + const transpo = tripItem?.data?.transportation || ''; + + const debouncedHandleTranspo = useCallback( + debounce((transportation, date, tripId) => { + if (transportation !== transpo) { pubUpdateTransportation( { visitDate: date, transportation: transportation, }, tripId, - ), - ); - } - }; - - const transpo = tripItem?.data?.transportation || ''; + ); + } + }, 1000), + [transpo], + ); return ( <> {tripPath && } -
{tripAuthority !== 'WRITE' || isEdit ? (
) : (
handleTranspo('CAR', date || '', tripId || '')} + onClick={() => + debouncedHandleTranspo('CAR', date || '', tripId || '') + } className="flex h-[32px] w-[32px] cursor-pointer items-center justify-center rounded-l-md border border-solid border-gray3"> = ({ date, day }) => {
- handleTranspo('PUBLIC_TRANSPORTATION', date || '', tripId || '') + debouncedHandleTranspo( + 'PUBLIC_TRANSPORTATION', + date || '', + tripId || '', + ) } className="pointer-cursor -ml-[1px] flex h-[32px] w-[32px] cursor-pointer items-center justify-center rounded-r-md border border-solid border-gray3"> = ({ date, day }) => {
navigate('./place')} - className="h-[40px] w-full"> + className="h-[56px] w-full">
장소 추가하기
diff --git a/src/components/Plan/PlanItemBox.tsx b/src/components/Plan/PlanItemBox.tsx index 3244d0cc..4cdd0f64 100644 --- a/src/components/Plan/PlanItemBox.tsx +++ b/src/components/Plan/PlanItemBox.tsx @@ -31,7 +31,6 @@ const PlanItemBox = ({ if (!item || !paths) { return
Missing data
; } - console.log(paths); const { tripAuthority } = useGetTripsAuthority(); const { tripId } = useContext(socketContext); @@ -53,10 +52,19 @@ const PlanItemBox = ({ } }; + const formatTime = (totalMinutes: number) => { + const hours = Math.floor(totalMinutes / 60); + const minutes = totalMinutes % 60; + if (hours === 0) { + return `${minutes}분`; + } + return `${hours}시간 ${minutes}분`; + }; + return ( <>
-
{day}
+
{day}
{item.map((item, index) => (
@@ -68,17 +76,25 @@ const PlanItemBox = ({
-
+
img -
-
- {item.name.length > 19 - ? item.name.slice(0, 19) + '...' +
+
+ {item.name.length > 16 + ? item.name.slice(0, 16) + '...' : item.name} +
+
+
+ {item.category} +
+
+
+ {item.price.toLocaleString()} 원 {tripAuthority == 'WRITE' && ( - + } content={ -
+
setInputPrice(e.target.value)} @@ -118,12 +134,6 @@ const PlanItemBox = ({ /> )}
-
- {item.category} -
-
- {item.price.toLocaleString()} 원 -
{index < itemLength - 1 && @@ -148,9 +158,9 @@ const PlanItemBox = ({ ? '경로 정보가 없습니다.' : `${(path.pathInfo.totalDistance / 1000).toFixed( 2, - )}km, ${ - path.pathInfo.totalTime - }분, ${path.pathInfo.price.toLocaleString()}원`} + )}km, ${formatTime( + path.pathInfo.totalTime, + )}, ${path.pathInfo.price.toLocaleString()}원`}
diff --git a/src/components/Plan/PlanMoveItem.tsx b/src/components/Plan/PlanMoveItem.tsx index 0daa5b5f..51d36b81 100644 --- a/src/components/Plan/PlanMoveItem.tsx +++ b/src/components/Plan/PlanMoveItem.tsx @@ -3,8 +3,6 @@ import { PaperIcon } from '@components/common/icons/Icons'; import { useRecoilValue } from 'recoil'; import { dayState, dateState } from '@recoil/plan'; import { pubUpdateVisitDate } from '@api/socket'; -import { useContext } from 'react'; -import { socketContext } from '@hooks/useSocket'; import { useState, useEffect } from 'react'; import ToastPopUp from '@components/common/toastpopup/ToastPopUp'; import { useRecoilState } from 'recoil'; @@ -22,7 +20,6 @@ const PlanMoveItem: React.FC = ({ visitDate, }) => { const [, setIsEdit] = useRecoilState(isEditState); - const { callBackPub } = useContext(socketContext); const day = useRecoilValue(dayState); const date = useRecoilValue(dateState); @@ -37,15 +34,13 @@ const PlanMoveItem: React.FC = ({ return; } if (tripId && isCheck && visitDate) { - callBackPub(() => - pubUpdateVisitDate( - { - tripId: tripId, - oldVisitDate: visitDate, - newVisitDate: newVisitDate, - }, - isCheck, - ), + pubUpdateVisitDate( + { + tripId: tripId, + oldVisitDate: visitDate, + newVisitDate: newVisitDate, + }, + isCheck, ); } setToastPopUp(() => ({ @@ -85,17 +80,17 @@ const PlanMoveItem: React.FC = ({ - +
-
-

+

+

날짜 이동

-
-
+
+
{day.map((day, index) => ( - ); - }, - )} + return ( + + ); + })}
); diff --git a/src/components/Review/ReviewRating.tsx b/src/components/Review/ReviewRating.tsx index 7ec0baed..f4f5ffb1 100644 --- a/src/components/Review/ReviewRating.tsx +++ b/src/components/Review/ReviewRating.tsx @@ -13,7 +13,7 @@ const ReviewRating = () => { const handleStarClick = (index: number) => { const newRating = index + 1; - setRating((prevRating: any) => { + setRating((prevRating: number) => { const updatedIsHalfClicked = prevRating === newRating ? !isHalfClicked : false; setIsHalfClicked(updatedIsHalfClicked); diff --git a/src/components/Share/IsEditableModal.tsx b/src/components/Share/IsEditableModal.tsx index 5087ef94..f3f6a832 100644 --- a/src/components/Share/IsEditableModal.tsx +++ b/src/components/Share/IsEditableModal.tsx @@ -22,8 +22,8 @@ const IsEditableModal = ({ isEditable, setIsEditable }: Props) => { return ( - - + + 편집 참여 코드를 입력하시면
diff --git a/src/components/Tours/CreateTripButton.tsx b/src/components/Tours/CreateTripButton.tsx index 27026623..0cffb946 100644 --- a/src/components/Tours/CreateTripButton.tsx +++ b/src/components/Tours/CreateTripButton.tsx @@ -45,9 +45,9 @@ const CreateTripButton = () => { title={'로그인'} message={ <> - 로그인이 필요한 기능입니다. + 여정을 계획하려면 로그인이 필요해요.
- 로그인 하시겠습니까? + 로그인하러 가볼까요? } onConfirm={handleConfirm}> diff --git a/src/components/Tours/ToursCategory.tsx b/src/components/Tours/ToursCategory.tsx index 8f899739..8042e180 100644 --- a/src/components/Tours/ToursCategory.tsx +++ b/src/components/Tours/ToursCategory.tsx @@ -1,4 +1,3 @@ -import { RegionTypes, ToursCategoryProps } from '@/@types/tours.types'; import ToursCategoryItem from './ToursCategoryItem'; import { getPopularRegion } from '@api/region'; import { Swiper, SwiperSlide } from 'swiper/react'; @@ -52,7 +51,11 @@ const ToursCategory = ({ if (showSkeleton) { return (
- + {Array.from({ length: 10 }, (_, index) => ( diff --git a/src/components/Tours/ToursCategoryItem.tsx b/src/components/Tours/ToursCategoryItem.tsx index f7e62cb3..f6a11688 100644 --- a/src/components/Tours/ToursCategoryItem.tsx +++ b/src/components/Tours/ToursCategoryItem.tsx @@ -1,5 +1,3 @@ -import { ToursCategoryItemProps } from '@/@types/tours.types'; - const ToursCategoryItem = ({ name, isSelected, diff --git a/src/components/Tours/ToursItem.tsx b/src/components/Tours/ToursItem.tsx index 0e30a938..c6221f5c 100644 --- a/src/components/Tours/ToursItem.tsx +++ b/src/components/Tours/ToursItem.tsx @@ -1,4 +1,3 @@ -import { TourType } from '@/@types/tours.types'; import { HeartIcon, StarIcon } from '@components/common/icons/Icons'; import Like from '@components/common/like/Like'; import { useNavigate } from 'react-router-dom'; diff --git a/src/components/Tours/ToursList.tsx b/src/components/Tours/ToursList.tsx index 45888808..9f3a8a09 100644 --- a/src/components/Tours/ToursList.tsx +++ b/src/components/Tours/ToursList.tsx @@ -1,4 +1,3 @@ -import { TourType, ToursListProps } from '@/@types/tours.types'; import { getTours } from '@api/tours'; import { useInfiniteQuery } from '@tanstack/react-query'; import React, { useEffect, useState } from 'react'; @@ -46,6 +45,7 @@ const ToursList = ({ selectedRegion }: ToursListProps) => { pageStart={0} loadMore={() => fetchNextPage()} hasMore={hasNextPage} + threshold={500} loader={
diff --git a/src/components/Trip/EditCodeModal.tsx b/src/components/Trip/EditCodeModal.tsx index b17dfbe7..f5e5c7ea 100644 --- a/src/components/Trip/EditCodeModal.tsx +++ b/src/components/Trip/EditCodeModal.tsx @@ -63,21 +63,21 @@ const EditCodeModal = () => { return ( <> - {isToastVisible && } + {isToastVisible && } {isLogin ? ( tripAuthority === 'WRITE' ? ( {isEditModal && ( - - + + 나의 여정 diff --git a/src/components/Trip/LikedToursList.tsx b/src/components/Trip/LikedToursList.tsx index 5587077e..9fa49f59 100644 --- a/src/components/Trip/LikedToursList.tsx +++ b/src/components/Trip/LikedToursList.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { useInfiniteQuery } from '@tanstack/react-query'; @@ -8,8 +8,10 @@ import NoDataMessage from '@components/common/noData/NoDataMessage'; import { getTripsLike } from '@api/trips'; import { HeartIcon, NewIcon } from '@components/common/icons/Icons'; +import Alert from '@components/common/alert/Alert'; export const LikedToursList = () => { + const [isLoggedIn, setIsLoggedIn] = useState(false); const [selectedContentTypeId, setSelectedContentTypeId] = useState< null | number >(null); @@ -18,7 +20,7 @@ export const LikedToursList = () => { const { id: tripId } = useParams(); if (!tripId) { - return; + return null; } const { fetchNextPage, hasNextPage, data, isLoading, error } = @@ -52,8 +54,21 @@ export const LikedToursList = () => { setSelectedContentTypeId(contentTypeId); }; + const handleConfirm = () => { + navigate('/login'); + }; + + useEffect(() => { + const token = window.localStorage.getItem('accessToken'); + if (token) { + setIsLoggedIn(true); + } else { + setIsLoggedIn(false); + } + }, []); + return ( -
+
{data?.pages[0].data.content.length > 0 ? ( @@ -70,7 +85,7 @@ export const LikedToursList = () => { ) : (
} /> @@ -78,16 +93,38 @@ export const LikedToursList = () => { )} {/* 우리의 관심 여행지 추가 버튼 => 검색 라우터 이동 */} -
- -
+ {isLoggedIn ? ( +
+ +
+ ) : ( + + 관심 여행지를 추가하려면 로그인이 필요해요. +
+ 로그인하러 가볼까요? + + } + onConfirm={handleConfirm}> +
+ +
+
+ )}
); }; diff --git a/src/components/Trip/LikedToursLists/LikedToursListCategory.tsx b/src/components/Trip/LikedToursLists/LikedToursListCategory.tsx index 8a243c2f..8e78be04 100644 --- a/src/components/Trip/LikedToursLists/LikedToursListCategory.tsx +++ b/src/components/Trip/LikedToursLists/LikedToursListCategory.tsx @@ -12,9 +12,9 @@ const LikedToursListCategory: React.FC = ({ const categories = [ { code: null, name: '전체' }, - { code: 12, name: '관광지' }, { code: 32, name: '숙소' }, { code: 39, name: '식당' }, + { code: 12, name: '관광지' }, ]; const handleSelectCategory = (name: string) => { @@ -27,7 +27,7 @@ const LikedToursListCategory: React.FC = ({ }; return ( -
+
{categories.map((category) => { return ( + className={`body4 mr-[8px] flex h-[32px] w-[58px] items-center justify-center whitespace-nowrap rounded-[30px] border border-solid bg-[#28D8FF] px-[16px] py-[7px] leading-normal ${buttonStyle}`}> {category.name} ); diff --git a/src/components/Trip/LikedToursLists/LikedToursListItem.tsx b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx index 7260e8fa..f72641fa 100644 --- a/src/components/Trip/LikedToursLists/LikedToursListItem.tsx +++ b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx @@ -1,3 +1,7 @@ +import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { postTripsLikeHate } from '@api/trips'; import { ThumbsUp, ThumbsDown, @@ -5,10 +9,6 @@ import { ClickThumbsDown, StarIcon, } from '@components/common/icons/Icons'; -import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { postTripsLikeHate } from '@api/trips'; -import { useNavigate } from 'react-router-dom'; -import { useState } from 'react'; interface LikedToursListItemProps { ourTripList: ourTripType; @@ -34,11 +34,11 @@ const LikedToursListItem: React.FC = ({ const navigate = useNavigate(); const queryClient = useQueryClient(); const [thumbsState, setThumbsState] = useState({ - prefer: false, - notPrefer: false, + prefer: prefer, + notPrefer: notPrefer, }); - const { mutate: thumbsUpMutate } = useMutation({ + const { mutate: thumbsMutate } = useMutation({ mutationFn: () => postTripsLikeHate( selectedTripId, @@ -54,36 +54,42 @@ const LikedToursListItem: React.FC = ({ const onClickThumbsUpButton = (e: React.MouseEvent) => { e.stopPropagation(); - setThumbsState({ prefer: true, notPrefer: false }); - thumbsUpMutate(); + setThumbsState((prev) => ({ + prefer: !prev.prefer, + notPrefer: false, + })); + thumbsMutate(); }; const onClickThumbsDownButton = (e: React.MouseEvent) => { e.stopPropagation(); - setThumbsState({ prefer: false, notPrefer: true }); - thumbsUpMutate(); + setThumbsState((prev) => ({ + prefer: false, + notPrefer: !prev.notPrefer, + })); + thumbsMutate(); }; return (
navigate(`/detail/${tourItemId}`)}>
여행지 이미지
-
-
-

+

+
+

{title}

-
+
diff --git a/src/components/Trip/PlanTripButton.tsx b/src/components/Trip/PlanTripButton.tsx index 01cb4eb9..ccba7409 100644 --- a/src/components/Trip/PlanTripButton.tsx +++ b/src/components/Trip/PlanTripButton.tsx @@ -24,7 +24,7 @@ const PlanTripButton = () => {
-

여행 계획하기

+

여행 계획하기

diff --git a/src/components/Trip/TripInfo.tsx b/src/components/Trip/TripInfo.tsx index 973a38b1..72b02f76 100644 --- a/src/components/Trip/TripInfo.tsx +++ b/src/components/Trip/TripInfo.tsx @@ -5,7 +5,6 @@ import TripSurveyMember from '@components/common/modal/children/TripSurveyMember import { Modal } from '@components/common/modal'; import { useQuery } from '@tanstack/react-query'; import { getTripsMembers } from '@api/trips'; -// import { ReactComponent as NullUser } from '@assets/images/NullUser.svg'; import { DownIcon } from '@components/common/icons/Icons'; import { useState } from 'react'; import { UserIcon } from '@components/common/icons/Icons'; @@ -23,12 +22,11 @@ const ShareList = () => { enabled: !!tripId, }); const members = tripsMembers?.data?.data?.tripMemberSimpleInfos; - console.log(tripsMembers); return ( <>
- {members.map((member: any, index: number) => { + {members.map((member: TripMemeberInfo, index: number) => { return (
{ }>
- // )}
{member.nickname}
@@ -92,7 +89,7 @@ const TripInfo = () => {
- {members?.map((member: any, index: number) => ( + {members?.map((member: TripMemeberInfo, index: number) => (
{member.profileImageUrl && member.profileImageUrl !== 'http://asiduheimage.jpg' ? ( @@ -108,7 +105,6 @@ const TripInfo = () => { }>
- // )}
))} diff --git a/src/components/Trip/TripParticipant.tsx b/src/components/Trip/TripParticipant.tsx index d114a6d5..28938a6f 100644 --- a/src/components/Trip/TripParticipant.tsx +++ b/src/components/Trip/TripParticipant.tsx @@ -7,9 +7,11 @@ interface ParticipantStatusProps { status: string; } -const ParticipantList: React.FC<{ infos: any[] }> = ({ infos }) => ( +const ParticipantList: React.FC<{ infos: TripSurveySetMemberInfo[] }> = ({ + infos, +}) => (
- {infos.map((info: any) => ( + {infos.map((info: TripSurveySetMemberInfo) => (
diff --git a/src/components/Trip/TripPreference.tsx b/src/components/Trip/TripPreference.tsx index bcc94302..16749894 100644 --- a/src/components/Trip/TripPreference.tsx +++ b/src/components/Trip/TripPreference.tsx @@ -14,19 +14,19 @@ import { useGetTripsAuthority } from '@hooks/useGetTripsAuthority'; import { useNavigate } from 'react-router-dom'; import { getMember } from '@api/member'; -interface RatioBarParams { +type RatioBarParams = { value: number; total: number; color: string; label1: string; label2: string; -} +}; -interface PercentageParams { +type PercentageParams = { value: number; total: number; color: string; -} +}; const TripPreferenceButton: React.FC = () => { const { tripAuthority } = useGetTripsAuthority(); diff --git a/src/components/Trip/TripRealtimeMember.tsx b/src/components/Trip/TripRealtimeMember.tsx index 5dd0fd86..db5a77ea 100644 --- a/src/components/Trip/TripRealtimeMember.tsx +++ b/src/components/Trip/TripRealtimeMember.tsx @@ -6,7 +6,6 @@ import { Navigation } from 'swiper/modules'; const TripRealtimeMember = () => { const { tripMember } = useContext(socketContext); - const tripMemberData = tripMember?.data; return ( @@ -15,7 +14,7 @@ const TripRealtimeMember = () => { slidesPerView={5} navigation={true} modules={[Navigation]} - className="flex w-[375px] items-center justify-center"> + className="flex w-[100vw] max-w-[375px] items-center justify-center"> {tripMemberData?.tripMembers?.map((member) => { const isConnected = member?.connected; const thumbnailUrl = member?.thumbnailUrl; diff --git a/src/components/Trip/TripSectionTop.tsx b/src/components/Trip/TripSectionTop.tsx index 730f3a65..7b40a52c 100644 --- a/src/components/Trip/TripSectionTop.tsx +++ b/src/components/Trip/TripSectionTop.tsx @@ -8,6 +8,7 @@ import { LikedToursList } from './LikedToursList'; import { useGetTripsAuthority } from '@hooks/useGetTripsAuthority'; import { useEffect, useState } from 'react'; import IsEditableModal from '@components/Share/IsEditableModal'; +import ScrollTopButton from '@components/common/scrollTopButton/ScrollTopButton'; const TripSectionTop = () => { const navigate = useNavigate(); @@ -43,6 +44,8 @@ const TripSectionTop = () => { lists={['우리의 여행취향', '우리의 관심목록']} contents={[, ]} /> + +
); }; diff --git a/src/components/Wish/Wish.tsx b/src/components/Wish/Wish.tsx index 7858c79c..560a700a 100644 --- a/src/components/Wish/Wish.tsx +++ b/src/components/Wish/Wish.tsx @@ -5,6 +5,7 @@ import WishList from './WishList'; import NoDataMessage from '@components/common/noData/NoDataMessage'; import { getMemberTours } from '@api/member'; import { HeartIcon } from '@components/common/icons/Icons'; +import ScrollTopButton from '@components/common/scrollTopButton/ScrollTopButton'; const Wish = () => { const [selectedContentTypeId, setSelectedContentTypeId] = useState< @@ -43,7 +44,7 @@ const Wish = () => { } return ( -
+

나의 관심 목록

@@ -59,11 +60,13 @@ const Wish = () => { /> ) : ( } /> )} + +
); }; diff --git a/src/components/Wish/WishCategory.tsx b/src/components/Wish/WishCategory.tsx index c288671b..7e9d55af 100644 --- a/src/components/Wish/WishCategory.tsx +++ b/src/components/Wish/WishCategory.tsx @@ -10,9 +10,9 @@ const WishCategory: React.FC = ({ onCategoryClick }) => { const categories = [ { code: null, name: '전체' }, - { code: 12, name: '관광지' }, { code: 32, name: '숙소' }, { code: 39, name: '식당' }, + { code: 12, name: '관광지' }, ]; const handleSelectCategory = (name: string) => { @@ -25,7 +25,7 @@ const WishCategory: React.FC = ({ onCategoryClick }) => { }; return ( -
+
{categories.map((category) => { return ( = ({ return ( ); diff --git a/src/components/Wish/WishItem.tsx b/src/components/Wish/WishItem.tsx index 8a27f666..75928caa 100644 --- a/src/components/Wish/WishItem.tsx +++ b/src/components/Wish/WishItem.tsx @@ -1,4 +1,3 @@ -import { TourType } from '@/@types/tours.types'; import { HeartIcon, StarIcon } from '@components/common/icons/Icons'; import Like from '@components/common/like/Like'; import { useEffect, useState } from 'react'; @@ -33,12 +32,12 @@ const WishItem: React.FC = ({ wishList }) => { return (
navigate(`/detail/${id}`)}> -
+
여행지 이미지 @@ -48,25 +47,25 @@ const WishItem: React.FC = ({ wishList }) => {
-
-

+

+

{title}

-
+

{isMetroIncluded && tourAddress ? (tourAddress.match(/(.*?[시군구])/)?.[0] || '') + (tourAddress .replace(/(.*?[시군구])/, '') - .match(/(특별시|광역시)?.*?[시군구]/)?.[0] || '') + .match(/(특별`시|광역시)?.*?[시군구]/)?.[0] || '') : tourAddress?.match(/(.*?[시군구])/)?.[0]}

-
+
-
+
@@ -79,10 +78,10 @@ const WishItem: React.FC = ({ wishList }) => {
-
+
- + {likedCount ? likedCount.toLocaleString() : likedCount}
diff --git a/src/components/Wish/WishList.tsx b/src/components/Wish/WishList.tsx index 45c2f717..c4fbb68d 100644 --- a/src/components/Wish/WishList.tsx +++ b/src/components/Wish/WishList.tsx @@ -3,7 +3,6 @@ import InfiniteScroll from 'react-infinite-scroller'; import { v4 as uuidv4 } from 'uuid'; import WishItem from './WishItem'; import ToursItemSkeleton from '@components/Tours/ToursItemSkeleton'; -import { TourType } from '@/@types/tours.types'; import { Spinner } from '@components/common/spinner/Spinner'; interface WishListProps { diff --git a/src/pages/plan/AddToTripPlan/OurLiked.tsx b/src/components/addToList/AddToTripPlan/OurLiked.tsx similarity index 100% rename from src/pages/plan/AddToTripPlan/OurLiked.tsx rename to src/components/addToList/AddToTripPlan/OurLiked.tsx diff --git a/src/pages/plan/AddToTripPlan/OurLikedList.tsx b/src/components/addToList/AddToTripPlan/OurLikedList.tsx similarity index 97% rename from src/pages/plan/AddToTripPlan/OurLikedList.tsx rename to src/components/addToList/AddToTripPlan/OurLikedList.tsx index 76d48865..512ef578 100644 --- a/src/pages/plan/AddToTripPlan/OurLikedList.tsx +++ b/src/components/addToList/AddToTripPlan/OurLikedList.tsx @@ -2,7 +2,6 @@ import React from 'react'; import InfiniteScroll from 'react-infinite-scroller'; import { v4 as uuidv4 } from 'uuid'; import { OurLikedListItem } from './OurLikedListItem'; -import { LikedListType } from '@/@types/tours.types'; import { Spinner } from '@components/common/spinner/Spinner'; interface WishListProps { diff --git a/src/pages/plan/AddToTripPlan/OurLikedListItem.tsx b/src/components/addToList/AddToTripPlan/OurLikedListItem.tsx similarity index 97% rename from src/pages/plan/AddToTripPlan/OurLikedListItem.tsx rename to src/components/addToList/AddToTripPlan/OurLikedListItem.tsx index 19a20840..3548e423 100644 --- a/src/pages/plan/AddToTripPlan/OurLikedListItem.tsx +++ b/src/components/addToList/AddToTripPlan/OurLikedListItem.tsx @@ -1,4 +1,3 @@ -import { LikedListType } from '@/@types/tours.types'; import { ListCheckBtn } from '@components/common/button/ListSelectBtn'; import { StarIcon } from '@components/common/icons/Icons'; import { selectedItemsState } from '@recoil/listItem'; diff --git a/src/pages/plan/addToOurPlace/AddtoListBtn.tsx b/src/components/addToList/addToOurPlace/AddtoListBtn.tsx similarity index 98% rename from src/pages/plan/addToOurPlace/AddtoListBtn.tsx rename to src/components/addToList/addToOurPlace/AddtoListBtn.tsx index ea7589f6..80b1e760 100644 --- a/src/pages/plan/addToOurPlace/AddtoListBtn.tsx +++ b/src/components/addToList/addToOurPlace/AddtoListBtn.tsx @@ -17,7 +17,6 @@ const AddToListButton = ({ const [selectedTourItemIds, setSelectedTourItemIds] = useRecoilState(selectedItemsState); const visitDate = useRecoilValue(visitDateState); - console.log(selectedTourItemIds); const { callBackPub } = useContext(socketContext); const navigate = useNavigate(); diff --git a/src/pages/plan/addToOurPlace/MyLiked.tsx b/src/components/addToList/addToOurPlace/MyLiked.tsx similarity index 100% rename from src/pages/plan/addToOurPlace/MyLiked.tsx rename to src/components/addToList/addToOurPlace/MyLiked.tsx diff --git a/src/pages/plan/addToOurPlace/MyLikedList.tsx b/src/components/addToList/addToOurPlace/MyLikedList.tsx similarity index 97% rename from src/pages/plan/addToOurPlace/MyLikedList.tsx rename to src/components/addToList/addToOurPlace/MyLikedList.tsx index 6979f41a..c8acd8d7 100644 --- a/src/pages/plan/addToOurPlace/MyLikedList.tsx +++ b/src/components/addToList/addToOurPlace/MyLikedList.tsx @@ -2,7 +2,6 @@ import React from 'react'; import InfiniteScroll from 'react-infinite-scroller'; import { v4 as uuidv4 } from 'uuid'; import { MyLikedListItem } from './MyLikedListItem'; -import { TourType } from '@/@types/tours.types'; import { Spinner } from '@components/common/spinner/Spinner'; interface WishListProps { diff --git a/src/pages/plan/addToOurPlace/MyLikedListItem.tsx b/src/components/addToList/addToOurPlace/MyLikedListItem.tsx similarity index 97% rename from src/pages/plan/addToOurPlace/MyLikedListItem.tsx rename to src/components/addToList/addToOurPlace/MyLikedListItem.tsx index 67628128..852b5ddd 100644 --- a/src/pages/plan/addToOurPlace/MyLikedListItem.tsx +++ b/src/components/addToList/addToOurPlace/MyLikedListItem.tsx @@ -1,4 +1,3 @@ -import { TourType } from '@/@types/tours.types'; import { ListCheckBtn } from '@components/common/button/ListSelectBtn'; import { StarIcon } from '@components/common/icons/Icons'; import { selectedItemsState } from '@recoil/listItem'; diff --git a/src/pages/plan/addToOurPlace/PlanAddPlace.page.tsx b/src/components/addToList/addToOurPlace/PlanAddPlace.page.tsx similarity index 100% rename from src/pages/plan/addToOurPlace/PlanAddPlace.page.tsx rename to src/components/addToList/addToOurPlace/PlanAddPlace.page.tsx diff --git a/src/pages/plan/addToOurPlace/ResultCategoryPlan.tsx b/src/components/addToList/addToOurPlace/ResultCategoryPlan.tsx similarity index 96% rename from src/pages/plan/addToOurPlace/ResultCategoryPlan.tsx rename to src/components/addToList/addToOurPlace/ResultCategoryPlan.tsx index b8988d18..e7fd80f2 100644 --- a/src/pages/plan/addToOurPlace/ResultCategoryPlan.tsx +++ b/src/components/addToList/addToOurPlace/ResultCategoryPlan.tsx @@ -1,5 +1,4 @@ import { ButtonWhite } from '@components/common/button/Button'; -import { TourType } from '@/@types/tours.types'; import { InfiniteQueryObserverResult } from '@tanstack/react-query'; import { ResultItemPlan } from './ResultItem'; import AddToListButton from './AddtoListBtn'; diff --git a/src/pages/plan/addToOurPlace/ResultItem.tsx b/src/components/addToList/addToOurPlace/ResultItem.tsx similarity index 97% rename from src/pages/plan/addToOurPlace/ResultItem.tsx rename to src/components/addToList/addToOurPlace/ResultItem.tsx index 7d027aaa..9b99dc1e 100644 --- a/src/pages/plan/addToOurPlace/ResultItem.tsx +++ b/src/components/addToList/addToOurPlace/ResultItem.tsx @@ -1,4 +1,3 @@ -import { TourType } from '@/@types/tours.types'; import { ListSelectBtn } from '@components/common/button/ListSelectBtn'; import { StarIcon } from '@components/common/icons/Icons'; import { selectedItemsState } from '@recoil/listItem'; diff --git a/src/pages/plan/addToOurPlace/SearchResult.tsx b/src/components/addToList/addToOurPlace/SearchResult.tsx similarity index 100% rename from src/pages/plan/addToOurPlace/SearchResult.tsx rename to src/components/addToList/addToOurPlace/SearchResult.tsx diff --git a/src/components/common/accordion/Accordion.tsx b/src/components/common/accordion/Accordion.tsx index 4175b9f7..3d8a8fe9 100644 --- a/src/components/common/accordion/Accordion.tsx +++ b/src/components/common/accordion/Accordion.tsx @@ -1,21 +1,31 @@ import * as accordion from '@radix-ui/react-accordion'; -import { DownIcon } from '../icons/Icons'; interface AccordionProps { title: React.ReactNode; content: React.ReactNode; + value: string; + openAccordion: string; + setOpenAccordion: (value: string) => void; } -const Accordion: React.FC = ({ title, content }) => { +const Accordion: React.FC = ({ + title, + content, + value, + openAccordion, + setOpenAccordion, +}) => { return ( - - - - {title} - - - - + + + + {title} + + {content} diff --git a/src/components/common/button/Button.tsx b/src/components/common/button/Button.tsx index a3ca8c3b..211bfa70 100644 --- a/src/components/common/button/Button.tsx +++ b/src/components/common/button/Button.tsx @@ -29,7 +29,7 @@ export const ButtonPrimary: React.FC = ({ return ( diff --git a/src/components/common/header/DetailHeader.tsx b/src/components/common/header/DetailHeader.tsx index c008416d..2350511d 100644 --- a/src/components/common/header/DetailHeader.tsx +++ b/src/components/common/header/DetailHeader.tsx @@ -13,7 +13,7 @@ export default function DetailHeader() { }; return ( -
+
diff --git a/src/components/common/icons/Icons.tsx b/src/components/common/icons/Icons.tsx index c8d95c73..ec00f17e 100644 --- a/src/components/common/icons/Icons.tsx +++ b/src/components/common/icons/Icons.tsx @@ -34,7 +34,7 @@ export const HomeIcon: React.FC = ({ }; export const CalendarIcon: React.FC = ({ - size = 25, + size = 20, color = 'black', fill = 'none', className, @@ -44,76 +44,87 @@ export const CalendarIcon: React.FC = ({ xmlns="http://www.w3.org/2000/svg" width={size} height={size} - className={className} - viewBox="0 0 25 25" - fill={fill}> - + viewBox="0 0 21 21" + color={color} + fill={fill} + className={className}> + + ); +}; + +export const CalendarIcon2: React.FC = ({ size = 25 }) => { + return ( + + = ({ ); }; -export const CalendarIcon2: React.FC = ({ size = 25 }) => { +export const CalendarIcon3: React.FC = ({ + size = 25, + color = 'black', + fill = 'none', + className, +}) => { return ( + fill={fill}> + = ({ }; export const PenIcon: React.FC = ({ - size = 25, + size = 20, color = 'black', fill = 'none', className, @@ -386,24 +412,21 @@ export const PenIcon: React.FC = ({ }; export const PhoneIcon: React.FC = ({ - size = 25, - color = 'black', - fill = 'none', + size = 20, + color = '#888888', + fill = '#888888', }) => { return ( - - - + viewBox="0 0 21 21" + fill={fill}> + ); }; @@ -683,32 +706,23 @@ export const SearchIcon: React.FC = ({ }) => { return ( - - - - + fill={fill}> + + ); }; @@ -1041,8 +1055,8 @@ export const TopIcon: React.FC = () => { }; export const ShareIcon: React.FC = ({ - width = 20, - height = 19, + width = 17.9, + height = 17, fill = 'none', color = 'black', }) => { @@ -1707,3 +1721,88 @@ export const DropdownIcon: React.FC = ({}) => { ); }; + +export const GrayCalendarIcon: React.FC = ({}) => { + return ( + + + + + + + + + + + + + ); +}; diff --git a/src/components/common/like/Like.tsx b/src/components/common/like/Like.tsx index 159bf56d..8ab6504c 100644 --- a/src/components/common/like/Like.tsx +++ b/src/components/common/like/Like.tsx @@ -75,9 +75,9 @@ const Like = ({ liked, id }: LikeProps) => { title={'로그인'} message={ <> - 관심 목록 등록시 로그인이 필요합니다. + 관심 여행지를 추가하려면 로그인이 필요해요.
- 로그인 하시겠습니까? + 로그인하러 가볼까요? } onConfirm={handleConfirm} diff --git a/src/components/common/modal/Modal.tsx b/src/components/common/modal/Modal.tsx index 8296f7bc..340f72e7 100644 --- a/src/components/common/modal/Modal.tsx +++ b/src/components/common/modal/Modal.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ReactNode } from 'react'; import Modal from 'react-modal'; import { modalChildrenState } from '@recoil/modal'; import { useRecoilValue } from 'recoil'; @@ -6,7 +6,7 @@ import { useRecoilValue } from 'recoil'; interface ModalProps { isOpen: boolean; closeModal: () => void; - children: any; + children: ReactNode; } const ModalComponent: React.FC = ({ diff --git a/src/components/common/nav/InputComment.tsx b/src/components/common/nav/InputComment.tsx index 3e3bb64d..ebaad8f5 100644 --- a/src/components/common/nav/InputComment.tsx +++ b/src/components/common/nav/InputComment.tsx @@ -106,12 +106,11 @@ export const InputComment: React.FC = () => { }; return ( -
-
+
+
{ navigate('/'); window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }); }} - className="cursor-pointer flex-col items-center justify-center px-2"> + className="w-[53.12px] cursor-pointer flex-col items-center justify-center px-2">
-

+

+ 홈 +

{isLoggedIn ? (
navigate('/mytrip')} - className="cursor-pointer flex-col items-center justify-center px-2"> + className="cursor-pointe w-[53.12px] flex-col items-center justify-center px-2">
{isActive('/mytrip') ? ( ) : ( - + )}
-

여정

+

+ 여정 +

) : ( - 나의 여정 조회를 위해 로그인이 필요합니다. + 여정을 관리하려면 로그인이 필요해요.
- 로그인 하시겠습니까? + 로그인하러 가볼까요? } onConfirm={handleConfirm}> -
+
-
-

+

여정

@@ -89,14 +93,14 @@ const Nav = () => { {isLoggedIn ? (
navigate('/wishlist')} - className="cursor-pointer flex-col items-center justify-center px-2"> + className="w-[53.12px] cursor-pointer flex-col items-center justify-center px-2">
-

+

관심목록

@@ -105,20 +109,20 @@ const Nav = () => { title={'로그인'} message={ <> - 관심 목록 조회를 위해 로그인이 필요합니다. + 관심 여행지를 관리하려면 로그인이 필요해요.
- 로그인 하시겠습니까? + 로그인하러 가볼까요? } onConfirm={handleConfirm}> -
+
-

+

관심목록

@@ -127,14 +131,16 @@ const Nav = () => {
navigate('/mypage')} - className="cursor-pointer flex-col items-center justify-center px-1"> + className="w-[53.12px] cursor-pointer flex-col items-center justify-center px-1 pt-[1px]">
-

내정보

+

+ 내정보 +

diff --git a/src/components/common/noData/NoDataMessage.tsx b/src/components/common/noData/NoDataMessage.tsx index 6e15c2d2..cab01453 100644 --- a/src/components/common/noData/NoDataMessage.tsx +++ b/src/components/common/noData/NoDataMessage.tsx @@ -15,13 +15,9 @@ const NoDataMessage: React.FC = ({
{icon}
-
- {message1} -
+
{message1}
-
- {message2} -
+
{message2}
diff --git a/src/components/common/scrollTopButton/ScrollTopButton.tsx b/src/components/common/scrollTopButton/ScrollTopButton.tsx new file mode 100644 index 00000000..2eb1bcbc --- /dev/null +++ b/src/components/common/scrollTopButton/ScrollTopButton.tsx @@ -0,0 +1,41 @@ +import { TopIcon } from '@components/common/icons/Icons'; +import { useEffect, useState } from 'react'; + +const ScrollTopButton = () => { + const [visible, setVisible] = useState(false); + + const checkScrollTop = () => { + if (!visible && window.scrollY > 300) { + setVisible(true); + } else if (visible && window.scrollY <= 300) { + setVisible(false); + } + }; + + useEffect(() => { + window.addEventListener('scroll', checkScrollTop); + return () => { + window.removeEventListener('scroll', checkScrollTop); + }; + }, [visible]); + + const scrollToTop = () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + if (!visible) { + return null; + } + + return ( + + ); +}; + +export default ScrollTopButton; diff --git a/src/components/common/tab/Tab.tsx b/src/components/common/tab/Tab.tsx index c75d14f2..7d012b00 100644 --- a/src/components/common/tab/Tab.tsx +++ b/src/components/common/tab/Tab.tsx @@ -29,14 +29,16 @@ const Tab = ({ lists, contents }: TabProps) => { defaultValue="tab0" onValueChange={handleTabChange}> {lists.map((list, index) => { return ( {list} diff --git a/src/components/common/toastpopup/ToastPopUp.tsx b/src/components/common/toastpopup/ToastPopUp.tsx index 4dbf53ca..75c28bb0 100644 --- a/src/components/common/toastpopup/ToastPopUp.tsx +++ b/src/components/common/toastpopup/ToastPopUp.tsx @@ -22,8 +22,10 @@ const ToastPopUp: React.FC = ({ noun, verb }) => { }, []); useEffect(() => { - if (noun === '일정' || noun === '날짜 이동' || noun === '여행 일정') { + if (noun === '일정' || noun === '날짜 이동') { setParticle('이'); + } else if (noun === '나의 여정') { + setParticle('에서'); } }, [noun]); @@ -51,7 +53,7 @@ const ToastPopUp: React.FC = ({ noun, verb }) => {

{noun} - {particle} {verb}되었습니다. + {particle} {verb}되었어요.

); diff --git a/src/components/common/toggleGroup/ToggleValue.tsx b/src/components/common/toggleGroup/ToggleValue.tsx index fffff6dc..57764632 100644 --- a/src/components/common/toggleGroup/ToggleValue.tsx +++ b/src/components/common/toggleGroup/ToggleValue.tsx @@ -16,7 +16,7 @@ export const ToggleValue = ({ {values.map((value) => ( onToggle(value)}> diff --git a/src/components/search/RegionSelect.tsx b/src/components/search/RegionSelect.tsx index f0383b42..2a5c69ec 100644 --- a/src/components/search/RegionSelect.tsx +++ b/src/components/search/RegionSelect.tsx @@ -9,15 +9,16 @@ export const RegionSelect = ({}) => { const [selectedRegion, setSelectedRegion] = useState(''); // 지역값 쿼리스트링으로 저장 - const onRegionSelect = (value: string) => { + const onRegionSelect = (key: string) => { const queryParams = new URLSearchParams(location.search); + const value = AREA_CODE[key as keyof typeof AREA_CODE]; - if (value === selectedRegion) { + if (key === selectedRegion) { queryParams.delete('region'); setSelectedRegion(''); } else { queryParams.set('region', value); - setSelectedRegion(value); + setSelectedRegion(key); } navigate( @@ -30,6 +31,6 @@ export const RegionSelect = ({}) => { }; return ( - + ); }; diff --git a/src/components/search/ResultCategory.tsx b/src/components/search/ResultCategory.tsx index e6447af1..3f321437 100644 --- a/src/components/search/ResultCategory.tsx +++ b/src/components/search/ResultCategory.tsx @@ -1,5 +1,4 @@ import { ButtonWhite } from '@components/common/button/Button'; -import { TourType } from '@/@types/tours.types'; import { InfiniteQueryObserverResult } from '@tanstack/react-query'; import { ResultItem } from './ResultItem'; diff --git a/src/components/search/ResultItem.tsx b/src/components/search/ResultItem.tsx index 47c86ecc..f27ead28 100644 --- a/src/components/search/ResultItem.tsx +++ b/src/components/search/ResultItem.tsx @@ -1,4 +1,3 @@ -import { TourType } from '@/@types/tours.types'; import { useNavigate } from 'react-router-dom'; export const ResultItem = ({ result }: { result: TourType }) => { @@ -9,7 +8,7 @@ export const ResultItem = ({ result }: { result: TourType }) => { }; return (
{ />
-
{result.title}
+
{result.title}
{result.tourAddress} diff --git a/src/components/search/SearchInput.tsx b/src/components/search/SearchInput.tsx index c3dbbabf..0adedc1c 100644 --- a/src/components/search/SearchInput.tsx +++ b/src/components/search/SearchInput.tsx @@ -52,24 +52,26 @@ const SearchInput = () => {
-
- -
- - {inputValue && ( -
- +
+
+
- )} + + {inputValue && ( +
+ +
+ )} +
); diff --git a/src/components/search/SearchResult.tsx b/src/components/search/SearchResult.tsx index 74fbb61f..c420e2b5 100644 --- a/src/components/search/SearchResult.tsx +++ b/src/components/search/SearchResult.tsx @@ -4,6 +4,7 @@ import { useInfiniteQuery } from '@tanstack/react-query'; import ToursCategoryItem from '@components/Tours/ToursCategoryItem'; import { useEffect, useState } from 'react'; import { Spinner } from '@components/common/spinner/Spinner'; +import ScrollTopButton from '@components/common/scrollTopButton/ScrollTopButton'; interface SearchResultProps { selectedRegion: string | null; @@ -97,6 +98,8 @@ export const SearchResult = ({ isFetchingNextPage={isFetchingNextPage} /> )} + +
); }; diff --git a/src/components/search/StartSearchBtn.tsx b/src/components/search/StartSearchBtn.tsx index a5b9b3ef..000b3d30 100644 --- a/src/components/search/StartSearchBtn.tsx +++ b/src/components/search/StartSearchBtn.tsx @@ -1,5 +1,5 @@ import { useNavigate } from 'react-router-dom'; -import { ReactComponent as SearchIcon } from '@assets/images/Search.svg'; +import { SearchIcon } from '@components/common/icons/Icons'; export const StartSearchButton = () => { const navigate = useNavigate(); @@ -10,10 +10,10 @@ export const StartSearchButton = () => { return ( ); }; diff --git a/src/constants.ts b/src/constants.ts index 37e408d4..c50f848b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,14 +6,14 @@ export const AREA_CODE = { 광주: '광주', 대전: '대전', 울산: '울산', - 세종: '세종', + 세종: '세종특별자치시', 제주: '제주', - 경기: '경기', - 강원: '강원', - 충북: '충북', - 충남: '충남', - 경북: '경북', - 경남: '경남', - 전북: '전북', - 전남: '전남', + 경기: '경기도', + 강원: '강원도', + 충북: '충청북도', + 충남: '충청남도', + 경북: '경상북도', + 경남: '경상남도', + 전북: '전라북도', + 전남: '전라남도', }; diff --git a/src/hooks/useGetMyTrips.ts b/src/hooks/useGetMyTrips.ts index 754188ed..78670740 100644 --- a/src/hooks/useGetMyTrips.ts +++ b/src/hooks/useGetMyTrips.ts @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query'; import { getMyTrips } from '@api/trips'; interface Trip { - tripId: number; + tripId: string; tripName: string; startDate: string; endDate: string; @@ -15,7 +15,6 @@ export const useGetMyTrips = (): { myTrips: Trip[] } => { const { data, isLoading, isError } = useQuery({ queryKey: ['getMyTrips'], queryFn: () => getMyTrips(), - staleTime: 60000, }); const myTrips = data?.data.data; diff --git a/src/hooks/useReviewStats.ts b/src/hooks/useReviewStats.ts index 001b1a54..2c4a37fd 100644 --- a/src/hooks/useReviewStats.ts +++ b/src/hooks/useReviewStats.ts @@ -1,6 +1,5 @@ import { useQuery } from '@tanstack/react-query'; import { getToursReviews } from '@api/tours'; -import { TourKeywordInfo } from '@/@types/tours.types'; import { useParams } from 'react-router-dom'; type UseGetToursReviewsReturn = { diff --git a/src/hooks/useReviewStatsCalculator.ts b/src/hooks/useReviewStatsCalculator.ts index 88be9c15..89573b0c 100644 --- a/src/hooks/useReviewStatsCalculator.ts +++ b/src/hooks/useReviewStatsCalculator.ts @@ -1,5 +1,4 @@ import { useMemo } from 'react'; -import { TourKeywordInfo } from '@/@types/tours.types'; const getMaxMinCounts = (reviewStats: TourKeywordInfo[]) => { const counts = reviewStats.map((item) => item.keywordCount); diff --git a/src/hooks/useSocket.ts b/src/hooks/useSocket.ts index eb9b0520..3de7e43f 100644 --- a/src/hooks/useSocket.ts +++ b/src/hooks/useSocket.ts @@ -5,6 +5,7 @@ import { subPath, subMember, subBudget, + subCursor, } from '@api/socket'; import { subInfoRes, @@ -12,6 +13,7 @@ import { subPathRes, subMemberRes, subBudgetRes, + subCursorRes, SocketContextType, } from '@/@types/service'; import { createContext } from 'react'; @@ -26,6 +28,7 @@ export const socketContext = createContext({ tripPath: null, tripMember: null, tripBudget: null, + tripCursor: null, tripId: '', callBackPub: () => {}, }); @@ -40,6 +43,8 @@ export const useSocket = () => { const [tripPath, setTripPath] = useState(null); const [tripMember, setTripMember] = useState(null); const [tripBudget, setTripBudget] = useState(null); + const [tripCursor, setTripCursor] = useState(null); + const [socketCallback, setSocketCallback] = useState<(() => void) | null>( null, ); @@ -80,6 +85,12 @@ export const useSocket = () => { } }); + subCursor(tripId, visitDate, (res) => { + if (res) { + setTripCursor(res); + } + }); + if (socketCallback) { socketCallback(); } @@ -92,11 +103,9 @@ export const useSocket = () => { if (tripId && visitDate) { socketConnect(tripId, visitDate.visitDate); } - console.log('소켓연결'); return () => { socketClient.deactivate(); - console.log('소켓해제'); }; }, [tripId, visitDate, socketCallback]); @@ -106,6 +115,7 @@ export const useSocket = () => { tripPath, tripMember, tripBudget, + tripCursor, tripId, callBackPub, }; diff --git a/src/main.tsx b/src/main.tsx index 3de05f65..0fe89954 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -2,9 +2,4 @@ import ReactDOM from 'react-dom/client'; import App from './App.tsx'; import './index.css'; -// if (import.meta.env.DEV) { -// const { worker } = await import('./mocks/browser.ts'); -// await worker.stop(); -// } - ReactDOM.createRoot(document.getElementById('root')!).render(); diff --git a/src/mocks/browser.ts b/src/mocks/browser.ts deleted file mode 100644 index df8e9011..00000000 --- a/src/mocks/browser.ts +++ /dev/null @@ -1,4 +0,0 @@ -// import { setupWorker } from 'msw'; -// // import { handlers } from './handlers'; - -// export const worker = setupWorker(...handlers); diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts deleted file mode 100644 index 05fe7d83..00000000 --- a/src/mocks/handlers.ts +++ /dev/null @@ -1,944 +0,0 @@ -// import { rest } from 'msw'; - -// const SERVER_URL = import.meta.env.VITE_SERVER_URL; - -// export const handlers = [ -// // 댓글 관련 API -// // 댓글 수정 -// rest.put(`${SERVER_URL}/comments/:commentId`, (req, res, ctx) => { -// const { commentId } = req.params; -// const commentData = req.body; -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// commentId: commentId, -// authorNickname: '은별', -// authorProfileImageUrl: 'https://~~~.png', -// content: commentData, -// createdTime: '2023-12-28T15:12:40.231Z', -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 댓글 삭제 -// rest.delete(`${SERVER_URL}/comments/:commentId`, (req, res, ctx) => { -// const { commentId } = req.params; -// const responseData = { -// status: 0, -// message: `댓글 삭제 성공, commentId: ${commentId}`, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 댓글 작성 -// rest.post(`${SERVER_URL}/comments`, (req, res, ctx) => { -// const { commentId } = req.params; -// const commentData = req.body; -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// commentId: commentId, -// authorNickname: '은별', -// authorProfileImageUrl: 'https://~~~.png', -// content: commentData, -// createdTime: '2023-12-28T15:15:48.041Z', -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 리뷰 관련 API -// // 리뷰 수정 -// rest.put(`${SERVER_URL}/reviews/:reviewId`, (req, res, ctx) => { -// const { reviewId } = req.params; -// const reviewData = req.body as ReviewRequest; -// const responseData = reviewData; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 리뷰 삭제 -// rest.delete(`${SERVER_URL}/reviews/:reviewId`, (req, res, ctx) => { -// const { reviewId } = req.params; -// return res( -// ctx.status(200), -// ctx.json({ message: `리뷰 ${reviewId} 삭제 성공` }), -// ); -// }), -// // 리뷰 작성 -// rest.post(`${SERVER_URL}/reviews`, (req, res, ctx) => { -// const { reviewId } = req.params; -// const reviewData = req.body as ReviewRequest; -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// reviewId: reviewId, -// authorNickname: '은별', -// authorProfileImageUrl: 'https://~~~.png', -// rating: 4, -// createdTime: '2023-12-28T16:24:09.639Z', -// content: '~~~여서 ~~~ 해서 ~~로 좋았습니다.', -// keywords: [ -// { -// keywordId: 1, -// content: '깨끗해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// ], -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 리뷰 댓글 조회 -// rest.get(`${SERVER_URL}/reviews/:reviewId/comments`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// comments: [ -// { -// commentId: 1, -// authorNickname: '은별', -// authorProfileImageUrl: 'https://~~~.png', -// content: '잘보고 갑니다~', -// createdTime: '2023-12-28T16:29:34.105Z', -// }, -// ], -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 리뷰 키워드 조회 -// rest.get(`${SERVER_URL}/reviews/keywords`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// keywords: [ -// { -// keywordId: 1, -// content: '깨끗해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// ], -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 여정 관련 API -// // 나의 여정 목록 조회 -// rest.get(`${SERVER_URL}/trips`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// trips: [ -// { -// tripId: 1, -// tripName: '나의 ~번째 여정', -// startDate: '2023-12-28', -// endDate: '2023-12-28', -// numberOfTripMembers: 2, -// tripStatus: '여행 전', -// tripThumbnailUrl: 'https://~~~~.png', -// }, -// ], -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 여정 생성 -// rest.post(`${SERVER_URL}/trips`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// tripId: 1, -// tripName: '나의 ~번째 여정', -// startDate: '2023-12-28', -// endDate: '2023-12-28', -// numberOfTripMembers: 2, -// tripStatus: '여행 전', -// tripThumbnailUrl: 'https://~~~~.png', -// }, -// }; -// return res(ctx.status(201), ctx.json(responseData)); -// }), -// // 여정 탈퇴 -// rest.delete(`${SERVER_URL}/trips/:tripId`, (req, res, ctx) => { -// const { tripId } = req.params; -// return res( -// ctx.status(200), -// ctx.json({ message: `여행 ${tripId} 탈퇴 성공` }), -// ); -// }), -// // 여행지 관련 API -// // 인기 여행지 조회 -// rest.get(`${SERVER_URL}/tours`, (req, res, ctx) => { -// const { page, size } = req.params; -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// totalPages: 0, -// totalElements: 0, -// pageable: { -// pageNumber: page, -// pageSize: size, -// offset: 0, -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// paged: true, -// unpaged: true, -// }, -// size: size, // 확인필요 -// content: [ -// { -// id: 1, -// title: '여행지 이름', -// ratingAverage: 4.5, -// reviewCount: 100, -// likedCount: 100, -// liked: false, -// smallThumbnailUrl: 'http://~~~~~~image.jpg', -// }, -// ], -// number: page, // 확인필요 -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// numberOfElements: 0, -// first: true, -// last: true, -// empty: true, -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 여행지 상세 조회 -// rest.get(`${SERVER_URL}/tours/:tourItemId`, (req, res, ctx) => { -// const { tourId } = req.params; -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// id: tourId, -// title: '여행지 이름', -// liked: false, -// fullAddress: 'OO시/도 OO구/군 OO로/길 OOO', -// zipcode: '00000', -// longitude: '127.04', -// latitude: '33.56', -// tel: '010-0000-0000', -// originalThumbnailUrl: 'http://~~~~~~image.jpg', -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 여행지 검색 -// rest.get(`${SERVER_URL}/tours/search`, (req, res, ctx) => { -// const { page, size } = req.params; -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// totalPages: 0, -// totalElements: 0, -// pageable: { -// pageNumber: page, -// pageSize: size, -// offset: 0, -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// paged: true, -// unpaged: true, -// }, -// size: size, // 확인필요 -// content: [ -// { -// id: 1, -// title: '여행지 이름', -// ratingAverage: 4.5, -// reviewCount: 100, -// likedCount: 100, -// liked: false, -// smallThumbnailUrl: 'http://~~~~~~image.jpg', -// }, -// ], -// number: page, // 확인필요 -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// numberOfElements: 0, -// first: true, -// last: true, -// empty: true, -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 유저 관련 API -// // 회원 정보 조회 -// rest.get(`${SERVER_URL}/member`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// memberId: 1, -// nickname: '닉네임', -// email: 'example@mail.com', -// profileImageUrl: '프로필 이미지', -// ageType: '연령대', -// genderType: '성별', -// survey: '설문조사 결과', -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 회원 정보 수정 -// rest.put(`${SERVER_URL}/member`, (req, res, ctx) => { -// const memberData = req.body as MemberRequest; -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// memberId: 1, -// nickname: memberData.nickname, -// email: 'example@mail.com', -// profileImageUrl: memberData.profileImageUrl, -// ageType: '연령대', -// genderType: '성별', -// survey: memberData.survey, -// }, -// }; -// return res( -// ctx.status(200), -// ctx.json({ -// message: `회원 정보 수정 성공, 비밀번호:${memberData.password}`, -// responseData, -// }), -// ); -// }), -// // 회원 탈퇴 -// rest.delete(`${SERVER_URL}/member`, (req, res, ctx) => { -// return res(ctx.status(200), ctx.json({ message: '회원 탈퇴 성공' })); -// }), -// // 나의 여정 조회 -// rest.get(`${SERVER_URL}/member/trips`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// totalPages: 0, -// totalElements: 0, -// pageable: { -// pageNumber: 0, -// pageSize: 0, -// offset: 0, -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// paged: true, -// unpaged: true, -// }, -// size: 0, -// content: [ -// { -// tripId: 1, -// tripName: '나의 ~번째 여정', -// startDate: '2023-12-28', -// endDate: '2023-12-28', -// numberOfTripMembers: 2, -// tripStatus: '여행 전', -// tripThumbnailUrl: 'https://~~~~.png', -// }, -// ], -// number: 0, -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// numberOfElements: 0, -// first: true, -// last: true, -// empty: true, -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 나의 관심 여행지 조회 -// rest.get(`${SERVER_URL}/member/tours`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// totalPages: 0, -// totalElements: 0, -// pageable: { -// pageNumber: 0, -// pageSize: 0, -// offset: 0, -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// paged: true, -// unpaged: true, -// }, -// size: 0, -// content: [ -// { -// id: 1, -// title: '여행지 이름', -// ratingAverage: 4.5, -// reviewCount: 100, -// likedCount: 100, -// liked: false, -// smallThumbnailUrl: 'http://~~~~~~image.jpg', -// }, -// ], -// number: 0, -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// numberOfElements: 0, -// first: true, -// last: true, -// empty: true, -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 나의 리뷰 조회 -// rest.get(`${SERVER_URL}/member/reviews`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// totalPages: 0, -// totalElements: 0, -// pageable: { -// pageNumber: 0, -// pageSize: 0, -// offset: 0, -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// paged: true, -// unpaged: true, -// }, -// size: 0, -// content: [ -// { -// reviewId: 1, -// authorNickname: '은별', -// authorProfileImageUrl: 'https://~~~.png', -// rating: 4, -// createdTime: '2023-12-28T16:15:43.756Z', -// content: '~~~여서 ~~~ 해서 ~~로 좋았습니다.', -// keywords: [ -// { -// keywordId: 1, -// content: '깨끗해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// ], -// }, -// ], -// number: 0, -// sort: { -// sorted: true, -// empty: true, -// unsorted: true, -// }, -// numberOfElements: 0, -// first: true, -// last: true, -// empty: true, -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 나의 관심 여행지 삭제 -// rest.delete(`${SERVER_URL}/member/tours/:tourId`, (req, res, ctx) => { -// const { tourId } = req.params; -// return res( -// ctx.status(200), -// ctx.json({ message: `관심 여행지 ${tourId} 삭제 성공` }), -// ); -// }), -// // 인증 관련 API -// // 회원가입 -// rest.post(`${SERVER_URL}/auth/signup`, (req, res, ctx) => { -// const authData = req.body as AuthRequest; -// return res( -// ctx.status(200), -// ctx.json({ message: '회원가입 성공', authData }), -// ); -// }), -// // 로그아웃 -// rest.post(`${SERVER_URL}/auth/logout`, (req, res, ctx) => { -// return res(ctx.status(200), ctx.json({ message: '로그아웃 성공' })); -// }), -// // 이메일 로그인 -// rest.post(`${SERVER_URL}/auth/login`, (req, res, ctx) => { -// const loginData = req.body; -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// token: 'jwtToken', -// }, -// }; -// return res( -// ctx.status(200), -// ctx.json({ message: '로그인 성공', loginData, responseData }), -// ); -// }), -// // 카카오 로그인 -// rest.post(`${SERVER_URL}/auth/login/kakao`, (req, res, ctx) => { -// const loginData = req.body; -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// token: 'jwtToken', -// }, -// }; -// return res( -// ctx.status(200), -// ctx.json({ message: '카카오 로그인 성공', loginData, responseData }), -// ); -// }), -// // 닉네임 중복조회 -// rest.get(`${SERVER_URL}/auth/nicknames/check/:nickname`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// exists: true, -// }, -// }; -// return res( -// ctx.status(200), -// ctx.json({ message: '닉네임 중복조회 완료', responseData }), -// ); -// }), -// // 이메일 중복조회 -// rest.get(`${SERVER_URL}/auth/emails/check/:email`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// exists: true, -// }, -// }; -// return res( -// ctx.status(200), -// ctx.json({ message: '이메일 중복조회 완료', responseData }), -// ); -// }), -// // 지역 관련 API -// // 전체 지역 조회 -// rest.get(`${SERVER_URL}/region`, (req, res, ctx) => { -// const areaCode = req.url.searchParams.get('areaCode'); -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// regions: [ -// { -// areaCode: areaCode, // 확인필요 -// subAreaCode: 0, -// name: '서울시', -// }, -// ], -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 인기 지역 조회 -// rest.get(`${SERVER_URL}/region/popular`, (req, res, ctx) => { -// const responseData = { -// status: 0, -// message: 'string', -// data: { -// regions: [ -// { -// areaCode: 1, -// subAreaCode: 0, -// name: '서울시', -// }, -// ], -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 카테고리 관련 API -// // 카테고리 조회 -// rest.get(`${SERVER_URL}/category`, (req, res, ctx) => { -// // 모의 카테고리 데이터 -// const responseData = { -// status: 0, -// message: 'string', -// data: [ -// { -// code: 39, -// name: '식당', -// }, -// ], -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// // 여행 상품 리뷰 조회 -// rest.get(`${SERVER_URL}/tours/:tourItemId/reviews`, (req, res, ctx) => { -// const responseData = { -// status: 200, -// message: 'SUCCESS', -// data: { -// ratingAverage: 4.125, -// reviewTotalCount: 8, -// keywordTotalCount: 38, -// reviewInfos: { -// content: [ -// { -// reviewId: 15, -// authorNickname: '익명 사용자1', -// authorProfileImageUrl: -// 'https://common.hanmi.co.kr/upfile/ces/product/p_2011_tenten_p_400.jpg', -// rating: 4, -// createdTime: '2023-12-30T20:02:06.03406', -// content: '좋은 여행지였습니다.', -// keywords: [ -// { -// keywordId: 1, -// content: '깨끗해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// { -// keywordId: 2, -// content: '친절해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// ], -// commentCount: 0, -// }, -// { -// reviewId: 23, -// authorNickname: '익명 사용자1', -// authorProfileImageUrl: -// 'https://common.hanmi.co.kr/upfile/ces/product/p_2011_tenten_p_400.jpg', -// rating: 4, -// createdTime: '2023-12-30T20:03:17.978397', -// content: '좋은 여행지였습니다.', -// keywords: [ -// { -// keywordId: 1, -// content: '깨끗해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// { -// keywordId: 2, -// content: '친절해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// ], -// commentCount: 0, -// }, -// { -// reviewId: 24, -// authorNickname: '익명 사용자1', -// authorProfileImageUrl: -// 'https://common.hanmi.co.kr/upfile/ces/product/p_2011_tenten_p_400.jpg', -// rating: 4, -// createdTime: '2023-12-30T20:03:18.970952', -// content: '좋은 여행지였습니다.', -// keywords: [ -// { -// keywordId: 1, -// content: '깨끗해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// { -// keywordId: 2, -// content: '친절해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// ], -// commentCount: 0, -// }, -// { -// reviewId: 25, -// authorNickname: '익명 사용자1', -// authorProfileImageUrl: -// 'https://common.hanmi.co.kr/upfile/ces/product/p_2011_tenten_p_400.jpg', -// rating: 4, -// createdTime: '2023-12-30T20:03:20.335173', -// content: '좋은 여행지였습니다.', -// keywords: [ -// { -// keywordId: 1, -// content: '깨끗해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// { -// keywordId: 2, -// content: '친절해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// ], -// commentCount: 0, -// }, -// { -// reviewId: 26, -// authorNickname: '익명 사용자1', -// authorProfileImageUrl: -// 'https://common.hanmi.co.kr/upfile/ces/product/p_2011_tenten_p_400.jpg', -// rating: 4, -// createdTime: '2023-12-30T20:03:21.924918', -// content: '좋은 여행지였습니다.', -// keywords: [ -// { -// keywordId: 1, -// content: '깨끗해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// { -// keywordId: 2, -// content: '친절해요', -// type: 'ACCOMMODATION_KEYWORD', -// }, -// ], -// commentCount: 0, -// }, -// ], -// pageable: { -// pageNumber: 0, -// pageSize: 20, -// sort: { -// sorted: false, -// empty: true, -// unsorted: true, -// }, -// offset: 0, -// paged: true, -// unpaged: false, -// }, -// last: true, -// totalElements: 5, -// totalPages: 1, -// size: 20, -// number: 0, -// sort: { -// sorted: false, -// empty: true, -// unsorted: true, -// }, -// first: true, -// numberOfElements: 5, -// empty: false, -// }, -// tourKeywordInfos: [ -// { -// keywordId: 1, -// content: '깨끗해요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 30, -// }, -// { -// keywordId: 2, -// content: '친절해요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 29, -// }, -// { -// keywordId: 3, -// content: '뷰가 좋아요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 28, -// }, -// { -// keywordId: 4, -// content: '침구가 좋아요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 27, -// }, -// { -// keywordId: 5, -// content: '주차하기 편해요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 26, -// }, -// { -// keywordId: 6, -// content: '냉난방이 잘돼요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 25, -// }, -// { -// keywordId: 7, -// content: '대중교통이 편해요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 24, -// }, -// { -// keywordId: 8, -// content: '호캉스하기 좋아요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 23, -// }, -// { -// keywordId: 9, -// content: '조식이 맛있어요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 22, -// }, -// { -// keywordId: 10, -// content: '사진 찍기 좋아요', -// type: 'ACCOMMODATION_KEYWORD', -// keywordCount: 21, -// }, -// { -// keywordId: 11, -// content: '음식이 맛있어요', -// type: 'DINING_KEYWORD', -// keywordCount: 20, -// }, -// { -// keywordId: 12, -// content: '친절해요', -// type: 'DINING_KEYWORD', -// keywordCount: 19, -// }, -// { -// keywordId: 13, -// content: '인테리어가 멋져요', -// type: 'DINING_KEYWORD', -// keywordCount: 18, -// }, -// { -// keywordId: 14, -// content: '매장이 청결해요', -// type: 'DINING_KEYWORD', -// keywordCount: 17, -// }, -// { -// keywordId: 15, -// content: '특별한 메뉴가 있어요', -// type: 'DINING_KEYWORD', -// keywordCount: 16, -// }, -// { -// keywordId: 16, -// content: '가성비가 좋아요', -// type: 'DINING_KEYWORD', -// keywordCount: 15, -// }, -// { -// keywordId: 17, -// content: '재료가 신선해요', -// type: 'DINING_KEYWORD', -// keywordCount: 14, -// }, -// { -// keywordId: 18, -// content: '사진찍기 좋아요', -// type: 'DINING_KEYWORD', -// keywordCount: 13, -// }, -// { -// keywordId: 19, -// content: '주차하기 편해요', -// type: 'DINING_KEYWORD', -// keywordCount: 12, -// }, -// { -// keywordId: 20, -// content: '화장실이 깨끗해요', -// type: 'DINING_KEYWORD', -// keywordCount: 11, -// }, -// { -// keywordId: 21, -// content: '사진이 잘 나와요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 10, -// }, -// { -// keywordId: 22, -// content: '뷰가 좋아요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 9, -// }, -// { -// keywordId: 23, -// content: '관리가 잘 되어있어요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 8, -// }, -// { -// keywordId: 24, -// content: '볼거리가 많아요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 7, -// }, -// { -// keywordId: 25, -// content: '편의시설이 잘 되어 있어요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 6, -// }, -// { -// keywordId: 26, -// content: '대중교통이 편해요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 5, -// }, -// { -// keywordId: 27, -// content: '주차하기 편해요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 4, -// }, -// { -// keywordId: 28, -// content: '화장실이 깨끗해요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 3, -// }, -// { -// keywordId: 29, -// content: '가격이 합리적이에요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 2, -// }, -// { -// keywordId: 30, -// content: '방문객이 많아요', -// type: 'ATTRACTION_KEYWORD', -// keywordCount: 1, -// }, -// ], -// }, -// }; -// return res(ctx.status(200), ctx.json(responseData)); -// }), -// ]; diff --git a/src/pages/create/createTrip.page.tsx b/src/pages/create/createTrip.page.tsx index acaf0422..ce7c23fc 100644 --- a/src/pages/create/createTrip.page.tsx +++ b/src/pages/create/createTrip.page.tsx @@ -88,7 +88,7 @@ export const CreateTrip = () => { ); } return ( -
+
여행 생성하기
@@ -102,7 +102,6 @@ export const CreateTrip = () => { onChange={(e) => { setTitle(e.target.value); }} - autoFocus /> {title && (
{ 나의 여행 취향 설정
- +
); diff --git a/src/pages/signup/signupSuccess.page.tsx b/src/pages/signup/signupSuccess.page.tsx index c7adcb3e..82eeb663 100644 --- a/src/pages/signup/signupSuccess.page.tsx +++ b/src/pages/signup/signupSuccess.page.tsx @@ -11,14 +11,14 @@ const SignupSuccess = () => {

- 환영합니다! + 만나서 반가워요!
- 가입이 완료되었습니다. + 가입이 완료되었어요.

- 위플랜플랜스 회원이 되신 것을 환영합니다. + 위플랜플랜스에서 여행 계획을 세워볼까요?
- 여행 취향과 프로필을 등록해주세요! + 여행 취향과 프로필을 등록하면 도움이 될 거예요.
diff --git a/src/pages/trip/AddOurList.page.tsx b/src/pages/trip/AddOurList.page.tsx index 14eaf416..fe8c8729 100644 --- a/src/pages/trip/AddOurList.page.tsx +++ b/src/pages/trip/AddOurList.page.tsx @@ -1,6 +1,6 @@ import SearchInput from '@components/search/SearchInput'; -import { MyLiked } from '@pages/plan/addToOurPlace/MyLiked'; -import { SearchResultForPlan } from '@pages/plan/addToOurPlace/SearchResult'; +import { MyLiked } from '@components/addToList/addToOurPlace/MyLiked'; +import { SearchResultForPlan } from '@components/addToList/addToOurPlace/SearchResult'; import { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; diff --git a/src/pages/trip/tripEdit.page.tsx b/src/pages/trip/tripEdit.page.tsx index 50d6bc51..d9750bf9 100644 --- a/src/pages/trip/tripEdit.page.tsx +++ b/src/pages/trip/tripEdit.page.tsx @@ -106,7 +106,7 @@ const TripEdit = () => { ); } return ( -
+
{ @@ -119,7 +119,7 @@ const TripEdit = () => { { @@ -166,7 +166,7 @@ const TripEdit = () => {
{formattedTripDate}
-
+
완료
diff --git a/src/recoil/review.ts b/src/recoil/review.ts index 1c9753e1..0aaac458 100644 --- a/src/recoil/review.ts +++ b/src/recoil/review.ts @@ -1,17 +1,5 @@ import { atom } from 'recoil'; -interface ReviewRequest { - tourItemId: number; - rating: number; - keywords: Keyword[]; - content: string; -} - -type Keyword = { - keywordId: number; - content: string; -}; - export const ratingState = atom({ key: 'ratingState', default: 0, diff --git a/src/recoil/trip.ts b/src/recoil/trip.ts index 9df993e0..b2b7e656 100644 --- a/src/recoil/trip.ts +++ b/src/recoil/trip.ts @@ -1,17 +1,5 @@ import { atom } from 'recoil'; -type Participant = { - memberId: number; - nickname: string; - thumbnail: string; -}; - -export type Participants = { - tripSurveyMemberCount: number; - tripSurveySetMemberInfos: Participant[]; - nonTripSurveySetMemberInfos: Participant[]; -}; - export const participantsState = atom({ key: 'participantsState', default: { diff --git a/src/router/mainRouter.tsx b/src/router/mainRouter.tsx index 1cbe518c..dd309613 100644 --- a/src/router/mainRouter.tsx +++ b/src/router/mainRouter.tsx @@ -15,12 +15,10 @@ import { EditUserSurvey, Mypage, } from '@pages/mypage'; -import useGetUserInfo from '@hooks/useGetUserInfo'; import MainLayout from './routerLayout'; import { CreateTrip } from '@pages/create/createTrip.page'; const MainRouter = () => { - useGetUserInfo(); return ( <> diff --git a/src/router/routerLayout.tsx b/src/router/routerLayout.tsx index 93033a41..bb3f24ef 100644 --- a/src/router/routerLayout.tsx +++ b/src/router/routerLayout.tsx @@ -3,6 +3,7 @@ import { Outlet, useLocation } from 'react-router-dom'; import { Nav } from '@components/common/nav'; import { InputComment } from '@components/common/nav'; import '../index.css'; +import useGetUserInfo from '@hooks/useGetUserInfo'; const MainLayout = () => { const location = useLocation(); @@ -16,15 +17,19 @@ const MainLayout = () => { '/myPageReview', '/info', '/survey', - '/trip', + '/plan', '/create', + '/add', + '/edit', ]; const showNav = !hideNavPaths.some((path) => location.pathname.includes(path), ); + useGetUserInfo(); + return ( -
+
diff --git a/src/router/socketRouter.tsx b/src/router/socketRouter.tsx index 1f02a88f..8de2d225 100644 --- a/src/router/socketRouter.tsx +++ b/src/router/socketRouter.tsx @@ -1,7 +1,7 @@ import { Route, Routes } from 'react-router-dom'; import { useSocket, socketContext } from '@hooks/useSocket'; import PlanTrip from '@pages/plan/planTrip.page'; -import { PlanAddPlace } from '@pages/plan/addToOurPlace/PlanAddPlace.page'; +import { PlanAddPlace } from '@components/addToList/addToOurPlace/PlanAddPlace.page'; import PlanPlaceSearch from '@pages/plan/planPlaceSearch.page'; import Trip from '@pages/trip/trip.page'; import MainLayout from './routerLayout'; diff --git a/src/styles/globalStyles.ts b/src/styles/globalStyles.ts deleted file mode 100644 index e4028567..00000000 --- a/src/styles/globalStyles.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { createGlobalStyle } from 'styled-components'; - -export const GlobalStyle = createGlobalStyle` - html, body, div, span, applet, object, iframe, - h1, h2, h3, h4, h5, h6, p, blockquote, pre, - a, abbr, acronym, address, big, cite, code, - del, dfn, em, img, ins, kbd, q, s, samp, - small, strike, strong, sub, sup, tt, var, - b, u, i, center, - dl, dt, dd, ol, ul, li, - fieldset, form, label, legend, - table, caption, tbody, tfoot, thead, tr, th, td, - article, aside, canvas, details, embed, - figure, figcaption, footer, header, hgroup, - menu, nav, output, ruby, section, summary, - time, mark, audio, video, button { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; - } - - /* HTML5 display-role reset for older browsers */ - article, aside, details, figcaption, figure, - footer, header, hgroup, menu, nav, section { - display: block; - } - - body { - line-height: 1; - } - - ol, ul { - list-style: none; - } - - blockquote, q { - quotes: none; - } - - blockquote:before, blockquote:after, - q:before, q:after { - content: ''; - content: none; - } - - table { - border-collapse: collapse; - border-spacing: 0; - } - * { - box-sizing: border-box; - } - body { - font-family: 'Pretendard Variable', sans-serif; - background-color: ${({ theme }) => theme.colors.bg_page}; - color: ${({ theme }) => theme.colors.text1}; - } - a { - text-decoration: none; - color: inherit; - } -`; diff --git a/src/styles/theme.ts b/src/styles/theme.ts deleted file mode 100644 index 93fe759f..00000000 --- a/src/styles/theme.ts +++ /dev/null @@ -1,61 +0,0 @@ -export const theme = { - colors: { - navy: '#253C59', //primary navy - blue: '#58788c', //옵션에 사용하는 두번째 blue - yellow: '#D9B70D', //찜에 사용하는 yellow - gray1: '#f8f8f8', //제일 어두운 gray - gray2: '#AFAFAF', //중간 gray - gray3: '#757575', - - error: '#CF0000', - success: '#008000', - }, - fonts: { - subtitle1: { - fontSize: '2.5rem', - fontWeight: '900', - lineHeight: '1.5', - }, - subtitle2: { - fontSize: '2rem', - fontWeight: '700', - lineHeight: '1.5', - }, - subtitle3: { - fontSize: '1.75rem', - fontWeight: '600', - lineHeight: '1.5', - }, - subtitle4: { - fontSize: '1.5rem', - fontWeight: '500', - lineHeight: '1.5', - }, - subtitle4_5: { - fontSize: '1.25rem', - fontWeight: '700', - lineHeight: '1.5', - }, - subtitle5: { - fontSize: '1rem', - fontWeight: '700', - lineHeight: '1.5', - }, - body: { - fontSize: '0.875rem', - fontWeight: '700', - lineHeight: '1.6', - }, - }, - shadows: { - shadow1: { - shadow: '0px 4px 8px rgba(0, 0, 0, 0.04)', - }, - shadow2: { - shadow: '0px 8px 16px rgba(0, 0, 0, 0.16)', - }, - shadow3: { - shadow: '0px 12px 40px rgba(0, 0, 0, 0.12)', - }, - }, -};