diff --git a/baedalmate/src/components/atoms/Report/ReportListItem.tsx b/baedalmate/src/components/atoms/Report/ReportListItem.tsx index e28250f..383736c 100644 --- a/baedalmate/src/components/atoms/Report/ReportListItem.tsx +++ b/baedalmate/src/components/atoms/Report/ReportListItem.tsx @@ -23,7 +23,14 @@ import { } from 'themes/theme'; import {Fonts} from '../../../assets/Fonts'; -const ReportListItem = ({type, item, onPress, selectedReportReason}) => { +const ReportListItem = ({ + type, + item, + onPress, + selectedReportReason, + detailReport, + setDetailReport, +}) => { return ( @@ -65,6 +72,10 @@ const ReportListItem = ({type, item, onPress, selectedReportReason}) => { color: '#313131', padding: 15, }} + value={detailReport} + onChangeText={v => { + setDetailReport(v); + }} placeholder={'신고 사유를 작성해주세요. (100자 이내)'} placeholderTextColor={'#C8C8C8'} multiline diff --git a/baedalmate/src/components/pages/Report/ItemReport.tsx b/baedalmate/src/components/pages/Report/ItemReport.tsx index dc02971..44a14ea 100644 --- a/baedalmate/src/components/pages/Report/ItemReport.tsx +++ b/baedalmate/src/components/pages/Report/ItemReport.tsx @@ -1,12 +1,14 @@ import React, {useState} from 'react'; -import {ScrollView, View} from 'react-native'; +import {KeyboardAvoidingView, Platform, ScrollView, View} from 'react-native'; import {DARK_GRAY_COLOR, PRIMARY_COLOR, WHITE_COLOR} from 'themes/theme'; import MyPageListItem from 'components/atoms/Setting/MyPageListItem'; import MyPageBar from 'components/atoms/Setting/MyPageBar'; import {TextKRBold, TextKRReg} from 'themes/text'; import BtnVerticalOrange from 'components/atoms/Button/BtnVerticalOrange'; import ReportListItem from 'components/atoms/Report/ReportListItem'; - +import {postReportRecruitAPI} from 'components/utils/api/Report'; +import {UsePopup} from 'components/utils/usePopup'; +import {postBlockAPI} from 'components/utils/api/Block'; export interface MyPageI { userId: number; nickname: string; @@ -23,8 +25,10 @@ export const MyPageUserDummyData = { }; const ItemReport = ({route, navigation}) => { - // const navigation = useNavigation(); const [selectedReportReason, setSelectedReportReason] = useState(-1); + const targetRecruitId = route.params.item.recruitId; + const [detailReport, setDetailReport] = useState(''); + const userInfo = route.params.userInfo; const ItemReportList = [ { value: 0, @@ -59,42 +63,83 @@ const ItemReport = ({route, navigation}) => { name: '다른 문제가 있어요', }, ]; + const [modal, setModal] = useState(false); + const handleModal = () => { + modal ? setModal(false) : setModal(true); + }; + const blockUser = async () => { + if (userInfo?.userId) { + const result = await postBlockAPI(userInfo?.userId); + if (result) { + console.log('block user', result); + } + } + }; + const successModalData = { + title: '신고가 완료되었습니다.', + description: `신고 심사 결과에 따라 처리됩니다.\n'${userInfo.nickname}'님을 차단하시겠습니까?`, + modal: modal, + handleModal: handleModal, + confirmEvent: blockUser, + choiceCnt: 2, + }; + const errorModalData = { + title: '신고에 실패하였습니다.', + description: '', + modal: modal, + handleModal: handleModal, + confirmEvent: handleModal, + choiceCnt: 1, + }; + const [modalData, setModalData] = useState<{ + title: string; + description: string; + modal: boolean; + handleModal: () => void; + confirmEvent: any; + choiceCnt: number; + }>(successModalData); const UserReportList = [ { name: '사용자 신고하러 가기', onPress: () => { - navigation.navigate('사용자 신고하기'); + navigation.navigate('사용자 신고하기', { + userInfo: userInfo, + } as never); }, }, ]; - // const renderItem = ({item}) => { - // return ( - // { - // setSelectedReportReason(item.value); - // }} - // style={{ - // height: 52, - // width: '100%', - // paddingHorizontal: 15, - // justifyContent: 'center', - // borderBottomColor: LINE_GRAY_COLOR, - // borderBottomWidth: 1, - // }}> - // - // {item.name} - // - // - // ); - // }; + const reportItem = async () => { + const result = await postReportRecruitAPI( + targetRecruitId, + ItemReportList[selectedReportReason].name, + detailReport, + ); + console.log('report item ', result); + if ('result' in result) { + setModalData(successModalData); + handleModal(); + } else { + if (result.response.data.code === 400) { + if (result.response.data.message === 'Api request body invalid') { + errorModalData.description = '필수 정보가 누락되었습니다.'; + } else if (result.response.data.message === 'Already reported') { + errorModalData.description = '이미 신고하였습니다.'; + } else if ( + result.response.data.message === 'Users cannot report themselves' + ) { + errorModalData.description = '자기 자신은 신고가 불가능합니다.'; + } + } else if (result.response.data.code === 401) { + errorModalData.description = '토큰이 만료되었습니다.'; + } else if (result.response.data.code === 403) { + errorModalData.description = '권한이 부족합니다.'; + } + setModalData(errorModalData); + handleModal(); + } + }; return ( <> { paddingVertical: 10, backgroundColor: WHITE_COLOR, }}> - - - 게시글을 신고하는 사유를 선택해주세요 - - - 신고 사유 검토후, 검토 결과에 따라 처리됩니다.{' '} - - - {ItemReportList.map((v, i) => ( - - - { - setSelectedReportReason(v.value); - }} - selectedReportReason={selectedReportReason} - /> - - ))} + + + + + 게시글을 신고하는 사유를 선택해주세요 + + + 신고 사유 검토후, 검토 결과에 따라 처리됩니다.{' '} + + + {ItemReportList.map((v, i) => ( + + + { + setSelectedReportReason(v.value); + setDetailReport(''); + }} + selectedReportReason={selectedReportReason} + detailReport={detailReport} + setDetailReport={setDetailReport} + /> + + ))} + - - - - ‘캡스톤 디자인’ 님을 신고하고 싶으신가요? - - - {UserReportList.map((v, i) => ( - - {i !== 0 && } - - - ))} + + + ‘{userInfo.nickname}’ 님을 신고하고 싶으신가요? + + + {UserReportList.map((v, i) => ( + + {i !== 0 && } + + + ))} + - + { position: 'absolute', bottom: 45, }}> - {}} text={'신고하기'} /> + { + if ( + selectedReportReason === -1 || + (selectedReportReason === 7 && detailReport === '') + ) + return; + reportItem(); + }} + text={'신고하기'} + /> ); diff --git a/baedalmate/src/components/pages/Report/UserReport.tsx b/baedalmate/src/components/pages/Report/UserReport.tsx index 6976288..e3a888f 100644 --- a/baedalmate/src/components/pages/Report/UserReport.tsx +++ b/baedalmate/src/components/pages/Report/UserReport.tsx @@ -1,10 +1,13 @@ import React, {useState} from 'react'; -import {ScrollView, View} from 'react-native'; +import {KeyboardAvoidingView, Platform, ScrollView, View} from 'react-native'; import {DARK_GRAY_COLOR, PRIMARY_COLOR, WHITE_COLOR} from 'themes/theme'; import MyPageBar from 'components/atoms/Setting/MyPageBar'; import {TextKRBold, TextKRReg} from 'themes/text'; import BtnVerticalOrange from 'components/atoms/Button/BtnVerticalOrange'; import ReportListItem from 'components/atoms/Report/ReportListItem'; +import {postBlockAPI} from 'components/utils/api/Block'; +import {postReportUserAPI} from 'components/utils/api/Report'; +import {UsePopup} from 'components/utils/usePopup'; export interface MyPageI { userId: number; @@ -24,6 +27,10 @@ export const MyPageUserDummyData = { const UserReport = ({route, navigation}) => { // const navigation = useNavigation(); const [selectedReportReason, setSelectedReportReason] = useState(-1); + const [detailReport, setDetailReport] = useState(''); + const userInfo = route.params.userInfo; + const targetUserId = route.params.userInfo.userId; + const UserReportList = [ { value: 0, @@ -55,34 +62,73 @@ const UserReport = ({route, navigation}) => { }, ]; - // const renderItem = ({item}) => { - // return ( - // { - // setSelectedReportReason(item.value); - // }} - // style={{ - // height: 52, - // width: '100%', - // paddingHorizontal: 15, - // justifyContent: 'center', - // borderBottomColor: LINE_GRAY_COLOR, - // borderBottomWidth: 1, - // }}> - // - // {item.name} - // - // - // ); - // }; - console.log(route, navigation); + const [modal, setModal] = useState(false); + const handleModal = () => { + modal ? setModal(false) : setModal(true); + }; + const blockUser = async () => { + if (userInfo?.userId) { + const result = await postBlockAPI(userInfo?.userId); + if (result) { + console.log('block user', result); + } + } + }; + const successModalData = { + title: '신고가 완료되었습니다.', + description: `신고 심사 결과에 따라 처리됩니다.\n'${userInfo.nickname}'님을 차단하시겠습니까?`, + modal: modal, + handleModal: handleModal, + confirmEvent: blockUser, + choiceCnt: 2, + }; + const errorModalData = { + title: '신고에 실패하였습니다.', + description: '', + modal: modal, + handleModal: handleModal, + confirmEvent: handleModal, + choiceCnt: 1, + }; + const [modalData, setModalData] = useState<{ + title: string; + description: string; + modal: boolean; + handleModal: () => void; + confirmEvent: any; + choiceCnt: number; + }>(successModalData); + + const reportUser = async () => { + const result = await postReportUserAPI( + targetUserId, + UserReportList[selectedReportReason].name, + detailReport, + ); + console.log('report user ', result); + if ('result' in result) { + setModalData(successModalData); + handleModal(); + } else { + if (result.response.data.code === 400) { + if (result.response.data.message === 'Api request body invalid') { + errorModalData.description = '필수 정보가 누락되었습니다.'; + } else if (result.response.data.message === 'Already reported') { + errorModalData.description = '이미 신고하였습니다.'; + } else if ( + result.response.data.message === 'Users cannot report themselves' + ) { + errorModalData.description = '자기 자신은 신고가 불가능합니다.'; + } + } else if (result.response.data.code === 401) { + errorModalData.description = '토큰이 만료되었습니다.'; + } else if (result.response.data.code === 403) { + errorModalData.description = '권한이 부족합니다.'; + } + setModalData(errorModalData); + handleModal(); + } + }; return ( <> { paddingVertical: 10, backgroundColor: WHITE_COLOR, }}> - - - ‘{route.params.user.nickname}’ 님을 신고하는 사유를 선택해주세요 - - - 신고 사유 검토후, 검토 결과에 따라 처리됩니다.{' '} - - - {UserReportList && - UserReportList.map((v, i) => ( - - - { - setSelectedReportReason(v.value); - }} - selectedReportReason={selectedReportReason} - /> - - ))} + + + + + ‘{userInfo.nickname}’ 님을 신고하는 사유를 선택해주세요 + + + 신고 사유 검토후, 검토 결과에 따라 처리됩니다.{' '} + + + {UserReportList && + UserReportList.map((v, i) => ( + + + { + setSelectedReportReason(v.value); + }} + selectedReportReason={selectedReportReason} + detailReport={detailReport} + setDetailReport={setDetailReport} + /> + + ))} + - - + { position: 'absolute', bottom: 45, }}> - {}} text={'신고하기'} /> + { + if ( + selectedReportReason === -1 || + (selectedReportReason === 6 && detailReport === '') + ) + return; + reportUser(); + }} + text={'신고하기'} + /> ); diff --git a/baedalmate/src/components/utils/api/Report.ts b/baedalmate/src/components/utils/api/Report.ts new file mode 100644 index 0000000..9f01ef2 --- /dev/null +++ b/baedalmate/src/components/utils/api/Report.ts @@ -0,0 +1,84 @@ +import {url} from '../../../../App'; +import axios from 'axios'; +import {getJWTToken} from './Recruit'; + +export const reportURL = url + '/api/v1/report'; +export const reportUserURL = reportURL + '/user'; +export const reportRecruitURL = reportURL + '/recruit'; + +export interface reportI { + targetUserId: number; + reason: string; + detail: string; +} +export interface reportRecruitI { + targetRecruitId: number; + reason: string; + detail: string; +} + +export const postReportUserAPI = async ( + targetUserId: number, + reason: string, + detail: string, +) => { + const JWTAccessToken = await getJWTToken(); + console.log(JWTAccessToken); + try { + const result = axios + .post( + reportUserURL, + {targetUserId, reason, detail}, + { + headers: { + Authorization: 'Bearer ' + JWTAccessToken, + }, + }, + ) + .then(function (response) { + console.log(response); + return response; + }) + .catch(function (error) { + console.log(error); + return error; + }); + return result; + } catch (error) { + console.log(error); + return error; + } +}; + +export const postReportRecruitAPI = async ( + targetRecruitId: number, + reason: string, + detail: string, +) => { + const JWTAccessToken = await getJWTToken(); + console.log(JWTAccessToken); + try { + const result = axios + .post( + reportRecruitURL, + {targetRecruitId, reason, detail}, + { + headers: { + Authorization: 'Bearer ' + JWTAccessToken, + }, + }, + ) + .then(function (response) { + console.log(response); + return response; + }) + .catch(function (error) { + console.log(error); + return error; + }); + return result; + } catch (error) { + console.log(error); + return error; + } +}; diff --git a/baedalmate/src/components/utils/usePopup.tsx b/baedalmate/src/components/utils/usePopup.tsx index 4694969..ced2d64 100644 --- a/baedalmate/src/components/utils/usePopup.tsx +++ b/baedalmate/src/components/utils/usePopup.tsx @@ -14,6 +14,7 @@ export const UsePopup = ({ description, modal, handleModal, + choiceCnt, confirmEvent, }) => { return ( @@ -29,6 +30,7 @@ export const UsePopup = ({ {description} @@ -77,23 +80,25 @@ export const UsePopup = ({ justifyContent: 'space-around', alignItems: 'center', }}> - { - handleModal(); - }} - underlayColor={LINE_GRAY_COLOR}> - - 취소 - - + {choiceCnt > 1 && ( + { + handleModal(); + }} + underlayColor={LINE_GRAY_COLOR}> + + 취소 + + + )}