| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- 'use client';
- import './style.scss';
- import { useEffect, useState, useCallback, useRef } from 'react';
- import Loading from '@/app/component/Loading';
- import { Button } from '@/components/ui/button';
- import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
- import { fetchReport } from '@/lib/api/forum/post';
- import { throwError } from '@/lib/utils/client';
- import { ReportType } from '@/constants/forum';
- import PostReportRequest from '@/dtos/request/forum/post/postReportRequest';
- type Props = {
- isEnable: boolean;
- open: boolean;
- onChange: (_: boolean) => void;
- onComplete: (_: boolean) => void;
- postID: number;
- memberID?: number;
- }
- export default function Report({ isEnable, open, onChange, onComplete, postID, memberID }: Props)
- {
- const [error, setError] = useState<string>('');
- const [loading, setLoading] = useState<boolean>(false);
- const [form, setForm] = useState<{
- type: string;
- reason: string;
- }>({
- type: '',
- reason: ''
- });
- const typeRef = useRef<HTMLSelectElement>(null);
- const reasonRef = useRef<HTMLTextAreaElement>(null);
- const reportTypeLabels: Record<ReportType, string> = {
- [ReportType.None]: '신고 유형을 선택하세요.',
- [ReportType.Abuse]: '욕설',
- [ReportType.Obscene]: '음란',
- [ReportType.Illegal]: '불법',
- [ReportType.Impersonation]: '신분 사칭',
- [ReportType.CashTrade]: '현금거래 유도',
- [ReportType.SpamAd]: '스팸/광고',
- [ReportType.Flood]: '도배',
- [ReportType.PersonalLeak]: '개인정보 노출',
- [ReportType.Other]: '기타'
- };
- useEffect(() => {
- if (error) {
- alert(error);
- setError('');
- }
- }, [error]);
- const handleChange = (e: React.ChangeEvent<HTMLSelectElement|HTMLTextAreaElement>) => {
- const { name, value } = e.target;
- setForm((prev) => ({
- ...prev,
- [name]: value
- }));
- };
- const handleSubmit = useCallback(async () => {
- if (!form.type) {
- alert('신고 유형을 선택하세요.');
- typeRef.current?.focus();
- return;
- }
- if (!form.reason) {
- alert('신고 내용을 입력해주세요.');
- reasonRef.current?.focus();
- return;
- }
- if (!memberID) {
- alert('로그인 후 이용해주세요.');
- return;
- }
- setLoading(true);
- onChange(false);
- try {
- const res = await fetchReport({
- postID,
- type: Number(form.type) as ReportType,
- reason: form.reason
- } as PostReportRequest);
- if (res.success) {
- alert('신고가 접수되었습니다.');
- setForm({ type: '', reason: '' });
- onComplete(true);
- } else {
- throwError(res);
- }
- } catch (err: any) {
- alert(err.message);
- } finally {
- setLoading(false);
- }
- }, [form, postID, memberID, onChange]);
- if (!isEnable) {
- return null;
- }
- return (
- <>
- {loading && <Loading />}
- <Dialog open={open} onOpenChange={onChange}>
- <DialogContent className='w-3xs sm:max-w-md'>
- <DialogHeader>
- <DialogTitle>게시글 신고</DialogTitle>
- </DialogHeader>
- <div id='report' className='flex flex-col items-center gap-4'>
- <select ref={typeRef} name='type' value={form.type} title='신고 유형' onChange={handleChange}>
- {Object.entries(reportTypeLabels).map(([key, label]) => (
- <option key={key} value={key}>
- {label}
- </option>
- ))}
- </select>
- <textarea ref={reasonRef} name='reason' rows={4} value={form.reason} title='신고 내용' onChange={handleChange} maxLength={500} placeholder='신고 내용을 구체적으로 입력해주세요.(500자 이하)'></textarea>
- <Button type='button' variant='outline' className='hover:bg-blue-500 hover:text-white sm:w-24' onClick={handleSubmit}>
- 신고하기
- </Button>
- </div>
- </DialogContent>
- </Dialog>
- </>
- );
- }
|