-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 톡픽 상세 조회 모바일 컴포넌트 구현 #307
base: dev
Are you sure you want to change the base?
Changes from all commits
9a9f88b
f13b0f2
adda972
facdd05
0e6efe4
a2330c1
6ad78aa
38b2c52
c9e5967
071ce13
3029212
25ea527
a6b25ed
300456e
00705ac
b64bfb2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { css } from '@emotion/react'; | ||
import color from '@/styles/color'; | ||
import typo from '@/styles/typo'; | ||
|
||
export const summaryItemStyling = css(typo.Mobile.Text.Medium_12, { | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
padding: '4px 20px 4px 5px', | ||
gap: '13px', | ||
backgroundColor: color.WT_VIOLET, | ||
color: color.BK, | ||
borderRadius: '30px', | ||
}); | ||
|
||
export const numberItemStyling = css(typo.Mobile.Text.Medium_12, { | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
flexShrink: 0, | ||
width: '18px', | ||
height: '18px', | ||
backgroundColor: color.MAIN, | ||
color: color.WT, | ||
borderRadius: '50%', | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import React, { ReactNode } from 'react'; | ||
import { numberItemStyling, summaryItemStyling } from './SummaryItem.style'; | ||
|
||
export interface SummaryItemProps { | ||
itemNumber?: '1' | '2' | '3'; | ||
children?: ReactNode; | ||
} | ||
|
||
const SummaryItem = ({ itemNumber = '1', children }: SummaryItemProps) => ( | ||
<div css={summaryItemStyling}> | ||
<div css={numberItemStyling}>{itemNumber}</div> | ||
{children} | ||
</div> | ||
); | ||
|
||
export default SummaryItem; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { css } from '@emotion/react'; | ||
import color from '@/styles/color'; | ||
import typo from '@/styles/typo'; | ||
|
||
export const reportModalStyling = css({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
alignItems: 'center', | ||
gap: '20px', | ||
}); | ||
|
||
export const reportTextWrapper = css({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
alignItems: 'center', | ||
gap: '6px', | ||
}); | ||
|
||
export const reportTextStyling = css(typo.Main.SemiBold, { | ||
color: color.BK, | ||
}); | ||
|
||
export const buttonWrapperStyling = css({ | ||
display: 'grid', | ||
gridTemplateColumns: 'repeat(2, 1fr)', | ||
gridGap: '7px', | ||
}); | ||
|
||
export const reportBtnWrapperStyling = css({ | ||
display: 'flex', | ||
justifyContent: 'space-between', | ||
width: '100%', | ||
}); | ||
|
||
export const buttonStyling = css(typo.Mobile.Text.Medium_14, { | ||
display: 'flex', | ||
width: '143px', | ||
height: '50px', | ||
alignItems: 'center', | ||
padding: '0 16px', | ||
borderRadius: '8px', | ||
backgroundColor: color.GY[5], | ||
color: color.GY[6], | ||
cursor: 'pointer', | ||
}); | ||
|
||
export const selectedButtonStyling = css({ | ||
backgroundColor: color.WT_VIOLET, | ||
color: color.MAIN, | ||
outline: `2px solid ${color.MAIN}`, | ||
}); | ||
|
||
export const getButtonStyling = (selected: boolean) => | ||
css({ | ||
width: '293px', | ||
height: '44px', | ||
borderRadius: '12px', | ||
backgroundColor: selected ? color.MAIN : color.GY[2], | ||
}); | ||
|
||
export const reportInputStyling = css(typo.Mobile.Text.SemiBold_14, { | ||
width: '100%', | ||
padding: '6px 0', | ||
outline: '0', | ||
border: 'none', | ||
borderBottom: `1px solid ${color.GY[3]}`, | ||
color: color.BK, | ||
|
||
':-webkit-autofill': { | ||
boxShadow: '0 0 0px 1000px white inset', | ||
}, | ||
|
||
'&::placeholder': { | ||
color: color.GY[1], | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,75 @@ | ||||||||||||||||||||||||||||||||||||
import React, { useState } from 'react'; | ||||||||||||||||||||||||||||||||||||
import { MobileReport } from '@/assets'; | ||||||||||||||||||||||||||||||||||||
import Modal from '@/components/mobile/atoms/Modal/Modal'; | ||||||||||||||||||||||||||||||||||||
import Button from '@/components/mobile/atoms/Button/Button'; | ||||||||||||||||||||||||||||||||||||
import { reportOptions } from '@/constants/reportOption'; | ||||||||||||||||||||||||||||||||||||
import * as S from './ReportModal.style'; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
export interface ReportModalProps { | ||||||||||||||||||||||||||||||||||||
isOpen?: boolean; | ||||||||||||||||||||||||||||||||||||
onConfirm?: (reason: string) => void; | ||||||||||||||||||||||||||||||||||||
onClose?: () => void; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
Comment on lines
+8
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Props 타입에 필수값 표시가 필요합니다. Props 타입에서 선택적 필드( export interface ReportModalProps {
- isOpen?: boolean;
- onConfirm?: (reason: string) => void;
- onClose?: () => void;
+ isOpen: boolean;
+ onConfirm: (reason: string) => void;
+ onClose: () => void;
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
const ReportModal = ({ isOpen, onConfirm, onClose }: ReportModalProps) => { | ||||||||||||||||||||||||||||||||||||
const [reportReason, setReportReason] = useState<string>(''); | ||||||||||||||||||||||||||||||||||||
const [otherReason, setOtherReason] = useState<string>(''); | ||||||||||||||||||||||||||||||||||||
const finalReportReason: string = | ||||||||||||||||||||||||||||||||||||
reportReason === '기타' ? otherReason : reportReason; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
const handleOtherReportReason = (e: React.ChangeEvent<HTMLInputElement>) => { | ||||||||||||||||||||||||||||||||||||
setOtherReason(e.target.value); | ||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
const handleConfirm = () => { | ||||||||||||||||||||||||||||||||||||
if (!finalReportReason.trim()) return; | ||||||||||||||||||||||||||||||||||||
onConfirm?.(finalReportReason); | ||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||
Comment on lines
+24
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion handleConfirm 함수의 오류 처리가 필요합니다. 빈 문자열 체크만 하고 있으며, 최소/최대 길이 검증이나 사용자 피드백이 없습니다. const handleConfirm = () => {
- if (!finalReportReason.trim()) return;
+ if (!finalReportReason.trim()) {
+ showToastModal('신고 사유를 입력해주세요.');
+ return;
+ }
+ if (reportReason === '기타' && otherReason.length < 10) {
+ showToastModal('신고 사유는 최소 10자 이상 입력해주세요.');
+ return;
+ }
onConfirm?.(finalReportReason);
}; 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||
<Modal action="share" isOpen={isOpen} onClose={onClose}> | ||||||||||||||||||||||||||||||||||||
<div css={S.reportModalStyling}> | ||||||||||||||||||||||||||||||||||||
<div css={S.reportTextWrapper}> | ||||||||||||||||||||||||||||||||||||
<MobileReport /> | ||||||||||||||||||||||||||||||||||||
<div css={S.reportTextStyling}>신고사유 선택</div> | ||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||
<div css={S.buttonWrapperStyling}> | ||||||||||||||||||||||||||||||||||||
{reportOptions.map((option) => ( | ||||||||||||||||||||||||||||||||||||
<button | ||||||||||||||||||||||||||||||||||||
type="button" | ||||||||||||||||||||||||||||||||||||
value={option.value} | ||||||||||||||||||||||||||||||||||||
key={option.value} | ||||||||||||||||||||||||||||||||||||
onClick={() => { | ||||||||||||||||||||||||||||||||||||
setReportReason(option.value); | ||||||||||||||||||||||||||||||||||||
setOtherReason(''); | ||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||
css={[ | ||||||||||||||||||||||||||||||||||||
S.buttonStyling, | ||||||||||||||||||||||||||||||||||||
option.value === reportReason && S.selectedButtonStyling, | ||||||||||||||||||||||||||||||||||||
]} | ||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||
{option.label} | ||||||||||||||||||||||||||||||||||||
</button> | ||||||||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||
{reportReason === '기타' && ( | ||||||||||||||||||||||||||||||||||||
<input | ||||||||||||||||||||||||||||||||||||
css={S.reportInputStyling} | ||||||||||||||||||||||||||||||||||||
placeholder="신고사유를 작성해주세요." | ||||||||||||||||||||||||||||||||||||
onChange={handleOtherReportReason} | ||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||
Comment on lines
+56
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 접근성을 개선하세요. 입력 필드에 적절한 레이블과 ARIA 속성이 필요합니다. +<label htmlFor="otherReason" css={S.srOnly}>
+ 기타 신고 사유
+</label>
<input
+ id="otherReason"
css={S.reportInputStyling}
placeholder="신고사유를 작성해주세요."
+ aria-label="기타 신고 사유"
onChange={handleOtherReportReason}
/> 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||
Comment on lines
+55
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 입력 필드에 대한 유효성 검사를 추가하세요. 기타 사유 입력 시 최소/최대 길이 제한과 같은 유효성 검사가 필요합니다. <input
css={S.reportInputStyling}
placeholder="신고사유를 작성해주세요."
+ minLength={10}
+ maxLength={200}
onChange={handleOtherReportReason}
+ required
/> 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||
<Button | ||||||||||||||||||||||||||||||||||||
size="large" | ||||||||||||||||||||||||||||||||||||
variant="primary" | ||||||||||||||||||||||||||||||||||||
onClick={handleConfirm} | ||||||||||||||||||||||||||||||||||||
css={S.getButtonStyling(!!finalReportReason)} | ||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||
설정 완료 | ||||||||||||||||||||||||||||||||||||
</Button> | ||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||
</Modal> | ||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
export default ReportModal; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
선택된 버튼의 너비가 일관성이 없습니다.
getButtonStyling
함수에서 설정된 버튼 너비(293px)가buttonStyling
의 너비(143px)와 크게 다릅니다. 일관된 사용자 경험을 위해 버튼 크기를 통일하는 것이 좋습니다.