-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* fix: stylelint를 통한 css 속성 정렬 기능 오류 수정 - stylelint 버전16과 충돌되는 플러그인 삭제 : stylelint-config-prettier, stylelint-prettier - css 정렬에 필요하지 않은 플러그인 삭제 : stylelint-config-standard, stylelint-config-styled-componented, stylelint-webpack-plugin - 추가로 설치한 플러그인: postcss-syntax, @stylelint/postcss-css-in-js - stylelint 적용 script 추가 - .stylelintrc.json 수정 : css 관련 rule 설정 * refactor: stylelint 적용에 따른 css 속성 정렬 * fix : 절대 경로 사용 시 오류 수정 오류 : eslintimport/no-unresolved * chore: eslintrc.cjs 에서 불필요한 코드 삭제 node 환경 setting 삭제 * style: eslint 적용에 따른 리뷰 상세페이지 import 순서 정리 * refactor: formatDate를 utils/date 파일로 이동 * design: theme에 colors,, fontSize 변경 및 borderRadius 추가 * feat: MultilineTextViewer 컴포넌트 생성 - 개행이 포함된 string에 개행을 적용해서 보여주는 컴포넌트 * feat: 깃허브 저장소 이미지 컴포넌트 생성 * feat: 리뷰와 관련된 날짜 UI 컴포넌트 생성 * featr: LockButton 삭제 LockToggle 추가 * refactor: 피그마 디자인 변경에 따른 ReviewDescription 변경 * feat: ReviewComment 컴포넌트 생성 * refactor: ReviewViewSection -> ReviewSection 으로 변경 및 리팩토링 - 불필요한 컴포넌트 삭제 : RevieAnswer , ReviewQuestion * refactor: DetailedReviewPage 리팩토링 - 목데이터 변경 - 추가 및 변경된 컴포넌트를 사용해 리뷰 상세페이지 컴포넌트(DetailedReviewPage) 리팩토링 - DetailedReviewPage 폴더의 styles.ts 삭제 * refactor: review에 대한 타입 변경 * design : ReviewDate의 클론 스타일 적용 * feat: KeywordSection 컴포넌트 생성 - 리뷰 상세 페이지 키워드 부분 컴포넌트 생성 * feat: ReviewSectionHeader 컴포넌트 생성 및 적용 - 리뷰 상세보기에서 반복되는 질문,키워드 헤더부분을 컴포넌트로 분리 * design : 리뷰 상세페이지에 width 변경 * refactor: DetailedReview의 목데이터 변경 및 리팩토링 - 타입 변경에 따른 목 데이터 변경 - KeywordSection 적용 * design : formWidth를 theme에 추가 및 리뷰 작성/리뷰 상세 페이지에 적용 * fix: Layout에서 가로 스크롤 생기는 오류 수정 - 100vw는 스크롤을 포함한 뷰포트 너비라서 100%으로 수정 * feat: 리뷰 상페이지 router에 라우터 파라미터 적용 및 관련 설정 변경 - 데모데이를 위해 현재 데이터베이스에 있는 리뷰 상세페이지 id를 sidebar의 리뷰 상세페이지 메뉴 link에 적용 - 리뷰 상세페이지(DetailedReviewPage)의 api 핸들러 수정 * docs: 변수명 변경 (isLock -> isPublic) * refactor: 깃헙 저장소 로고 주소 변수명 변경 - projectImgSrc -> thumbnailUrl * ci: msw 관련 패키지 설치 * ci: msw 관련 설정파일 추가 - 브라우저 환경, node 환경에서 msw로 목서버 사용할 수 있도록 관련 파일 추가 * feat: mock 핸들러 추가 및 상세 리뷰 페이지 목 데이터 추가 * feat: root에서 목서버 사용할 수 있도록함 * refactor: endpoint 수정 - env 에서 서버 주소 끝에 슬래시 넣는 것으로 통일 * feat: 상세 리뷰 페이지(detailedReviewPage)에 목서버 연결 및 관련 코드 수정 - 상태명 변경: detailReview -> detailedReview - detailedReview 타입에 null 추가 및 그에 따른 오류 핸들링 추가 - deadline에 string 타입으로 response로 전달되어서 new Date로 감싸서 props로 전달 * docs: indexhtml의 title 변경 * style: apis/review.ts 의 import 관련 eslint rule 적용에 따른 수정 * fix: ts에서 process 읽지 못하는 오류 수정 * fix: webpack dev server script 복원
- Loading branch information
1 parent
4b2be22
commit e05c164
Showing
48 changed files
with
866 additions
and
262 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
/* eslint-disable */ | ||
/* tslint:disable */ | ||
|
||
/** | ||
* Mock Service Worker. | ||
* @see https://github.com/mswjs/msw | ||
* - Please do NOT modify this file. | ||
* - Please do NOT serve this file on production. | ||
*/ | ||
|
||
const PACKAGE_VERSION = '2.3.4'; | ||
const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'; | ||
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse'); | ||
const activeClientIds = new Set(); | ||
|
||
self.addEventListener('install', function () { | ||
self.skipWaiting(); | ||
}); | ||
|
||
self.addEventListener('activate', function (event) { | ||
event.waitUntil(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({ | ||
type: 'window', | ||
}); | ||
|
||
switch (event.data) { | ||
case 'KEEPALIVE_REQUEST': { | ||
sendToClient(client, { | ||
type: 'KEEPALIVE_RESPONSE', | ||
}); | ||
break; | ||
} | ||
|
||
case 'INTEGRITY_CHECK_REQUEST': { | ||
sendToClient(client, { | ||
type: 'INTEGRITY_CHECK_RESPONSE', | ||
payload: { | ||
packageVersion: PACKAGE_VERSION, | ||
checksum: 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; | ||
} | ||
} | ||
}); | ||
|
||
self.addEventListener('fetch', function (event) { | ||
const { request } = event; | ||
|
||
// 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; | ||
} | ||
|
||
// Generate unique request ID. | ||
const requestId = crypto.randomUUID(); | ||
event.respondWith(handleRequest(event, requestId)); | ||
}); | ||
|
||
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 responseClone = response.clone(); | ||
|
||
sendToClient( | ||
client, | ||
{ | ||
type: 'RESPONSE', | ||
payload: { | ||
requestId, | ||
isMockedResponse: IS_MOCKED_RESPONSE in response, | ||
type: responseClone.type, | ||
status: responseClone.status, | ||
statusText: responseClone.statusText, | ||
body: responseClone.body, | ||
headers: Object.fromEntries(responseClone.headers.entries()), | ||
}, | ||
}, | ||
[responseClone.body], | ||
); | ||
})(); | ||
} | ||
|
||
return response; | ||
} | ||
|
||
// 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({ | ||
type: 'window', | ||
}); | ||
|
||
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 getResponse(event, client, requestId) { | ||
const { request } = event; | ||
|
||
// Clone the request because it might've been already used | ||
// (i.e. its body has been read and sent to the client). | ||
const requestClone = request.clone(); | ||
|
||
function passthrough() { | ||
const headers = Object.fromEntries(requestClone.headers.entries()); | ||
|
||
// Remove internal MSW request header so the passthrough request | ||
// complies with any potential CORS preflight checks on the server. | ||
// Some servers forbid unknown request headers. | ||
delete headers['x-msw-intention']; | ||
|
||
return fetch(requestClone, { headers }); | ||
} | ||
|
||
// Bypass mocking when the client is not active. | ||
if (!client) { | ||
return passthrough(); | ||
} | ||
|
||
// 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 passthrough(); | ||
} | ||
|
||
// Notify the client that a request has been intercepted. | ||
const requestBuffer = await request.arrayBuffer(); | ||
const clientMessage = await sendToClient( | ||
client, | ||
{ | ||
type: 'REQUEST', | ||
payload: { | ||
id: requestId, | ||
url: request.url, | ||
mode: request.mode, | ||
method: request.method, | ||
headers: Object.fromEntries(request.headers.entries()), | ||
cache: request.cache, | ||
credentials: request.credentials, | ||
destination: request.destination, | ||
integrity: request.integrity, | ||
redirect: request.redirect, | ||
referrer: request.referrer, | ||
referrerPolicy: request.referrerPolicy, | ||
body: requestBuffer, | ||
keepalive: request.keepalive, | ||
}, | ||
}, | ||
[requestBuffer], | ||
); | ||
|
||
switch (clientMessage.type) { | ||
case 'MOCK_RESPONSE': { | ||
return respondWithMock(clientMessage.data); | ||
} | ||
|
||
case 'PASSTHROUGH': { | ||
return passthrough(); | ||
} | ||
} | ||
|
||
return passthrough(); | ||
} | ||
|
||
function sendToClient(client, message, transferrables = []) { | ||
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(message, [channel.port2].concat(transferrables.filter(Boolean))); | ||
}); | ||
} | ||
|
||
async function respondWithMock(response) { | ||
// Setting response status code to 0 is a no-op. | ||
// However, when responding with a "Response.error()", the produced Response | ||
// instance will have status code set to 0. Since it's not possible to create | ||
// a Response instance with status code 0, handle that use-case separately. | ||
if (response.status === 0) { | ||
return Response.error(); | ||
} | ||
|
||
const mockedResponse = new Response(response.body, response); | ||
|
||
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { | ||
value: true, | ||
enumerable: true, | ||
}); | ||
|
||
return mockedResponse; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
const endPoint = { | ||
postingReview: `${process.env.API_BASE_URL}/reviews`, | ||
gettingDetailedReview: (reviewId: number) => `${process.env.API_BASE_URL}/reviews/${reviewId}`, | ||
gettingDataToWriteReview: (reviewerGroupId: number) => `/reviewer-groups/${reviewerGroupId}`, | ||
gettingKeyword: `${process.env.API_BASE_URL}/keywords`, | ||
postingReview: `${process.env.API_BASE_URL}reviews`, | ||
gettingDetailedReview: (reviewId: number) => `${process.env.API_BASE_URL}reviews/${reviewId}`, | ||
gettingInfoToWriteReview: (reviewerGroupId: number) => `/reviewer-groups/${reviewerGroupId}`, | ||
gettingKeyword: `${process.env.API_BASE_URL}keywords`, | ||
}; | ||
|
||
export default endPoint; |
20 changes: 20 additions & 0 deletions
20
frontend/src/components/common/MultilineTextViewer/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import React from 'react'; | ||
|
||
interface MultilineTextViewerProps { | ||
text: string; | ||
} | ||
|
||
const MultilineTextViewer = ({ text }: MultilineTextViewerProps) => { | ||
return ( | ||
<> | ||
{text.split('\n').map((line, index) => ( | ||
<React.Fragment key={index}> | ||
{line} | ||
<br /> | ||
</React.Fragment> | ||
))} | ||
</> | ||
); | ||
}; | ||
|
||
export default MultilineTextViewer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import GithubLogoIcon from '@/assets/githubLogo.svg'; | ||
|
||
import * as S from './styles'; | ||
|
||
export interface ProjectImgProps { | ||
thumbnailUrl?: string; | ||
projectName: string; | ||
$size: string; | ||
} | ||
const ProjectImg = ({ thumbnailUrl, projectName, $size }: ProjectImgProps) => { | ||
const src = thumbnailUrl ?? GithubLogoIcon; | ||
const alt = thumbnailUrl ? `${projectName} 저장소 이미지` : '깃허브 로고'; | ||
return <S.Img src={src} alt={alt} $size={$size} />; | ||
}; | ||
|
||
export default ProjectImg; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import styled from '@emotion/styled'; | ||
|
||
interface ImgProps { | ||
$size: string; | ||
} | ||
|
||
export const Img = styled.img<ImgProps>` | ||
width: ${(props) => props.$size}; | ||
height: ${(props) => props.$size}; | ||
border-radius: ${({ theme }) => theme.borderRadius.basic}; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import * as S from './styles'; | ||
|
||
interface ReviewCommentProps { | ||
comment: string; | ||
} | ||
|
||
const ReviewComments = ({ comment }: ReviewCommentProps) => { | ||
return <S.ReviewComment>{comment}</S.ReviewComment>; | ||
}; | ||
|
||
export default ReviewComments; |
Oops, something went wrong.