diff --git a/.env.development b/.env.development index cfc50e71..f35f6208 100644 --- a/.env.development +++ b/.env.development @@ -1,6 +1,8 @@ -NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" +NEXT_PUBLIC_API_SERVER_PATH="https://dev-api.hanasys.jp" -NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000" +NEXT_PUBLIC_HOST_URL="//1.248.227.176:4000" + +NEXT_PUBLIC_API_HOST_URL="http://1.248.227.176:5000" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" @@ -8,4 +10,18 @@ SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS" NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/login/autoLogin" -NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" \ No newline at end of file +NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" + +# 테스트용 +# AWS_REGION="ap-northeast-2" +# AMPLIFY_BUCKET="interplug" +# AWS_ACCESS_KEY_ID="AKIAVWMWJCUXFHEAZ4FR" +# AWS_SECRET_ACCESS_KEY="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" +# NEXT_PUBLIC_AWS_S3_BASE_URL="https://interplug.s3.ap-northeast-2.amazonaws.com" + +# 실제 일본 서버 +AWS_REGION="ap-northeast-1" +AMPLIFY_BUCKET="files.hanasys.jp" +AWS_ACCESS_KEY_ID="AKIA3K4QWLZHFZRJOM2E" +AWS_SECRET_ACCESS_KEY="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" +NEXT_PUBLIC_AWS_S3_BASE_URL="//files.hanasys.jp" \ No newline at end of file diff --git a/.env.production b/.env.production index 09bb27d3..b2d50cdd 100644 --- a/.env.production +++ b/.env.production @@ -1,6 +1,8 @@ NEXT_PUBLIC_API_SERVER_PATH="https://api.hanasys.jp/" -NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000" +NEXT_PUBLIC_HOST_URL="//1.248.227.176:4000" + +NEXT_PUBLIC_API_HOST_URL="https://www.hanasys.jp/" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" @@ -10,4 +12,10 @@ NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secr # NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order.q-cells.jp/eos/login/autoLogin" # NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="https://q-musubi.q-cells.jp/qm/login/autoLogin" NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/login/autoLogin" -NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" \ No newline at end of file +NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" + +AWS_REGION="ap-northeast-2" +AMPLIFY_BUCKET="interplug" +AWS_ACCESS_KEY_ID="AKIAVWMWJCUXFHEAZ4FR" +AWS_SECRET_ACCESS_KEY="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" +NEXT_PUBLIC_AWS_S3_BASE_URL="//files.hanasys.jp" \ No newline at end of file diff --git a/.gitmessage.txt b/.gitmessage.txt new file mode 100644 index 00000000..07932f22 --- /dev/null +++ b/.gitmessage.txt @@ -0,0 +1,3 @@ +[일감번호] : [제목] + +[작업내용] : \ No newline at end of file diff --git a/package.json b/package.json index d9c1af06..bbddf9ad 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "serve": "node server.js" }, "dependencies": { + "@aws-sdk/client-s3": "^3.772.0", "ag-grid-react": "^32.0.2", "axios": "^1.7.8", "big.js": "^6.2.2", @@ -24,7 +25,7 @@ "js-cookie": "^3.0.5", "mathjs": "^13.0.2", "mssql": "^11.0.1", - "next": "14.2.26", + "next": "14.2.28", "next-international": "^1.2.4", "react": "^18", "react-chartjs-2": "^5.2.0", @@ -38,6 +39,7 @@ "react-responsive-modal": "^6.4.2", "react-select": "^5.8.1", "recoil": "^0.7.7", + "sharp": "^0.33.5", "sqlite": "^5.1.1", "sqlite3": "^5.1.7", "sweetalert2": "^11.14.1", diff --git a/qcast3.database.sqlite b/qcast3.database.sqlite index c0c43e6f..6a7a809a 100644 Binary files a/qcast3.database.sqlite and b/qcast3.database.sqlite differ diff --git a/src/app/api/image/cad/route.js b/src/app/api/image/cad/route.js new file mode 100644 index 00000000..b7d64a50 --- /dev/null +++ b/src/app/api/image/cad/route.js @@ -0,0 +1,69 @@ +import { NextResponse } from 'next/server' +import { S3Client, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3' + +const Bucket = process.env.AMPLIFY_BUCKET +const s3 = new S3Client({ + region: process.env.AWS_REGION, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + }, +}) + +const uploadImage = async (file) => { + const Body = Buffer.from(await file.arrayBuffer()) + const Key = `cads/${file.name}` + const ContentType = file.ContentType + + await s3.send( + new PutObjectCommand({ + Bucket, + Key, + Body, + ContentType, + }), + ) + + return { + filePath: `https://${process.env.AMPLIFY_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${Key}`, + fileName: Key, + } +} + +export async function POST(req) { + try { + const formData = await req.formData() + const file = formData.get('file') + + const result = await uploadImage(file) + + return NextResponse.json(result) + } catch (error) { + console.error(error) + return NextResponse.json({ error: 'Failed to upload image' }, { status: 500 }) + } +} + +export async function DELETE(req) { + try { + const searchParams = req.nextUrl.searchParams + const Key = `cads/${searchParams.get('fileName')}` + console.log('🚀 ~ DELETE ~ Key:', Key) + + if (!Key) { + return NextResponse.json({ error: 'fileName parameter is required' }, { status: 400 }) + } + + await s3.send( + new DeleteObjectCommand({ + Bucket, + Key, + }), + ) + + return NextResponse.json({ message: '이미지 삭제 성공' }, { status: 200 }) + } catch (error) { + console.error('S3 Delete Error:', error) + return NextResponse.json({ error: 'Failed to delete image' }, { status: 500 }) + } +} diff --git a/src/app/api/image/canvas/route.js b/src/app/api/image/canvas/route.js new file mode 100644 index 00000000..0a4d0be2 --- /dev/null +++ b/src/app/api/image/canvas/route.js @@ -0,0 +1,133 @@ +import { NextResponse } from 'next/server' +import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3' +import sharp from 'sharp' +import { v4 as uuidv4 } from 'uuid' +const Bucket = process.env.AMPLIFY_BUCKET +const s3 = new S3Client({ + region: process.env.AWS_REGION, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + }, +}) + +const checkArea = (obj) => { + const { width, height, left, top } = obj + + if (left < 0 || top < 0 || width > 1600 || height > 1000) { + return false + } + + return true +} + +const cropImage = async (Key, width, height, left, top) => { + try { + const checkResult = checkArea({ width, height, left, top }) + + // Get the image from S3 + const { Body } = await s3.send( + new GetObjectCommand({ + Bucket, + Key, + }), + ) + + // Convert stream to buffer + const chunks = [] + for await (const chunk of Body) { + chunks.push(chunk) + } + const imageBuffer = Buffer.concat(chunks) + + let processedImage + if (!checkResult) { + processedImage = await sharp(imageBuffer).toBuffer() + } else { + processedImage = await sharp(imageBuffer) + .extract({ + width: parseInt(width), + height: parseInt(height), + left: parseInt(left), + top: parseInt(top), + }) + .png() + .toBuffer() + } + return processedImage + } catch (error) { + console.error('Error processing image:', error) + throw error + } +} + +export async function POST(req) { + try { + const formData = await req.formData() + const file = formData.get('file') + const objectNo = formData.get('objectNo') + const planNo = formData.get('planNo') + const type = formData.get('type') + const width = formData.get('width') + const height = formData.get('height') + const left = formData.get('left') + const top = formData.get('top') + + const OriginalKey = `Drawing/${uuidv4()}` + + /** + * 원본 이미지를 우선 저장한다. + * 이미지 이름이 겹지는 현상을 방지하기 위해 uuid 를 사용한다. + */ + await s3.send( + new PutObjectCommand({ + Bucket, + Key: OriginalKey, + Body: Buffer.from(await file.arrayBuffer()), + ContentType: 'image/png', + }), + ) + + /** + * 저장된 원본 이미지를 기준으로 크롭여부를 결정하여 크롭 이미지를 저장한다. + */ + const bufferImage = await cropImage(OriginalKey, width, height, left, top) + + /** + * 크롭 이미지 이름을 결정한다. + */ + const Key = `Drawing/${objectNo}_${planNo}_${type}.png` + + /** + * 크롭이 완료된 이미지를 업로드한다. + */ + await s3.send( + new PutObjectCommand({ + Bucket, + Key, + Body: bufferImage, + ContentType: 'image/png', + }), + ) + + /** + * 크롭이미지 저장이 완료되면 원본 이미지를 삭제한다. + */ + await s3.send( + new DeleteObjectCommand({ + Bucket, + Key: OriginalKey, + }), + ) + + const result = { + filePath: `https://${process.env.AMPLIFY_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${Key}`, + fileName: Key, + } + + return NextResponse.json(result) + } catch (error) { + console.error('Error in POST:', error) + return NextResponse.json({ error: 'Failed to process and upload image' }, { status: 500 }) + } +} diff --git a/src/app/api/image/map/route.js b/src/app/api/image/map/route.js new file mode 100644 index 00000000..0cc76c02 --- /dev/null +++ b/src/app/api/image/map/route.js @@ -0,0 +1,78 @@ +import { NextResponse } from 'next/server' +import { S3Client, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3' + +const Bucket = process.env.AMPLIFY_BUCKET +const s3 = new S3Client({ + region: process.env.AWS_REGION, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + }, +}) + +export async function GET(req) { + try { + const searchParams = req.nextUrl.searchParams + const q = searchParams.get('q') + const fileNm = searchParams.get('fileNm') + const zoom = searchParams.get('zoom') + + /** 구글 맵을 이미지로 변경하기 위한 API */ + const API_KEY = 'AIzaSyDO7nVR1N_D2tKy60hgGFavpLaXkHpiHpc' + const targetUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${q}&zoom=${zoom}&maptype=satellite&size=640x640&scale=1&key=${API_KEY}` + const decodeUrl = decodeURIComponent(targetUrl) + + /** 구글 맵을 이미지로 변경하기 위한 API 호출 */ + const response = await fetch(decodeUrl) + const data = await response.arrayBuffer() + // const buffer = Buffer.from(data) + + /** 변경된 이미지를 S3에 업로드 */ + const Body = Buffer.from(data) + const Key = `maps/${fileNm}` + const ContentType = 'image/png' + + await s3.send( + new PutObjectCommand({ + Bucket, + Key, + Body, + ContentType, + }), + ) + + const result = { + filePath: `https://${process.env.AMPLIFY_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${Key}`, + fileName: Key, + } + + return NextResponse.json(result) + } catch (error) { + console.error(error) + return NextResponse.json({ error: 'Failed to upload image' }, { status: 500 }) + } +} + +export async function DELETE(req) { + try { + const searchParams = req.nextUrl.searchParams + const Key = `maps/${searchParams.get('fileName')}` + console.log('🚀 ~ DELETE ~ Key:', Key) + + if (!Key) { + return NextResponse.json({ error: 'fileName parameter is required' }, { status: 400 }) + } + + await s3.send( + new DeleteObjectCommand({ + Bucket, + Key, + }), + ) + + return NextResponse.json({ message: '이미지 삭제 성공' }, { status: 200 }) + } catch (error) { + console.error('S3 Delete Error:', error) + return NextResponse.json({ error: 'Failed to delete image' }, { status: 500 }) + } +} diff --git a/src/app/api/image/upload/route.js b/src/app/api/image/upload/route.js new file mode 100644 index 00000000..4d875257 --- /dev/null +++ b/src/app/api/image/upload/route.js @@ -0,0 +1,72 @@ +import { NextResponse } from 'next/server' +import { S3Client, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3' + +const Bucket = process.env.AMPLIFY_BUCKET +const s3 = new S3Client({ + region: process.env.AWS_REGION, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + }, +}) + +const uploadImage = async (file) => { + const Body = Buffer.from(await file.arrayBuffer()) + const Key = `upload/${file.name}` + const ContentType = file.ContentType + + await s3.send( + new PutObjectCommand({ + Bucket, + Key, + Body, + ContentType, + }), + ) + + return { + filePath: `https://${process.env.AMPLIFY_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${Key}`, + fileName: Key, + } +} + +export async function POST(req) { + try { + const formData = await req.formData() + const file = formData.get('file') + + const result = await uploadImage(file) + result.message = '이미지 업로드 성공' + + return NextResponse.json(result) + } catch (error) { + console.error(error) + return NextResponse.json({ error: 'Failed to upload image' }, { status: 500 }) + } +} + +export async function DELETE(req) { + try { + const searchParams = req.nextUrl.searchParams + const fileName = searchParams.get('fileName') + + if (!fileName) { + return NextResponse.json({ error: 'fileName parameter is required' }, { status: 400 }) + } + + const Key = `upload/${fileName}` + console.log('🚀 ~ DELETE ~ Key:', Key) + + await s3.send( + new DeleteObjectCommand({ + Bucket, + Key, + }), + ) + + return NextResponse.json({ message: '이미지 삭제 성공' }, { status: 200 }) + } catch (error) { + console.error('S3 Delete Error:', error) + return NextResponse.json({ error: 'Failed to delete image' }, { status: 500 }) + } +} diff --git a/src/common/common.js b/src/common/common.js index abda5acd..0fe0a002 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -125,6 +125,11 @@ export const TRESTLE_MATERIAL = { BRACKET: 'bracket', } +export const MODULE_SETUP_TYPE = { + LAYOUT: 'layout', + AUTO: 'auto', +} + export const SAVE_KEY = [ 'selectable', 'name', @@ -203,6 +208,8 @@ export const SAVE_KEY = [ 'fontWeight', 'dormerAttributes', 'toFixed', + 'startPoint', + 'endPoint', 'isSortedPoints', ] diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 8ce54402..7237e056 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -60,7 +60,7 @@ export default function Estimate({}) { const [cableItemList, setCableItemList] = useState([]) //케이블 리스트 const [cableItem, setCableItem] = useState('') //케이블 선택값 - + const [cableDbItem, setCableDbItem] = useState('') //케이블 선택값 const [startDate, setStartDate] = useState(new Date()) const singleDatePickerProps = { startDate, @@ -98,7 +98,7 @@ export default function Estimate({}) { } const initEstimate = (currPid = currentPid) => { - console.log('🚀 ~ initEstimate ~ currPid:', currPid) + // console.log('🚀 ~ initEstimate ~ currPid:', currPid) closeAll() setObjectNo(objectRecoil.floorPlanObjectNo) @@ -117,6 +117,7 @@ export default function Estimate({}) { item.value = item.clRefChr1 item.label = item.clRefChr2 }) + // console.log(code2) setCableItemList(code2) } @@ -152,7 +153,7 @@ export default function Estimate({}) { } useEffect(() => { - console.log('🚀 ~ Estimate ~ selectedPlan:', selectedPlan) + // console.log('🚀 ~ Estimate ~ selectedPlan:', selectedPlan) if (selectedPlan) initEstimate(selectedPlan.planNo) }, [selectedPlan]) @@ -739,6 +740,18 @@ export default function Estimate({}) { setCableItem(value) } + /* 케이블 select 변경시 */ + const onChangeDisplayDoubleCableItem = (value, itemList) => { + itemList.map((item, index) => { + if (item.dispCableFlg === '1' && item.itemTpCd === 'M12') { + if (value !== '') { + onChangeDisplayItem(value, item.dispOrder, index, true) + } + } + }) + setCableDbItem(value) + } + // 아이템 자동완성 검색시 아이템 추가/변경시 const onChangeDisplayItem = (itemId, dispOrder, index, flag) => { const param = { @@ -1088,15 +1101,20 @@ export default function Estimate({}) { item.showSaleTotPrice = '0' } - if (item.dispCableFlg === '1' && item.itemTpCd !== 'M12') { + if (item.dispCableFlg === '1' ) { dispCableFlgCnt++ - setCableItem(item.itemId) + if(item.itemTpCd === 'M12') { + setCableDbItem(item.itemId) + }else{ + setCableItem(item.itemId) + } } } }) if (dispCableFlgCnt === 0) { setCableItem('100038') + setCableDbItem('100037') } let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0 @@ -1159,14 +1177,20 @@ export default function Estimate({}) { dispCableFlgCnt++ } - if (item.dispCableFlg === '1' && item.itemTpCd !== 'M12') { - setCableItem(item.itemId) + if (item.dispCableFlg === '1'){ + + if(item.itemTpCd === 'M12') { + setCableDbItem(item.itemId) + }else{ + setCableItem(item.itemId) + } } } }) if (dispCableFlgCnt === 0) { setCableItem('100038') + setCableDbItem('100037') } totals.vatPrice = totals.supplyPrice * 0.1 @@ -1227,6 +1251,7 @@ export default function Estimate({}) { if (dispCableFlgCnt === 0) { setCableItem('100038') + setCableDbItem('100037') } } }, [estimateContextState?.itemList, cableItemList]) @@ -1831,6 +1856,7 @@ export default function Estimate({}) {
+
{getMessage('estimate.detail.header.singleCable')}
+
+
+
+
{getMessage('estimate.detail.header.doubleCable')}
+
+
@@ -1927,7 +1976,7 @@ export default function Estimate({}) { onChangeSelect(item.dispOrder)} checked={!!selection.has(item.dispOrder)} /> diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index a471b5be..7b817f8f 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -2,7 +2,7 @@ import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' import { QLine } from '@/components/fabric/QLine' import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util' -import { calculateAngle, drawGabledRoof, drawRidgeRoof, drawShedRoof, toGeoJSON } from '@/util/qpolygon-utils' +import { calculateAngle, drawRidgeRoof, drawShedRoof, toGeoJSON } from '@/util/qpolygon-utils' import * as turf from '@turf/turf' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import Big from 'big.js' @@ -29,12 +29,13 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.texts = [] this.hips = [] this.ridges = [] - this.connectRidges = [] this.cells = [] this.innerLines = [] this.children = [] this.separatePolygon = [] this.toFixed = options.toFixed ?? 1 + this.baseLines = [] + // this.colorLines = [] // 소수점 전부 제거 points.forEach((point) => { @@ -217,6 +218,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { * @param settingModalFirstOptions */ drawHelpLine(settingModalFirstOptions) { + /* innerLines 초기화 */ + this.innerLines.forEach((line) => { + this.canvas.remove(line) + }) + this.canvas.renderAll() + let textMode = 'plane' const dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id @@ -246,12 +253,13 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { const hasShed = types.includes(LINE_TYPE.WALLLINE.SHED) // A형, B형 박공 지붕 - if ( + /* if ( (gableOdd.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableEven.every((type) => gableType.includes(type))) || (gableEven.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableOdd.every((type) => gableType.includes(type))) ) { drawGabledRoof(this.id, this.canvas, textMode) - } else if (hasShed) { + } else*/ + if (hasShed) { const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED) const areLinesParallel = function (line1, line2) { const angle1 = calculateAngle(line1.startPoint, line1.endPoint) diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index c98f686b..5aa0332e 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -12,7 +12,7 @@ import { usePlan } from '@/hooks/usePlan' import { useContextMenu } from '@/hooks/useContextMenu' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' import { currentMenuState } from '@/store/canvasAtom' -import { totalDisplaySelector } from '@/store/settingAtom' +import { roofMaterialsAtom, totalDisplaySelector } from '@/store/settingAtom' import { MENU, POLYGON_TYPE } from '@/common/common' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { QcastContext } from '@/app/QcastProvider' @@ -30,10 +30,40 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import { useEvent } from '@/hooks/useEvent' import { compasDegAtom } from '@/store/orientationAtom' +import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' +import { useMasterController } from '@/hooks/common/useMasterController' import { hotkeyStore } from '@/store/hotkeyAtom' import { usePopup } from '@/hooks/usePopup' export default function CanvasFrame() { + const [roofMaterials, setRoofMaterials] = useRecoilState(roofMaterialsAtom) + const { getRoofMaterialList } = useMasterController() + useEffect(() => { + async function initRoofMaterial() { + if (roofMaterials.length !== 0) { + return + } + const { data } = await getRoofMaterialList() + + const roofLists = data.map((item, idx) => ({ + ...item, + id: item.roofMatlCd, + name: item.roofMatlNm, + selected: idx === 0, + index: idx, + nameJp: item.roofMatlNmJp, + length: item.lenBase && parseInt(item.lenBase), + width: item.widBase && parseInt(item.widBase), + raft: item.raftBase && parseInt(item.raftBase), + layout: ['ROOF_ID_SLATE', 'ROOF_ID_SINGLE'].includes(item.roofMatlCd) ? ROOF_MATERIAL_LAYOUT.STAIRS : ROOF_MATERIAL_LAYOUT.PARALLEL, + hajebichi: item.roofPchBase && parseInt(item.roofPchBase), + pitch: item.pitch ? parseInt(item.pitch) : 4, + angle: item.angle ? parseInt(item.angle) : 21.8, + })) + setRoofMaterials(roofLists) + } + initRoofMaterial() + }, []) const canvasRef = useRef(null) const { canvas } = useCanvas('canvas') const { canvasLoadInit, gridInit } = useCanvasConfigInitialize() diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index 059e96aa..cce79df2 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -37,7 +37,7 @@ export default function CanvasLayout({ children }) { } + {currentCanvasPlan?.bgImageName && } diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index 9a09aa1e..a70b9a22 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -1,4 +1,4 @@ -import { POLYGON_TYPE } from '@/common/common' +import { POLYGON_TYPE, MODULE_SETUP_TYPE } from '@/common/common' import WithDraggable from '@/components/common/draggable/WithDraggable' import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation' import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement' @@ -331,10 +331,13 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { + - diff --git a/src/components/floor-plan/modal/basic/step/Placement.jsx b/src/components/floor-plan/modal/basic/step/Placement.jsx index 909f5229..ffb96d83 100644 --- a/src/components/floor-plan/modal/basic/step/Placement.jsx +++ b/src/components/floor-plan/modal/basic/step/Placement.jsx @@ -37,7 +37,7 @@ const Placement = forwardRef((props, refs) => { const resetModuleSetupOption = useResetRecoilState(moduleSetupOptionState) const [colspan, setColspan] = useState(1) - const [moduleRowColArray, setModuleRowColArray] = useRecoilState(moduleRowColArrayState) + const moduleRowColArray = useRecoilValue(moduleRowColArrayState) //모듈 배치면 생성 useEffect(() => { @@ -64,9 +64,9 @@ const Placement = forwardRef((props, refs) => { } }, []) - useEffect(() => { - console.log('moduleRowColArray', moduleRowColArray) - }, [moduleRowColArray]) + // useEffect(() => { + // console.log('moduleRowColArray', moduleRowColArray) + // }, [moduleRowColArray]) //최초 지입시 체크 useEffect(() => { @@ -180,8 +180,8 @@ const Placement = forwardRef((props, refs) => { ))} - {selectedModules.itemList && - selectedModules.itemList.map((item, index) => ( + {selectedModules?.itemList && + selectedModules?.itemList?.map((item, index) => (
@@ -329,22 +329,25 @@ const Placement = forwardRef((props, refs) => { {selectedModules && - selectedModules.itemList.map((item) => ( - + selectedModules.itemList?.map((item) => ( + // +
{item.itemNm}
))} + {colspan > 1 && {getMessage('modal.module.basic.setting.module.placement.max.rows.multiple')}} - {selectedModules.itemList.map((item) => ( - <> - {getMessage('modal.module.basic.setting.module.placement.max.row')} - {colspan > 1 && {getMessage('modal.module.basic.setting.module.placement.max.rows.multiple')}} - - ))} + {selectedModules && + selectedModules.itemList?.map((item) => ( + <> + {getMessage('modal.module.basic.setting.module.placement.max.row')} + {/* {colspan > 1 && {getMessage('modal.module.basic.setting.module.placement.max.rows.multiple')}} */} + + ))} @@ -356,10 +359,11 @@ const Placement = forwardRef((props, refs) => { {item.addRoof?.roofMatlNmJp}
- {moduleRowColArray[index]?.map((item) => ( + {moduleRowColArray[index]?.map((item, index2) => ( <> {item.moduleMaxRows} - {colspan > 1 && {item.mixModuleMaxRows}} + {/* {colspan > 1 && {item.mixModuleMaxRows}} */} + {colspan > 1 && index2 === moduleRowColArray[index].length - 1 && {item.maxRow}} ))} diff --git a/src/components/floor-plan/modal/basic/step/Trestle.jsx b/src/components/floor-plan/modal/basic/step/Trestle.jsx index b184670e..44a68236 100644 --- a/src/components/floor-plan/modal/basic/step/Trestle.jsx +++ b/src/components/floor-plan/modal/basic/step/Trestle.jsx @@ -92,7 +92,7 @@ const Trestle = forwardRef((props, ref) => { useEffect(() => { if (raftBaseList.length > 0) { - setSelectedRaftBase(raftBaseList.find((raft) => raft.clCode === trestleState?.raftBaseCd) ?? null) + setSelectedRaftBase(raftBaseList.find((raft) => raft.clCode === selectedRoof?.raft) ?? null) } else { setSelectedRaftBase(null) } @@ -124,8 +124,13 @@ const Trestle = forwardRef((props, ref) => { useEffect(() => { if (constructionList.length > 0) { - console.log(constructionList) setSelectedConstruction(constructionList.find((construction) => construction.constTp === trestleState?.construction?.constTp) ?? null) + if (constructionList.filter((construction) => construction.constPossYn === 'Y').length === 0) { + Swal.fire({ + title: getMessage('modal.module.basic.settting.module.error4', [selectedRoof?.nameJp]), // 시공법법을 선택해주세요. + icon: 'warning', + }) + } } else { setSelectedConstruction(null) } @@ -144,6 +149,19 @@ const Trestle = forwardRef((props, ref) => { return 'no-click' } + const onChangeLength = (e) => { + setLengthBase(e) + dispatch({ + type: 'SET_LENGTH', + roof: { + length: e, + moduleTpCd: selectedModules.itemTp ?? '', + roofMatlCd: selectedRoof?.roofMatlCd ?? '', + raft: selectedRaftBase?.clCode, + }, + }) + } + const onChangeRaftBase = (e) => { setSelectedRaftBase(e) dispatch({ @@ -151,7 +169,7 @@ const Trestle = forwardRef((props, ref) => { roof: { moduleTpCd: selectedModules.itemTp ?? '', roofMatlCd: selectedRoof?.roofMatlCd ?? '', - raftBaseCd: e.clCode, + raft: e.clCode, }, }) } @@ -163,7 +181,7 @@ const Trestle = forwardRef((props, ref) => { roof: { moduleTpCd: selectedModules.itemTp ?? '', roofMatlCd: selectedRoof?.roofMatlCd ?? '', - raftBaseCd: selectedRaftBase?.clCode, + raft: selectedRaftBase?.clCode, trestleMkrCd: e.trestleMkrCd, }, }) @@ -176,7 +194,7 @@ const Trestle = forwardRef((props, ref) => { roof: { moduleTpCd: selectedModules.itemTp ?? '', roofMatlCd: selectedRoof?.roofMatlCd ?? '', - raftBaseCd: selectedRaftBase?.clCode, + raft: selectedRaftBase?.clCode, trestleMkrCd: selectedTrestle.trestleMkrCd, constMthdCd: e.constMthdCd, }, @@ -190,7 +208,7 @@ const Trestle = forwardRef((props, ref) => { roof: { moduleTpCd: selectedModules.itemTp ?? '', roofMatlCd: selectedRoof?.roofMatlCd ?? '', - raftBaseCd: selectedRaftBase?.clCode, + raft: selectedRaftBase?.clCode, trestleMkrCd: selectedTrestle.trestleMkrCd, constMthdCd: selectedConstMthd.constMthdCd, roofBaseCd: e.roofBaseCd, @@ -211,7 +229,7 @@ const Trestle = forwardRef((props, ref) => { roof: { moduleTpCd: selectedModules.itemTp ?? '', roofMatlCd: selectedRoof?.roofMatlCd ?? '', - raftBaseCd: selectedRaftBase?.clCode, + raft: selectedRaftBase?.clCode, trestleMkrCd: selectedTrestle.trestleMkrCd, constMthdCd: selectedConstMthd.constMthdCd, roofBaseCd: selectedRoofBase.roofBaseCd, @@ -225,7 +243,8 @@ const Trestle = forwardRef((props, ref) => { snowGdPossYn: constructionList[index].snowGdPossYn, cvrYn: constructionList[index].cvrYn, mixMatlNo: selectedModules.mixMatlNo, - workingWidth: selectedRoof?.length?.toString() ?? '', + // workingWidth: selectedRoof?.length?.toString() ?? '', + workingWidth: lengthBase, }, }) @@ -242,11 +261,12 @@ const Trestle = forwardRef((props, ref) => { return { ...selectedRoof, hajebichi, - lenBase: lengthBase, + length: lengthBase, eavesMargin, ridgeMargin, kerabaMargin, roofIndex: selectedRoof.index, + raft: selectedRaftBase?.clCode, trestle: { hajebichi: hajebichi, length: lengthBase, @@ -283,6 +303,7 @@ const Trestle = forwardRef((props, ref) => { ridgeMargin, kerabaMargin, roofIndex: roof.index, + raft: selectedRaftBase?.clCode, trestle: { length: lengthBase, hajebichi: hajebichi, @@ -329,7 +350,7 @@ const Trestle = forwardRef((props, ref) => { } if (!roof.trestle?.roofBaseCd) { Swal.fire({ - title: getMessage('modal.module.basic.settting.module.error3', [roof.nameJp]), // 지붕밑바탕탕을 선택해주세요. + title: getMessage('modal.module.basic.settting.module.error3', [roof.nameJp]), // 지붕밑바탕을 선택해주세요. icon: 'warning', }) result = false @@ -337,7 +358,7 @@ const Trestle = forwardRef((props, ref) => { } if (!roof.construction?.constTp) { Swal.fire({ - title: getMessage('modal.module.basic.settting.module.error4', [roof.nameJp]), // 시공법법을 선택해주세요. + title: getMessage('modal.module.basic.settting.module.error12', [roof.nameJp]), // 시공법법을 선택해주세요. icon: 'warning', }) result = false @@ -355,7 +376,7 @@ const Trestle = forwardRef((props, ref) => { } } if (['C', 'R'].includes(roof.raftAuth)) { - if (!roof?.raftBaseCd) { + if (!roof?.raft) { Swal.fire({ title: getMessage('modal.module.basic.settting.module.error6', [roof.nameJp]), // 서까래 간격을 입력해주세요. icon: 'warning', @@ -458,7 +479,7 @@ const Trestle = forwardRef((props, ref) => { addRoof: newRoofs[index], trestle: { ...roof.trestle, - raftBaseCd: roof.raftBaseCd, + raft: roof.raftBaseCd, }, construction: { // ...constructionList.find((construction) => newAddedRoofs[index].construction.constTp === construction.constTp), @@ -483,8 +504,6 @@ const Trestle = forwardRef((props, ref) => { return false } - const onMarginCheck = (target, data) => {} - useImperativeHandle(ref, () => ({ isComplete, })) @@ -518,7 +537,7 @@ const Trestle = forwardRef((props, ref) => { type="text" className="input-origin block" value={lengthBase} - onChange={(e) => setLengthBase(e.target.value)} + onChange={(e) => onChangeLength(e.target.value)} disabled={selectedRoof.lenAuth === 'R'} /> diff --git a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx index 4a4d72a2..281ae5a8 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -86,6 +86,26 @@ export default function PassivityCircuitAllocation(props) { .map((obj) => obj.circuitNumber), ), ] + + const surfaceList = targetModules.map((module) => { + return canvas.getObjects().filter((obj) => obj.id === canvas.getObjects().filter((obj) => obj.id === module)[0].surfaceId)[0] + }) + + if (surfaceList.length > 1) { + let surfaceType = {} + + surfaceList.forEach((surface) => { + surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface + }) + if (Object.keys(surfaceType).length > 1) { + swalFire({ + text: getMessage('module.circuit.fix.not.same.roof.error'), + type: 'alert', + icon: 'warning', + }) + return + } + } if (!circuitNumber || circuitNumber === 0) { swalFire({ text: getMessage('module.circuit.minimun.error'), diff --git a/src/components/floor-plan/modal/grid/GridCopy.jsx b/src/components/floor-plan/modal/grid/GridCopy.jsx index e1a6f9f9..805cf186 100644 --- a/src/components/floor-plan/modal/grid/GridCopy.jsx +++ b/src/components/floor-plan/modal/grid/GridCopy.jsx @@ -4,9 +4,11 @@ import { usePopup } from '@/hooks/usePopup' import { useRecoilValue } from 'recoil' import { contextPopupPositionState } from '@/store/popupAtom' import { useState } from 'react' -import { currentObjectState } from '@/store/canvasAtom' +import { canvasState, currentObjectState } from '@/store/canvasAtom' import { useGrid } from '@/hooks/common/useGrid' - +import { gridColorState } from '@/store/gridAtom' +import { gridDisplaySelector } from '@/store/settingAtom' +const GRID_PADDING = 5 export default function GridCopy(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const { id, pos = contextPopupPosition } = props @@ -15,9 +17,39 @@ export default function GridCopy(props) { const [length, setLength] = useState('0') const [arrow, setArrow] = useState(null) const currentObject = useRecoilValue(currentObjectState) - const { copy } = useGrid() + const canvas = useRecoilValue(canvasState) + const gridColor = useRecoilValue(gridColorState) + const isGridDisplay = useRecoilValue(gridDisplaySelector) const handleApply = () => { - copy(currentObject, ['↑', '←'].includes(arrow) ? +length * -1 : +length) + copy(currentObject, ['↑', '←'].includes(arrow) ? (+length * -1) / 10 : +length / 10) + } + + const copy = (object, length) => { + const lineStartX = object.direction === 'vertical' ? object.x1 + length : 0 + const lineEndX = object.direction === 'vertical' ? object.x2 + length : canvas.width + const lineStartY = object.direction === 'vertical' ? 0 : object.y1 + length + const lineEndY = object.direction === 'vertical' ? canvas.width : object.y1 + length + + const line = new fabric.Line([lineStartX, lineStartY, lineEndX, lineEndY], { + stroke: gridColor, + strokeWidth: 1, + selectable: true, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + strokeDashArray: [5, 2], + opacity: 0.3, + padding: GRID_PADDING, + direction: object.direction, + visible: isGridDisplay, + name: object.name, + }) + + canvas.add(line) + canvas.setActiveObject(line) + canvas.renderAll() } return ( diff --git a/src/components/floor-plan/modal/grid/GridMove.jsx b/src/components/floor-plan/modal/grid/GridMove.jsx index 4aa27851..52084e00 100644 --- a/src/components/floor-plan/modal/grid/GridMove.jsx +++ b/src/components/floor-plan/modal/grid/GridMove.jsx @@ -6,7 +6,6 @@ import { contextPopupPositionState } from '@/store/popupAtom' import { useCanvas } from '@/hooks/useCanvas' import { canvasState, currentObjectState } from '@/store/canvasAtom' import { useEffect, useState } from 'react' -import { useGrid } from '@/hooks/common/useGrid' import { useSwal } from '@/hooks/useSwal' import { set } from 'react-hook-form' @@ -17,7 +16,6 @@ export default function GridMove(props) { const { getMessage } = useMessage() const { closePopup } = usePopup() const { swalFire } = useSwal() - const { move } = useGrid() const [currentObject, setCurrentObject] = useRecoilState(currentObjectState) const [isAll, setIsAll] = useState(false) const [verticalSize, setVerticalSize] = useState('0') @@ -54,21 +52,31 @@ export default function GridMove(props) { .forEach((grid) => { move( grid, - arrow2 === '←' ? Number(horizonSize) * -1 : Number(horizonSize), - arrow1 === '↑' ? Number(verticalSize) * -1 : Number(verticalSize), + arrow2 === '←' ? (Number(horizonSize) * -1) / 10 : Number(horizonSize) / 10, + arrow1 === '↑' ? (Number(verticalSize) * -1) / 10 : Number(verticalSize) / 10, ) }) } else { move( currentObject, - arrow2 === '←' ? Number(horizonSize) * -1 : Number(horizonSize), - arrow1 === '↑' ? Number(verticalSize) * -1 : Number(verticalSize), + arrow2 === '←' ? (Number(horizonSize) * -1) / 10 : Number(horizonSize) / 10, + arrow1 === '↑' ? (Number(verticalSize) * -1) / 10 : Number(verticalSize) / 10, ) } canvas.renderAll() handleClose() } + const move = (object, x, y) => { + object.set({ + ...object, + x1: object.direction === 'vertical' ? object.x1 + x : 0, + x2: object.direction === 'vertical' ? object.x1 + x : canvas.width, + y1: object.direction === 'vertical' ? 0 : object.y1 + y, + y2: object.direction === 'vertical' ? canvas.height : object.y1 + y, + }) + } + const handleClose = () => { closePopup(id) } diff --git a/src/components/floor-plan/modal/movement/type/FlowLine.jsx b/src/components/floor-plan/modal/movement/type/FlowLine.jsx index 565a9ff8..3c23a30a 100644 --- a/src/components/floor-plan/modal/movement/type/FlowLine.jsx +++ b/src/components/floor-plan/modal/movement/type/FlowLine.jsx @@ -15,13 +15,18 @@ export default function FlowLine({ FLOW_LINE_REF }) { const currentObject = useRecoilValue(currentObjectState) const handleFocus = () => { if (currentObject === null) { + FLOW_LINE_REF.POINTER_INPUT_REF.current.value = '' FLOW_LINE_REF.FILLED_INPUT_REF.current.value = '' FLOW_LINE_REF.FILLED_INPUT_REF.current.blur() } } const handleInput = (e) => { - const value = e.target.value.replace(/^0+/, '') - setFilledInput(value.replace(/[^0-9]/g, '')) + const regex = /^-?\d*$/ + let value = e.target.value + if (!regex.test(value) && value !== '') return + if (value.startsWith('0') || value === '-0') return + + setFilledInput(value.replace(/[^0-9-]/g, '')) } return ( <> @@ -47,7 +52,7 @@ export default function FlowLine({ FLOW_LINE_REF }) {
- {/**/} + {}
diff --git a/src/components/floor-plan/modal/movement/type/Updown.jsx b/src/components/floor-plan/modal/movement/type/Updown.jsx index bcc45590..786c7017 100644 --- a/src/components/floor-plan/modal/movement/type/Updown.jsx +++ b/src/components/floor-plan/modal/movement/type/Updown.jsx @@ -15,6 +15,7 @@ export default function Updown({ UP_DOWN_REF }) { const currentObject = useRecoilValue(currentObjectState) const handleFocus = () => { if (currentObject === null) { + UP_DOWN_REF.POINTER_INPUT_REF.current.value = '' UP_DOWN_REF.FILLED_INPUT_REF.current.value = '' UP_DOWN_REF.FILLED_INPUT_REF.current.blur() } @@ -48,7 +49,7 @@ export default function Updown({ UP_DOWN_REF }) {
- {/**/} + {}
diff --git a/src/components/floor-plan/modal/setting01/GridOption.jsx b/src/components/floor-plan/modal/setting01/GridOption.jsx index b5b61acc..5931b561 100644 --- a/src/components/floor-plan/modal/setting01/GridOption.jsx +++ b/src/components/floor-plan/modal/setting01/GridOption.jsx @@ -105,6 +105,16 @@ export default function GridOption(props) { initEvent() }, [gridOptions]) + useEffect(() => { + return () => { + setAdsorptionPointAddMode(false) + setTempGridMode(false) + setTimeout(() => { + initEvent() + }, 100) + } + }, []) + const dotLineGridProps = { id: dotLineId, setIsShow: setShowDotLineGridModal, diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index f264edb2..d0acddb2 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -185,7 +185,7 @@ export default function SecondOption(props) { const onClickOption = async (item) => { let option4Data = settingModalSecondOptions?.option4 - let adsorpPointData = adsorptionPointMode.adsorptionPoint + let adsorpPointData = adsorptionPointMode //흡착범위 설정(단 건 선택) if ( @@ -203,11 +203,9 @@ export default function SecondOption(props) { //흡착점 범위 setAdsorptionRange(item.range) - - setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: adsorpPointData }) + setAdsorptionPointMode(adsorpPointData) } else if (item === 'adsorpPoint') { - setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: !adsorpPointData }) - adsorpPointData = !adsorpPointData + setAdsorptionPointMode(!adsorpPointData) } setSettingsData({ ...settingsData, option4: [...option4Data], adsorptionPoint: adsorpPointData }) @@ -257,7 +255,7 @@ export default function SecondOption(props) { }} > {getMessage('modal.canvas.setting.font.plan.absorption.point')} - {adsorptionPointMode.adsorptionPoint ? 'ON' : 'OFF'} + {adsorptionPointMode ? 'ON' : 'OFF'} diff --git a/src/components/floor-plan/modal/setting01/SettingModal01.jsx b/src/components/floor-plan/modal/setting01/SettingModal01.jsx index 4e6f91ea..71c19a83 100644 --- a/src/components/floor-plan/modal/setting01/SettingModal01.jsx +++ b/src/components/floor-plan/modal/setting01/SettingModal01.jsx @@ -6,16 +6,22 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import SecondOption from '@/components/floor-plan/modal/setting01/SecondOption' import { useMessage } from '@/hooks/useMessage' import GridOption from '@/components/floor-plan/modal/setting01/GridOption' -import { canGridOptionSeletor } from '@/store/canvasAtom' -import { useRecoilValue } from 'recoil' +import { adsorptionPointAddModeState, canGridOptionSeletor, tempGridModeState } from '@/store/canvasAtom' +import { useRecoilState, useRecoilValue } from 'recoil' import { usePopup } from '@/hooks/usePopup' import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' +import { useTempGrid } from '@/hooks/useTempGrid' +import { settingModalGridOptionsState } from '@/store/settingAtom' +import { useEvent } from '@/hooks/useEvent' export default function SettingModal01(props) { const { id } = props const [buttonAct, setButtonAct] = useState(1) const { getMessage } = useMessage() const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor) + const [gridOptions, setGridOptions] = useRecoilState(settingModalGridOptionsState) + const [tempGridMode, setTempGridMode] = useRecoilState(tempGridModeState) + const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState) const { closePopup } = usePopup() const { @@ -71,9 +77,22 @@ export default function SettingModal01(props) { setButtonAct(num) } + const onClose = () => { + setTempGridMode(false) + setAdsorptionPointAddMode(false) + setGridOptions((prev) => { + const newSettingOptions = [...prev] + newSettingOptions[0].selected = false + newSettingOptions[2].selected = false + return [...newSettingOptions] + }) + + closePopup(id, true) + } + return ( - closePopup(id, true)} /> +