diff --git a/src/components/cstmrService/inquiry/InquiryWrite.js b/src/components/cstmrService/inquiry/InquiryWrite.js
index 9cce90e..1ff680b 100644
--- a/src/components/cstmrService/inquiry/InquiryWrite.js
+++ b/src/components/cstmrService/inquiry/InquiryWrite.js
@@ -19,9 +19,16 @@ import {
import classnames from 'classnames';
import { X } from 'react-feather';
-function InquiryWrite({ isInquiryModalOpen, handlerInquiryModal, detail }) {
+function InquiryWrite({
+ isInquiryModalOpen,
+ handlerInquiryModal,
+ detail,
+ handlerChangeInquiryForm,
+ handlerSubmitInquiryForm,
+ memberName,
+ inquiryForm
+}) {
const fileInputRef = useRef(null);
- const [value, setValue] = useState('');
const [selectedFile, setSelectedFile] = useState(null);
const handleFileChange = event => {
@@ -51,8 +58,10 @@ function InquiryWrite({ isInquiryModalOpen, handlerInquiryModal, detail }) {
{}}
+ value={inquiryForm.category}
+ onChange={e => {
+ handlerChangeInquiryForm('category', e.target.value);
+ }}
>
@@ -67,10 +76,14 @@ function InquiryWrite({ isInquiryModalOpen, handlerInquiryModal, detail }) {
+
+ handlerChangeInquiryForm('contact', e.target.value)
+ }
/>
@@ -87,28 +100,37 @@ function InquiryWrite({ isInquiryModalOpen, handlerInquiryModal, detail }) {
type='text'
bsSize='sm'
placeholder=''
- defaultValue={detail.createUserNm || ''}
- disabled
- />
-
-
-
-
-
-
+ {detail.createDt && (
+
+
+
+
+
+
+ )}
-
+
+ handlerChangeInquiryForm('title', e.target.value)
+ }
+ />
@@ -117,18 +139,21 @@ function InquiryWrite({ isInquiryModalOpen, handlerInquiryModal, detail }) {
*내용
setValue(e.target.value)}
- defaultValue={detail.content}
+ value={inquiryForm.content}
+ onChange={e =>
+ handlerChangeInquiryForm('content', e.target.value)
+ }
/>
{/* 하단 필요없으면제거 */}
300
+ 'bg-danger': inquiryForm.content.length > 300
})}
>
- {`${value.length}/300`}
+ {`${inquiryForm.content.length}/300`}
@@ -153,7 +178,7 @@ function InquiryWrite({ isInquiryModalOpen, handlerInquiryModal, detail }) {
id='inputFile'
name=''
className='custom-file-input pal'
- onChange={handleFileChange}
+ onChange={() => handleFileChange()}
ref={fileInputRef}
/>
{/* 현재는 text만 바뀌는상태! input 초기화 작업해주세용 */}
@@ -187,7 +212,9 @@ function InquiryWrite({ isInquiryModalOpen, handlerInquiryModal, detail }) {
-
+
diff --git a/src/containers/cstmrService/inquiry/UserInquiryContainer.js b/src/containers/cstmrService/inquiry/UserInquiryContainer.js
index b1edd0f..3ee21d6 100644
--- a/src/containers/cstmrService/inquiry/UserInquiryContainer.js
+++ b/src/containers/cstmrService/inquiry/UserInquiryContainer.js
@@ -1,29 +1,62 @@
import { Button, Badge } from 'reactstrap';
import AppCollapse from '@components/app-collapse';
import { useDispatch, useSelector } from 'react-redux';
-import {
- ADMIN_DETAIL,
- ADMIN_DETAIL_INITAL,
- USER_LIST
-} from '../../../modules/cstmrService/inquiry/action';
-import { useEffect, useState } from 'react';
+import * as Actions from '../../../modules/cstmrService/inquiry/action';
+import { Fragment, useCallback, useEffect, useState } from 'react';
import moment from 'moment';
import InquiryWrite from '../../../components/cstmrService/inquiry/InquiryWrite';
+import { InfoModal } from '../../../components/modal/InfoModal';
+import { ErrorModal } from '../../../components/modal/ErrorModal';
-export default function UserInquiryContainer() {
+export default function UserInquiryContainer({ memberName }) {
const dispatch = useDispatch();
const { userList: lists, adminDetail: detail } = useSelector(
state => state.qnaState
);
const [isInquiryModalOpen, setIsInquiryModalOpen] = useState(false);
+ const [inquiryForm, setInquiryForm] = useState({
+ category: '칭찬',
+ contact: '',
+ title: '',
+ content: ''
+ });
+ const [validationModal, setValidationModal] = useState({
+ errorType: {
+ isOpen: false,
+ desc: '',
+ title: '필수값 입력 오류'
+ },
+ successType: {
+ isOpen: false,
+ desc: '',
+ title: '필수값 입력 오류'
+ },
+ confirmType: {
+ isOpen: false,
+ desc: '',
+ title: '필수값 입력 오류'
+ }
+ });
useEffect(() => {
- dispatch(USER_LIST.request({ category: '', searchType: '', word: '' }));
+ dispatch(
+ Actions.USER_LIST.request({ category: '', searchType: '', word: '' })
+ );
}, []);
+ useEffect(() => {
+ if (detail) setInquiryForm({ ...detail });
+ }, [detail]);
+
+ // 줄바꿈 문자(\r\n)을
로 변환
const textLineBreaks = text => {
- return text.replace((/\n/g, '
'));
+ return text.split('\r\n').map((line, index) => (
+
+ {line}
+ {index < text.split('\r\n').length - 1 &&
}
+
+ ));
};
// 문의 내역 list
@@ -64,22 +97,17 @@ export default function UserInquiryContainer() {
<>
Q
-
+
{/* br처리? 줄바꿈.. 추후에 생각 */}
+ {textLineBreaks(i.content)}
{i.anserStatus === 'Y' && (
A
-
+
+ {textLineBreaks(i.anserContent)}
+
)}
>
@@ -88,16 +116,91 @@ export default function UserInquiryContainer() {
});
};
- // 1:1 문의하기 Modal handler
+ // 1:1 문의/수정 Modal handler
const handlerInquiryModal = qnaSno => {
if (!isInquiryModalOpen && qnaSno) {
- dispatch(ADMIN_DETAIL.request(qnaSno));
+ dispatch(Actions.ADMIN_DETAIL.request(qnaSno));
} else {
- dispatch(ADMIN_DETAIL_INITAL());
+ dispatch(Actions.ADMIN_DETAIL_INITAL());
+ setInquiryForm({
+ category: '칭찬',
+ contact: '',
+ title: '',
+ content: ''
+ });
}
setIsInquiryModalOpen(!isInquiryModalOpen);
};
+ // 문의 등록 Form value change handler
+ const handlerChangeInquiryForm = useCallback(
+ (type, val) => {
+ if (type === 'contact') {
+ const phoneNumber = val.replace(/[^0-9]/g, '');
+ setInquiryForm({ ...inquiryForm, [type]: phoneNumber });
+ } else {
+ setInquiryForm({ ...inquiryForm, [type]: val });
+ }
+ },
+ [inquiryForm]
+ );
+
+ // 문의 등록 event handler
+ const handlerSubmitInquiryForm = () => {
+ const { category, title, content, contact } = inquiryForm;
+
+ if (!contact) {
+ setValidationModal({
+ ...validationModal,
+ errorType: {
+ title: '필수값 입력 오류',
+ isOpen: true,
+ desc: '연락처를 입력해주세요.'
+ }
+ });
+ return;
+ } else if (!title) {
+ setValidationModal({
+ ...validationModal,
+ errorType: {
+ title: '필수값 입력 오류',
+ isOpen: true,
+ desc: '제목을 입력해주세요.'
+ }
+ });
+ return;
+ } else if (!content) {
+ setValidationModal({
+ ...validationModal,
+ errorType: {
+ title: '필수값 입력 오류',
+ isOpen: true,
+ desc: '내용을 입력해주세요.'
+ }
+ });
+ return;
+ } else if (content.length > 300) {
+ setValidationModal({
+ ...validationModal,
+ errorType: {
+ title: '필수값 입력 오류',
+ isOpen: true,
+ desc: '300자 이하로 작성해주세요.'
+ }
+ });
+ return;
+ }
+
+ let form = new FormData();
+ form.append('category', category);
+ form.append('contact', contact);
+ form.append('title', title);
+ form.append('content', content);
+
+ dispatch(Actions.USER_INQUIRY.request(form));
+ setIsInquiryModalOpen(false);
+ };
+
return (
@@ -119,6 +222,33 @@ export default function UserInquiryContainer() {
isInquiryModalOpen={isInquiryModalOpen}
handlerInquiryModal={handlerInquiryModal}
detail={detail}
+ handlerChangeInquiryForm={handlerChangeInquiryForm}
+ handlerSubmitInquiryForm={handlerSubmitInquiryForm}
+ memberName={memberName}
+ inquiryForm={inquiryForm}
+ />
+
+ {
+ setValidationModal({
+ ...validationModal,
+ successType: {
+ ...val
+ }
+ });
+ }}
+ />
+ {
+ setValidationModal({
+ ...validationModal,
+ errorType: {
+ ...val
+ }
+ });
+ }}
/>
);
diff --git a/src/modules/cstmrService/inquiry/action/index.ts b/src/modules/cstmrService/inquiry/action/index.ts
index 90d6526..0e7ebd9 100644
--- a/src/modules/cstmrService/inquiry/action/index.ts
+++ b/src/modules/cstmrService/inquiry/action/index.ts
@@ -8,7 +8,8 @@ import {
IQnaAdminAnswer,
IQnaAdminFileDown,
IQnaUserList,
- IQnaUserSearch
+ IQnaUserSearch,
+ IQnaUserInquiry
} from '../model';
// 관리자 목록 조회
@@ -44,6 +45,11 @@ const USER_LIST_REQUEST = 'cstmrService/qna/USER_LIST_REQUEST';
const USER_LIST_SUCCESS = 'cstmrService/qna/USER_LIST_SUCCESS';
const USER_LIST_FAILURE = 'cstmrService/qna/USER_LIST_FAILURE';
+// 사용자 문의 등록
+const USER_INQUIRY_REQUEST = 'cstmrService/qna/USER_INQUIRY_REQUEST';
+const USER_INQUIRY_SUCCESS = 'cstmrService/qna/USER_INQUIRY_SUCCESS';
+const USER_INQUIRY_FAILURE = 'cstmrService/qna/USER_INQUIRY_FAILURE';
+
export const ADMIN_LIST = createAsyncAction(
ADMIN_LIST_REQUEST,
ADMIN_LIST_SUCCESS,
@@ -91,6 +97,12 @@ export const USER_LIST = createAsyncAction(
USER_LIST_FAILURE
)
();
+export const USER_INQUIRY = createAsyncAction(
+ USER_INQUIRY_REQUEST,
+ USER_INQUIRY_SUCCESS,
+ USER_INQUIRY_FAILURE
+)();
+
const actions = {
ADMIN_LIST,
ADMIN_DETAIL,
@@ -98,7 +110,8 @@ const actions = {
ADMIN_ANSWER,
ADMIN_FILE_DOWN,
ADMIN_DELETE,
- USER_LIST
+ USER_LIST,
+ USER_INQUIRY
};
export type QnaAction = ActionType;
diff --git a/src/modules/cstmrService/inquiry/apis/index.ts b/src/modules/cstmrService/inquiry/apis/index.ts
index 154af66..622b2a2 100644
--- a/src/modules/cstmrService/inquiry/apis/index.ts
+++ b/src/modules/cstmrService/inquiry/apis/index.ts
@@ -1,6 +1,6 @@
import axios from '../../../utils/customAxiosUtil';
import qs from 'qs';
-import { IQnaUserSearch } from '../model';
+import { IQnaUserInquiry, IQnaUserSearch } from '../model';
export const qnaAPI = {
adminList: async (data: {
@@ -61,5 +61,12 @@ export const qnaAPI = {
});
return await axios.get(`api/cns/qna/user${queryString}`);
+ },
+ userInquiry: async (data: IQnaUserInquiry) => {
+ return await axios.post('api/cns/qna', data, {
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ });
}
};
diff --git a/src/modules/cstmrService/inquiry/model/index.ts b/src/modules/cstmrService/inquiry/model/index.ts
index 13ea334..c55d788 100644
--- a/src/modules/cstmrService/inquiry/model/index.ts
+++ b/src/modules/cstmrService/inquiry/model/index.ts
@@ -89,6 +89,13 @@ export interface IQnaUserSearch {
word: string;
}
+export interface IQnaUserInquiry {
+ category: string;
+ title: string;
+ contact: string;
+ content: string;
+}
+
export const initalState = {
adminList: [],
adminDetail: {
diff --git a/src/modules/cstmrService/inquiry/sagas/index.ts b/src/modules/cstmrService/inquiry/sagas/index.ts
index 9db5d9e..74aa508 100644
--- a/src/modules/cstmrService/inquiry/sagas/index.ts
+++ b/src/modules/cstmrService/inquiry/sagas/index.ts
@@ -1,6 +1,10 @@
import { call, put, takeEvery } from '@redux-saga/core/effects';
import { ActionType } from 'typesafe-actions';
-import { DELETE_MESSAGE, HOST } from '../../../../configs/constants';
+import {
+ DELETE_MESSAGE,
+ HOST,
+ SAVE_MESSAGE
+} from '../../../../configs/constants';
import * as MessageActions from '../../../comn/message/actions/comnMessageAction';
import * as Actions from '../action';
import * as Apis from '../apis';
@@ -155,7 +159,7 @@ function* userListSaga(action: ActionType) {
try {
const payload = action.payload;
const res = yield call(Apis.qnaAPI.userList, payload);
- const { data, count, errorCode } = res;
+ const { data, errorCode } = res;
if (errorCode) {
// 오류메시지 호출
@@ -176,6 +180,45 @@ function* userListSaga(action: ActionType) {
}
}
+function* userInquirySaga(
+ action: ActionType
+) {
+ try {
+ const payload = action.payload;
+ const res = yield call(Apis.qnaAPI.userInquiry, payload);
+ const { errorCode, data } = res;
+
+ if (errorCode) {
+ // 오류메시지 호출
+ yield put(
+ MessageActions.IS_ERROR({
+ errorCode: errorCode,
+ errorMessage: '처리중 오류가 발생하였습니다',
+ isHistoryBack: false,
+ isRefresh: false
+ })
+ );
+ }
+
+ if (data) {
+ yield put(
+ MessageActions.IS_MESSAGE({
+ messageCode: SAVE_MESSAGE.code,
+ message: SAVE_MESSAGE.message,
+ isHistoryBack: false,
+ isRefresh: false
+ })
+ );
+ }
+ yield put(
+ Actions.USER_LIST.request({ category: '', searchType: '', word: '' })
+ );
+ // yield put(Actions.USER_INQUIRY.success(data));
+ } catch (error) {
+ yield put(Actions.ADMIN_ANSWER.failure(error));
+ }
+}
+
export function* qnaSaga() {
yield takeEvery(Actions.ADMIN_LIST.request, adminListSaga);
yield takeEvery(Actions.ADMIN_DETAIL.request, adminDetailSaga);
@@ -183,4 +226,5 @@ export function* qnaSaga() {
yield takeEvery(Actions.ADMIN_FILE_DOWN.request, adminFileDownSaga);
yield takeEvery(Actions.ADMIN_DELETE.request, adminDeleteSaga);
yield takeEvery(Actions.USER_LIST.request, userListSaga);
+ yield takeEvery(Actions.USER_INQUIRY.request, userInquirySaga);
}
diff --git a/src/views/cstmrService/InquiryView.js b/src/views/cstmrService/InquiryView.js
index 2e0c47e..c1cf70c 100644
--- a/src/views/cstmrService/InquiryView.js
+++ b/src/views/cstmrService/InquiryView.js
@@ -17,7 +17,7 @@ function InquiryView() {
{user?.authId !== 'USER' ? (
) : (
-
+
)}
>