diff --git a/public/assets/sprites/common.svg b/public/assets/sprites/common.svg index 2f44bdb..f81dfb3 100644 --- a/public/assets/sprites/common.svg +++ b/public/assets/sprites/common.svg @@ -113,4 +113,68 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/app/styles/_reset.scss b/src/app/styles/_reset.scss index c5a8d38..dcde9a0 100644 --- a/src/app/styles/_reset.scss +++ b/src/app/styles/_reset.scss @@ -78,7 +78,8 @@ summary, time, mark, audio, -video { +video, +textarea { margin: 0; padding: 0; border: 0; diff --git a/src/features/feed-reports/consts/index.ts b/src/features/feed-reports/consts/index.ts new file mode 100644 index 0000000..dc23413 --- /dev/null +++ b/src/features/feed-reports/consts/index.ts @@ -0,0 +1 @@ +export * from './reports'; diff --git a/src/features/feed-reports/consts/reports.ts b/src/features/feed-reports/consts/reports.ts new file mode 100644 index 0000000..e8a55ef --- /dev/null +++ b/src/features/feed-reports/consts/reports.ts @@ -0,0 +1,18 @@ +export type ReportCategoryId = 1 | 2 | 3 | 4 | 5 | 6 | 7; + +interface ReportCategory { + id: ReportCategoryId; + name: string; +} + +export const REPORT_CATEOGRIES: ReportCategory[] = [ + { id: 1, name: '상업적/홍보성' }, + { id: 2, name: '음란/선정성' }, + { id: 3, name: '저작권 침해' }, + { id: 4, name: '개인정보 노출' }, + { id: 5, name: '욕설/인신공격' }, + { id: 6, name: '반복적인 내용' }, + { id: 7, name: '기타' }, +]; + +export const MAX_REPORT_CONTENT_LENGTH = 100; diff --git a/src/features/feed-reports/index.ts b/src/features/feed-reports/index.ts new file mode 100644 index 0000000..0fe27b8 --- /dev/null +++ b/src/features/feed-reports/index.ts @@ -0,0 +1 @@ +export { FeedReportsForm } from './ui'; diff --git a/src/features/feed-reports/model/index.ts b/src/features/feed-reports/model/index.ts new file mode 100644 index 0000000..33ebb3d --- /dev/null +++ b/src/features/feed-reports/model/index.ts @@ -0,0 +1 @@ +export * from './useReportCategories'; diff --git a/src/features/feed-reports/model/useReportCategories.tsx b/src/features/feed-reports/model/useReportCategories.tsx new file mode 100644 index 0000000..94e1b92 --- /dev/null +++ b/src/features/feed-reports/model/useReportCategories.tsx @@ -0,0 +1,26 @@ +import { useState } from 'react'; + +import { REPORT_CATEOGRIES, ReportCategoryId } from '../consts'; + +export const useReportCategories = () => { + const [categories, setCategories] = useState( + new Map( + REPORT_CATEOGRIES.map((item) => [item.id, false]), + ), + ); + + const handleClickCategory = (id: ReportCategoryId) => { + setCategories((prev) => { + const newCheckedItem = new Map(prev); + newCheckedItem.set(id, !newCheckedItem.get(id)); + return newCheckedItem; + }); + }; + + return { categories, handleClickCategory }; +}; + +export function getCategoryName(id: ReportCategoryId) { + const category = REPORT_CATEOGRIES.find((item) => item.id === id); + return category?.name ?? ''; +} diff --git a/src/features/feed-reports/ui/ConfirmReportModal.scss b/src/features/feed-reports/ui/ConfirmReportModal.scss new file mode 100644 index 0000000..75534f5 --- /dev/null +++ b/src/features/feed-reports/ui/ConfirmReportModal.scss @@ -0,0 +1,21 @@ +.confirm-report-modal { + display: flex; + flex-direction: column; + + border-radius: 8px; + border: none; + background-color: white; + + width: 244px; + padding: 18px; + + .title { + align-self: start; + } + + .modal-btn-container { + display: flex; + justify-content: center; + gap: 8px; + } +} diff --git a/src/features/feed-reports/ui/ConfirmReportModal.tsx b/src/features/feed-reports/ui/ConfirmReportModal.tsx new file mode 100644 index 0000000..4defdf9 --- /dev/null +++ b/src/features/feed-reports/ui/ConfirmReportModal.tsx @@ -0,0 +1,39 @@ +import { ActiveButton, BasicButton } from '@/shared/ui'; +import { ModalOverlay } from '@/shared/ui/modal/ModalOverlay'; + +import './ConfirmReportModal.scss'; + +interface ConfirmReportModalProps { + onExecute: () => void; + onExecuteIsDisabled: boolean; + onClose: () => void; + children: JSX.Element[]; +} + +export const ConfirmReportModal: React.FC = ({ + onExecute, + onExecuteIsDisabled, + onClose, + children, +}) => { + return ( + +
+

신고하기

+ {children} +
+ + 취소 + + + 신고하기 + +
+
+
+ ); +}; diff --git a/src/features/feed-reports/ui/FeedReportsForm.scss b/src/features/feed-reports/ui/FeedReportsForm.scss new file mode 100644 index 0000000..af20af6 --- /dev/null +++ b/src/features/feed-reports/ui/FeedReportsForm.scss @@ -0,0 +1,68 @@ +.reports-list { + margin-top: 16px; + + display: grid; + grid-template-columns: repeat(2, 1fr); + + row-gap: 10px; + + .report-item { + display: flex; + align-items: center; + + gap: 4px; + + .checkbox-btn { + width: 20px; + height: 20px; + } + + .item-name { + color: $gray5; + } + } +} + +.report-textarea-container { + margin-top: 16px; + position: relative; + + width: 244px; + height: 72px; + + .report-textarea { + padding: 10px; + + width: calc(100% - 20px); + height: calc(100% - 20px); + + background-color: $gray1; + + resize: none; + + &:focus { + outline: none; + } + } + + .textarea-text-count { + position: absolute; + + right: 10px; + bottom: 8px; + + color: $gray3; + } +} + +.hide-checkbox-container { + margin: 12px 0 20px; + + display: flex; + align-items: center; + gap: 4px; + + .hide-checkbox-text { + color: $gray5; + } +} diff --git a/src/features/feed-reports/ui/FeedReportsForm.tsx b/src/features/feed-reports/ui/FeedReportsForm.tsx new file mode 100644 index 0000000..0c8d3a4 --- /dev/null +++ b/src/features/feed-reports/ui/FeedReportsForm.tsx @@ -0,0 +1,74 @@ +import { useInput, useToggle } from '@/shared/hooks'; +import { Icon } from '@/shared/ui'; + +import { MAX_REPORT_CONTENT_LENGTH } from '../consts'; +import { useReportCategories, getCategoryName } from '../model'; + +import { ConfirmReportModal } from './ConfirmReportModal'; +import './FeedReportsForm.scss'; + +interface FeedReportsFormProps { + onClose: () => void; +} + +export const FeedReportsForm: React.FC = ({ + onClose, +}) => { + const { categories, handleClickCategory } = useReportCategories(); + const [content, handleInputContent] = useInput(); + const [isBlind, toggleBlind] = useToggle(false); + + return ( + {}} // API 연동 후 수정 + onExecuteIsDisabled={false} // API 연동 후 수정 + onClose={onClose} + > + {/* 신고 카테고리 */} +
    + {[...categories].map(([id, checked]) => ( +
  • + +

    {getCategoryName(id)}

    +
  • + ))} +
+ + {/* 신고 사유 */} +
+