김지은 11 months ago
parent
commit
5992c59aae
  1. 38
      src/components/cstmrService/inquiry/InquiryWrite.js
  2. 9
      src/components/laanc/map/LaancAreaMap.js
  3. 32
      src/components/laanc/map/LaancDrawControl.js
  4. 69
      src/containers/cstmrService/inquiry/UserInquiryContainer.js
  5. 14
      src/modules/cstmrService/inquiry/model/index.ts
  6. 4
      src/modules/laanc/sagas/laancSagas.ts

38
src/components/cstmrService/inquiry/InquiryWrite.js

@ -26,20 +26,11 @@ function InquiryWrite({
handlerSubmitInquiryForm, handlerSubmitInquiryForm,
memberName, memberName,
inquiryForm, inquiryForm,
handlerDeleteConfirmInquiry handlerDeleteConfirmInquiry,
fileInputRef,
handlerFileChange,
handlerFileClear
}) { }) {
const fileInputRef = useRef(null);
const [selectedFile, setSelectedFile] = useState(null);
const handleFileChange = event => {
const file = event.target.files[0];
setSelectedFile(file);
};
const handleFileClear = () => {
setSelectedFile(null);
};
return ( return (
<Modal <Modal
isOpen={isInquiryModalOpen} isOpen={isInquiryModalOpen}
@ -170,7 +161,7 @@ function InquiryWrite({
</Label> </Label>
<div <div
className={`custom-file ${ className={`custom-file ${
selectedFile ? 'file-selected' : '' inquiryForm.fileInfos.length > 0 ? 'file-selected' : ''
}`} }`}
> >
<Input <Input
@ -178,21 +169,22 @@ function InquiryWrite({
id='inputFile' id='inputFile'
name='' name=''
className='custom-file-input pal' className='custom-file-input pal'
onChange={e => handleFileChange(e)} onChange={e => handlerFileChange(e)}
ref={fileInputRef} ref={fileInputRef}
/> />
{/* 현재는 text만 바뀌는상태! input 초기화 작업해주세용 */} {/* 현재는 text만 바뀌는상태! input 초기화 작업해주세용 */}
{selectedFile && ( // Display the trash icon only if a file is selected {inquiryForm.fileInfos.length > 0 && ( // Display the trash icon only if a file is selected
<span className='custom-file-control'> <span className='custom-file-control'>
<X // Display a trash icon <X // Display a trash icon
className='clear-file-button' className='clear-file-button'
onClick={handleFileClear} onClick={() => handlerFileClear('edit')}
/> />
</span> </span>
)} )}
<Label for='inputFile' className='custom-file-label'> <Label for='inputFile' className='custom-file-label'>
{selectedFile {inquiryForm.fileInfos.length > 0
? selectedFile.name ? inquiryForm.fileInfos[0].fileName ||
inquiryForm.fileInfos[0].name
: '선택된 파일이 없습니다.'} : '선택된 파일이 없습니다.'}
</Label> </Label>
</div> </div>
@ -208,9 +200,11 @@ function InquiryWrite({
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<div className='pal-form-btn'> <div className='pal-form-btn'>
<Button color='danger' onClick={handlerDeleteConfirmInquiry}> {detail.createDt && (
삭제 <Button color='danger' onClick={handlerDeleteConfirmInquiry}>
</Button> 삭제
</Button>
)}
<Button color='secondary' onClick={() => handlerInquiryModal()}> <Button color='secondary' onClick={() => handlerInquiryModal()}>
취소 취소
</Button> </Button>

9
src/components/laanc/map/LaancAreaMap.js

@ -47,7 +47,6 @@ export default function LaancAreaMap({
const dispatch = useDispatch(); const dispatch = useDispatch();
const mapControl = useSelector(state => state.controlMapReducer); const mapControl = useSelector(state => state.controlMapReducer);
const { areaCoordList } = useSelector(state => state.flightState); const { areaCoordList } = useSelector(state => state.flightState);
const { inAirArea } = useSelector(state => state.flightState);
const [mapObject, setMapObject] = useState(); const [mapObject, setMapObject] = useState();
const [isMapLoad, setIsMapLoad] = useState(false); const [isMapLoad, setIsMapLoad] = useState(false);
@ -82,10 +81,6 @@ export default function LaancAreaMap({
setMode(mapControl.drawType); setMode(mapControl.drawType);
}, [mapControl.drawType]); }, [mapControl.drawType]);
// useEffect(() => {
// console.log(inAirArea, '--inairARea');
// }, [inAirArea]);
useEffect(() => { useEffect(() => {
if (areaCoordList && mapObject) { if (areaCoordList && mapObject) {
if ( if (
@ -301,11 +296,11 @@ export default function LaancAreaMap({
const handlerCoordinates = areaInfo => { const handlerCoordinates = areaInfo => {
const areaList = handlerAreaInfoToAreaList(areaInfo); const areaList = handlerAreaInfoToAreaList(areaInfo);
// dispatch(LaancAction.LAANC_ALTITUDE.request(areaList));
dispatch(LaancAction.LAANC_VALID_AREA.request(areaList));
if (areaInfo.areaType === 'LINE' || areaInfo.areaType === 'POLYGON') { if (areaInfo.areaType === 'LINE' || areaInfo.areaType === 'POLYGON') {
dispatch(FLIGHT_PLAN_AREA_BUFFER_LIST.request(areaList)); dispatch(FLIGHT_PLAN_AREA_BUFFER_LIST.request(areaList));
} else { } else {
dispatch(LaancAction.LAANC_ALTITUDE.request(areaList));
dispatch(LaancAction.LAANC_VALID_AREA.request(areaList));
setMapAreaCoordList(areaList); setMapAreaCoordList(areaList);
} }
}; };

32
src/components/laanc/map/LaancDrawControl.js

@ -14,11 +14,14 @@ import { drawTypeChangeAction } from '../../../modules/control/map/actions/contr
import MapboxDraw from '@mapbox/mapbox-gl-draw'; import MapboxDraw from '@mapbox/mapbox-gl-draw';
import { CircleMode } from 'mapbox-gl-draw-circle'; import { CircleMode } from 'mapbox-gl-draw-circle';
import axios from '../../../modules/utils/customAxiosUtil'; import axios from '../../../modules/utils/customAxiosUtil';
import * as LaancAction from '../../../modules/laanc/actions/laancActions';
export const LaancDrawControl = props => { export const LaancDrawControl = props => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const mapControl = useSelector(state => state.controlMapReducer); const mapControl = useSelector(state => state.controlMapReducer);
const { laancElev } = useSelector(state => state.laancState);
const drawObj = props.drawObj; const drawObj = props.drawObj;
const mapObject = props.mapObject; const mapObject = props.mapObject;
@ -32,6 +35,10 @@ export const LaancDrawControl = props => {
desc: '' desc: ''
}); });
// useEffect(() => {
// console.log(laancElev, '----elev');
// }, [laancElev]);
useEffect(() => { useEffect(() => {
const areaType = props.areaCoordList[0].areaType; const areaType = props.areaCoordList[0].areaType;
const drawType = mapControl.drawType; const drawType = mapControl.drawType;
@ -200,38 +207,28 @@ export const LaancDrawControl = props => {
const areaInfo = handlerSettingAreaInfo(coords, mode); const areaInfo = handlerSettingAreaInfo(coords, mode);
const areaList = props.handlerAreaInfoToAreaList(areaInfo); const areaList = props.handlerAreaInfoToAreaList(areaInfo);
let isBreak = false; let isBreak = false;
// 비행금지 구역 체크 // 비행금지 구역 체크
console.log('unableElev'); console.log('unableElev');
try { try {
const elev1 = await axios.post(`api/bas/laanc/valid/elev`, areaList); const elev1 = await axios.post(`api/bas/laanc/valid/elev`, areaList);
dispatch(LaancAction.LAANC_ALTITUDE.success(elev1.data));
const elev2 = []; const elev2 = [];
if (mode === 'CIRCLE') { const formatCoords = mode === 'CIRCLE' ? [coords] : coords;
const point = mapObject.project(coords); for (let i = 0; i < formatCoords.length; i++) {
const point = mapObject.project(formatCoords[i]);
const maine = mapObject.queryRenderedFeatures(point, { const maine = mapObject.queryRenderedFeatures(point, {
layers: ['maine'] layers: ['maine']
}); });
if (maine.length > 0) { if (maine.length > 0) {
if (maine[0].properties.description.includes('김포공항 비행불가')) { if (maine[0].properties.description.includes('김포공항 비행불가')) {
elev2.push(maine[0]); elev2.push(maine[0]);
isBreak = true; isBreak = true;
} break;
}
} else {
for (let i = 0; i < coords.length; i++) {
const point = mapObject.project(coords[i]);
const maine = mapObject.queryRenderedFeatures(point, {
layers: ['maine']
});
if (maine.length > 0) {
if (maine[0].properties.description.includes('김포공항 비행불가')) {
elev2.push(maine[0]);
isBreak = true;
break;
}
} }
} }
} }
@ -239,6 +236,7 @@ export const LaancDrawControl = props => {
if (elev1.data[0] === 0 || elev2.length > 0) isBreak = true; if (elev1.data[0] === 0 || elev2.length > 0) isBreak = true;
} catch (error) { } catch (error) {
alert('에러 발생'); alert('에러 발생');
return;
} }
if (isBreak) { if (isBreak) {

69
src/containers/cstmrService/inquiry/UserInquiryContainer.js

@ -2,7 +2,7 @@ import { Button, Badge } from 'reactstrap';
import AppCollapse from '@components/app-collapse'; import AppCollapse from '@components/app-collapse';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import * as Actions from '../../../modules/cstmrService/inquiry/action'; import * as Actions from '../../../modules/cstmrService/inquiry/action';
import { Fragment, useCallback, useEffect, useState } from 'react'; import { Fragment, useCallback, useEffect, useRef, useState } from 'react';
import moment from 'moment'; import moment from 'moment';
import InquiryWrite from '../../../components/cstmrService/inquiry/InquiryWrite'; import InquiryWrite from '../../../components/cstmrService/inquiry/InquiryWrite';
import { InfoModal } from '../../../components/modal/InfoModal'; import { InfoModal } from '../../../components/modal/InfoModal';
@ -15,13 +15,16 @@ export default function UserInquiryContainer({ memberName }) {
state => state.qnaState state => state.qnaState
); );
const fileInputRef = useRef(null);
const [isInquiryModalOpen, setIsInquiryModalOpen] = useState(false); const [isInquiryModalOpen, setIsInquiryModalOpen] = useState(false);
const [inquiryForm, setInquiryForm] = useState({ const [inquiryForm, setInquiryForm] = useState({
category: '칭찬', category: '칭찬',
contact: '', contact: '',
title: '', title: '',
content: '' content: '',
fileInfos: []
}); });
const [validationModal, setValidationModal] = useState({ const [validationModal, setValidationModal] = useState({
errorType: { errorType: {
isOpen: false, isOpen: false,
@ -129,7 +132,8 @@ export default function UserInquiryContainer({ memberName }) {
category: '칭찬', category: '칭찬',
contact: '', contact: '',
title: '', title: '',
content: '' content: '',
fileInfos: []
}); });
} }
setIsInquiryModalOpen(!isInquiryModalOpen); setIsInquiryModalOpen(!isInquiryModalOpen);
@ -148,9 +152,25 @@ export default function UserInquiryContainer({ memberName }) {
[inquiryForm] [inquiryForm]
); );
const handlerFileChange = e => {
const file = e.target.files[0];
setInquiryForm({
...inquiryForm,
fileInfos: [file]
});
};
const handlerFileClear = () => {
setInquiryForm({
...inquiryForm,
fileInfos: []
});
};
// 문의 등록 event handler // 문의 등록 event handler
const handlerSubmitInquiryForm = type => { const handlerSubmitInquiryForm = type => {
const { category, title, content, contact, qnaSno } = inquiryForm; const { category, title, content, contact, fileInfos, qnaSno } =
inquiryForm;
if (!contact) { if (!contact) {
setValidationModal({ setValidationModal({
@ -192,6 +212,34 @@ export default function UserInquiryContainer({ memberName }) {
} }
}); });
return; return;
} else if (fileInfos.length > 0) {
const allowedExtensions = ['jpg', 'png', 'jpeg', 'gif'];
const fileExtension = fileInfos[0].name.split('.').pop().toLowerCase();
const maxFileSize = 3 * 1024 * 1024; // 3MB
if (!allowedExtensions.includes(fileExtension)) {
setValidationModal({
...validationModal,
errorType: {
title: '파일 형식 오류',
isOpen: true,
desc: '파일 형식은 jpg, png, jpeg, gif 형식만 가능합니다.'
}
});
return;
}
if (fileInfos[0].size > maxFileSize) {
setValidationModal({
...validationModal,
errorType: {
title: '파일 크기 오류',
isOpen: true,
desc: '파일 크기는 3MB를 초과할 수 없습니다.'
}
});
return;
}
} }
if (type === 'post') { if (type === 'post') {
@ -201,6 +249,10 @@ export default function UserInquiryContainer({ memberName }) {
form.append('title', title); form.append('title', title);
form.append('content', content); form.append('content', content);
if (fileInfos.length > 0) {
form.append('files', fileInfos[0]);
}
dispatch(Actions.USER_INQUIRY.request(form)); dispatch(Actions.USER_INQUIRY.request(form));
} else if (type === 'edit') { } else if (type === 'edit') {
dispatch( dispatch(
@ -249,13 +301,16 @@ export default function UserInquiryContainer({ memberName }) {
<InquiryWrite <InquiryWrite
isInquiryModalOpen={isInquiryModalOpen} isInquiryModalOpen={isInquiryModalOpen}
handlerInquiryModal={handlerInquiryModal}
detail={detail} detail={detail}
inquiryForm={inquiryForm}
memberName={memberName}
fileInputRef={fileInputRef}
handlerChangeInquiryForm={handlerChangeInquiryForm} handlerChangeInquiryForm={handlerChangeInquiryForm}
handlerSubmitInquiryForm={handlerSubmitInquiryForm} handlerSubmitInquiryForm={handlerSubmitInquiryForm}
memberName={memberName} handlerInquiryModal={handlerInquiryModal}
inquiryForm={inquiryForm}
handlerDeleteConfirmInquiry={handlerDeleteConfirmInquiry} handlerDeleteConfirmInquiry={handlerDeleteConfirmInquiry}
handlerFileChange={handlerFileChange}
handlerFileClear={handlerFileClear}
/> />
<InfoModal <InfoModal

14
src/modules/cstmrService/inquiry/model/index.ts

@ -28,6 +28,7 @@ export interface IQnaAdminSearch {
export interface IQnaFiles { export interface IQnaFiles {
fileSno: number; fileSno: number;
fileGroupNo: number;
downloadUrl: string; downloadUrl: string;
fileName: string; fileName: string;
} }
@ -95,6 +96,15 @@ export interface IQnaUserInquiry {
title: string; title: string;
contact: string; contact: string;
content: string; content: string;
files: IQnaUserFileUpload[];
}
export interface IQnaUserFileUpload {
lastModified: number;
lastModifiedDate: Date;
name: string;
type: string;
webkitRelativePath: string;
} }
export interface IQnaUserDetail { export interface IQnaUserDetail {
@ -115,7 +125,7 @@ export interface IQnaUserDetail {
createDt: string; createDt: string;
updateUserId: string; updateUserId: string;
updateDt: string; updateDt: string;
files: IQnaFiles[]; fileInfos: IQnaFiles[];
} }
export interface IQnaUserUpdate extends IQnaUserInquiry { export interface IQnaUserUpdate extends IQnaUserInquiry {
@ -163,6 +173,6 @@ export const initalState = {
createDt: '', createDt: '',
updateUserId: '', updateUserId: '',
updateDt: '', updateDt: '',
files: [] fileInfos: []
} }
}; };

4
src/modules/laanc/sagas/laancSagas.ts

@ -120,8 +120,8 @@ function* postValidElevSaga(
) { ) {
try { try {
const deail = action.payload; const deail = action.payload;
const res = yield call(Apis.laancApi.postValidElev, deail); // const res = yield call(Apis.laancApi.postValidElev, deail);
yield put(Actions.LAANC_ALTITUDE.success(res.data)); // yield put(Actions.LAANC_ALTITUDE.success(detail));
} catch (error) { } catch (error) {
yield put( yield put(
MessageActions.IS_ERROR({ MessageActions.IS_ERROR({

Loading…
Cancel
Save