598 lines
19 KiB
JavaScript
598 lines
19 KiB
JavaScript
'use client'
|
||
|
||
import { useRef, useState, useEffect, useContext } from 'react'
|
||
import Image from 'next/image'
|
||
import { useRecoilState } from 'recoil'
|
||
import { v4 as uuidv4 } from 'uuid'
|
||
import { FaAnglesUp } from 'react-icons/fa6'
|
||
import { FaAnglesDown } from 'react-icons/fa6'
|
||
import { Button } from '@nextui-org/react'
|
||
import ColorPicker from './common/color-picker/ColorPicker'
|
||
import { cadFileNameState, googleMapFileNameState, useCadFileState, useGoogleMapFileState } from '@/store/canvasAtom'
|
||
|
||
import { useAxios } from '@/hooks/useAxios'
|
||
import { useMessage } from '@/hooks/useMessage'
|
||
import { useMasterController } from '@/hooks/common/useMasterController'
|
||
import { useSwal } from '@/hooks/useSwal'
|
||
import { convertDwgToPng } from '@/lib/cadAction'
|
||
import { GlobalDataContext } from '@/app/GlobalDataProvider'
|
||
import QInput from './common/input/Qinput'
|
||
import QSelect from './common/select/QSelect'
|
||
import QPagination from './common/pagination/QPagination'
|
||
import QSelectBox from './common/select/QSelectBox'
|
||
import SampleReducer from './sample/SampleReducer'
|
||
|
||
import styles from './playground.module.css'
|
||
import useSWR from 'swr'
|
||
import useSWRMutation from 'swr/mutation'
|
||
|
||
export default function Playground() {
|
||
const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState)
|
||
const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState)
|
||
const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState)
|
||
const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState)
|
||
const fileRef = useRef(null)
|
||
const queryRef = useRef(null)
|
||
const [zoom, setZoom] = useState(20)
|
||
const { get, promiseGet, post, promisePost, getFetcher, postFetcher } = useAxios()
|
||
const testVar = process.env.NEXT_PUBLIC_TEST
|
||
const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL
|
||
const { getMessage } = useMessage()
|
||
const { swalFire } = useSwal()
|
||
const { getRoofMaterialList, getModuleTypeItemList, getTrestleList, getConstructionList, getTrestleDetailList } = useMasterController()
|
||
|
||
const [color, setColor] = useState('#ff0000')
|
||
|
||
const [textInput, setTextInput] = useState('')
|
||
const [numberInput, setNumberInput] = useState('')
|
||
const [radioInput, setRadioInput] = useState('')
|
||
const [checkboxInput, setCheckboxInput] = useState([])
|
||
const [selectedValue, setSelectedValue] = useState('')
|
||
|
||
const [users, setUsers] = useState([])
|
||
|
||
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
|
||
|
||
useEffect(() => {
|
||
console.log('textInput:', textInput)
|
||
}, [textInput])
|
||
useEffect(() => {
|
||
console.log('numberInput:', numberInput)
|
||
}, [numberInput])
|
||
useEffect(() => {
|
||
console.log('radioInput:', radioInput)
|
||
}, [radioInput])
|
||
useEffect(() => {
|
||
console.log('checkboxInput:', checkboxInput)
|
||
}, [checkboxInput])
|
||
useEffect(() => {
|
||
console.log('selectedValue:', selectedValue)
|
||
}, [selectedValue])
|
||
|
||
const handleUsers = async () => {
|
||
// const users = await get('/api/user/find-all')
|
||
const params = {
|
||
url: '/api/user/find-all',
|
||
}
|
||
const users = await get(params)
|
||
console.log('users', users)
|
||
}
|
||
|
||
const handleConvert = async () => {
|
||
console.log('file', fileRef.current.files[0])
|
||
|
||
const formData = new FormData()
|
||
formData.append('file', fileRef.current.files[0])
|
||
|
||
await promisePost({ url: converterUrl, data: formData })
|
||
.then((res) => {
|
||
console.log('response: ', res)
|
||
convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData)
|
||
setUseCadFile(true)
|
||
setCadFileName(res.data.Files[0].FileName)
|
||
swalFire({ text: '파일 변환 완료' })
|
||
})
|
||
.catch((err) => {
|
||
console.error(err)
|
||
swalFire({ text: '파일 변환 실패' })
|
||
})
|
||
}
|
||
|
||
const handleDownImage = async (fileName = '') => {
|
||
const fileNm = fileName === '' ? uuidv4() : fileName
|
||
const queryString = queryRef.current.value === '' ? '서울시 서대문구 연세로5다길 22-3 발리빌라 3층' : queryRef.current.value
|
||
const res = await get({ url: `http://localhost:3000/api/html2canvas?q=${queryString}&fileNm=${fileNm}&zoom=${zoom}` })
|
||
console.log('res', res)
|
||
setGoogleMapFileName(res.fileNm)
|
||
swalFire({ text: '이미지 저장 완료' })
|
||
setUseGoogleMapFile(true)
|
||
}
|
||
|
||
const handleZoom = async (type) => {
|
||
if (type === 'up') {
|
||
setZoom((prevState) => prevState + 1)
|
||
} else {
|
||
setZoom((prevState) => prevState - 1)
|
||
}
|
||
|
||
await handleDownImage()
|
||
}
|
||
|
||
const data = [
|
||
{
|
||
id: 1,
|
||
author: 'SWYOO',
|
||
contents: '버튼 정리(템플릿 적용)',
|
||
date: '2024.07.16',
|
||
},
|
||
{
|
||
id: 2,
|
||
author: 'SWYOO',
|
||
contents: 'README.md 파일 이미지 경로 수정',
|
||
date: '2024.07.17',
|
||
},
|
||
{
|
||
id: 3,
|
||
author: 'SWYOO',
|
||
contents: '',
|
||
date: '',
|
||
},
|
||
]
|
||
|
||
const handleSwalAlert = () => {
|
||
swalFire({
|
||
text: '알림 테스트입니다.',
|
||
})
|
||
}
|
||
|
||
const paginationProps = {
|
||
pageNo: 1,
|
||
pageSize: 10,
|
||
pagePerBlock: 10,
|
||
totalCount: 26,
|
||
handleChangePage: (page) => {
|
||
console.log('page', page)
|
||
},
|
||
}
|
||
|
||
useEffect(() => {
|
||
console.log('users:', users)
|
||
}, [users])
|
||
|
||
const codes = [
|
||
{
|
||
clHeadCd: '203800',
|
||
clCode: 'HEI_455',
|
||
clCodeNm: '세로 455mm이하',
|
||
clPriority: 1,
|
||
name: '세로 455mm이하',
|
||
id: 'HEI_455',
|
||
},
|
||
{
|
||
clHeadCd: '203800',
|
||
clCode: 'HEI_500',
|
||
clCodeNm: '세로 500mm이하',
|
||
clPriority: 2,
|
||
name: '세로 500mm이하',
|
||
id: 'HEI_500',
|
||
},
|
||
{
|
||
clHeadCd: '203800',
|
||
clCode: 'HEI_606',
|
||
clCodeNm: '세로 606mm이하',
|
||
clPriority: 3,
|
||
name: '세로 606mm이하',
|
||
id: 'HEI_606',
|
||
},
|
||
{
|
||
clHeadCd: '203800',
|
||
clCode: 'WID_606',
|
||
clCodeNm: '가로 606mm이하',
|
||
clPriority: 4,
|
||
name: '가로 606mm이하',
|
||
id: 'WID_606',
|
||
},
|
||
{
|
||
clHeadCd: '203800',
|
||
clCode: 'ETC',
|
||
clCodeNm: '기타',
|
||
clPriority: 5,
|
||
name: '기타',
|
||
id: 'ETC',
|
||
},
|
||
]
|
||
|
||
const [myData, setMyData] = useState({
|
||
roofMatlCd: 'ROOF_ID_WA_53A',
|
||
roofMatlNm: '화와 A',
|
||
roofMatlNmJp: '和瓦A',
|
||
widAuth: 'R',
|
||
widBase: '265.000',
|
||
lenAuth: 'R',
|
||
lenBase: '235.000',
|
||
roofPchAuth: null,
|
||
roofPchBase: null,
|
||
raftAuth: 'C',
|
||
raftBaseCd: 'HEI_455',
|
||
id: 'ROOF_ID_WA_53A',
|
||
name: '화와 A',
|
||
selected: true,
|
||
nameJp: '和瓦A',
|
||
length: 235,
|
||
width: 265,
|
||
layout: 'P',
|
||
hajebichi: null,
|
||
})
|
||
|
||
const handleChangeMyData = () => {
|
||
setMyData({ ...myData, raftBaseCd: 'HEI_500' })
|
||
}
|
||
|
||
const [myData2, setMyData2] = useState({})
|
||
|
||
const handleChangeMyData2 = () => {
|
||
setMyData2({
|
||
roofMatlCd: 'ROOF_ID_WA_53A',
|
||
roofMatlNm: '화와 A',
|
||
roofMatlNmJp: '和瓦A',
|
||
widAuth: 'R',
|
||
widBase: '265.000',
|
||
lenAuth: 'R',
|
||
lenBase: '235.000',
|
||
roofPchAuth: null,
|
||
roofPchBase: null,
|
||
raftAuth: 'C',
|
||
raftBaseCd: 'HEI_455',
|
||
id: 'ROOF_ID_WA_53A',
|
||
name: '화와 A',
|
||
selected: true,
|
||
nameJp: '和瓦A',
|
||
length: 235,
|
||
width: 265,
|
||
layout: 'P',
|
||
hajebichi: null,
|
||
})
|
||
}
|
||
|
||
const [callFlag, setCallFlag] = useState(false)
|
||
// const { data: tutoData, error, isLoadin g } = useSWR('http://localhost:8080/api/tutorial', getFetcher)
|
||
const { data: tutoData, error, isLoading } = useSWR(callFlag ? 'http://localhost:8080/api/tutorial' : null, getFetcher)
|
||
const { trigger, isMutating } = useSWRMutation('http://localhost:8080/api/tutorial', postFetcher)
|
||
|
||
if (isLoading) {
|
||
return <div>Loading...</div>
|
||
}
|
||
|
||
if (error) {
|
||
return <div>Error...</div>
|
||
}
|
||
|
||
useEffect(() => {
|
||
trigger({ id: 3, name: 'seulda kim', email: 'seulda.kim@interplug.co.kr' })
|
||
}, [tutoData])
|
||
|
||
return (
|
||
<>
|
||
<div className="container mx-auto p-4 m-4 border">
|
||
<div className={styles.test}>이 영역은 테스트입니다.</div>
|
||
<div className="my-2">
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
getRoofMaterialList()
|
||
}}
|
||
>
|
||
지붕재 목록 조회 API 호출
|
||
</button>{' '}
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
getModuleTypeItemList(['ROOF_ID_HIRA_SEME', 'ROOF_ID_ROOGA'])
|
||
}}
|
||
>
|
||
모듈 타입별 아이템 목록 조회 API 호출
|
||
</button>{' '}
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
getTrestleList({ moduleTpCd: '', roofMatlCd: '', raftBaseCd: '', trestleMkrCd: '', constMthdCd: '', roofBaseCd: '' }) //임시 데이터
|
||
}}
|
||
>
|
||
가대 목록 조회 API 호출
|
||
</button>{' '}
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
getConstructionList({
|
||
//임시 데이터
|
||
moduleTpCd: 'testData_1',
|
||
roofMatlCd: 'testData_2',
|
||
trestleMkrCd: 'testData_3',
|
||
constMthdCd: 'testData_4',
|
||
roofBaseCd: 'testData_5',
|
||
illuminationTp: 'testData_6',
|
||
instHt: 'testData_7',
|
||
stdWindSpeed: 'testData_8',
|
||
stdSnowLd: 'testData_9',
|
||
inclCd: 'testData_10',
|
||
raftBaseCd: '',
|
||
roofPitch: 30,
|
||
})
|
||
}}
|
||
>
|
||
시공법 목록 조회 API 호출
|
||
</button>{' '}
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
getTrestleDetailList({
|
||
//임시 데이터
|
||
moduleTpCd: 'testData_1',
|
||
roofMatlCd: 'testData_2',
|
||
trestleMkrCd: 'testData_3',
|
||
constMthdCd: 'testData_4',
|
||
roofBaseCd: 'testData_5',
|
||
illuminationTp: 'testData_6',
|
||
instHt: 'testData_7',
|
||
stdWindSpeed: 'testData_8',
|
||
stdSnowLd: 'testData_9',
|
||
inclCd: 'testData_10',
|
||
constTp: 'testData_11',
|
||
mixMatlNo: 30,
|
||
roofPitch: 0,
|
||
})
|
||
}}
|
||
>
|
||
가대 상세 조회 API 호출
|
||
</button>
|
||
</div>
|
||
|
||
<div className="m-2">
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
setTextInput('')
|
||
}}
|
||
>
|
||
QInput TextInput DATA RESET
|
||
</button>
|
||
<QInput type="text" placeholder="placeholder" value={textInput} onChange={setTextInput} />
|
||
<QInput type="text" placeholder="read only" value={textInput} onChange={setTextInput} readOnly="true" />
|
||
<br />
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
setNumberInput('')
|
||
}}
|
||
>
|
||
QInput NumberInput DATA RESET
|
||
</button>
|
||
<QInput type="number" placeholder="placeholder" value={numberInput} onChange={setNumberInput} />
|
||
<QInput type="number" placeholder="read only" value={numberInput} onChange={setNumberInput} readOnly="true" />
|
||
<br />
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
setRadioInput('')
|
||
}}
|
||
>
|
||
QInput Radio DATA RESET
|
||
</button>
|
||
<QInput
|
||
type="radio"
|
||
value={radioInput}
|
||
onChange={setRadioInput}
|
||
options={[
|
||
{ id: 'r01', value: 'option1', name: 'Option 1' },
|
||
{ id: 'r02', value: 'option2', name: 'Option 2' },
|
||
]}
|
||
/>
|
||
<br />
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
setCheckboxInput([])
|
||
}}
|
||
>
|
||
QInput Checkbox DATA RESET
|
||
</button>
|
||
<QInput
|
||
type="checkbox"
|
||
value={checkboxInput}
|
||
onChange={setCheckboxInput}
|
||
options={[
|
||
{ id: 'c01', value: 'checkbox1', name: 'Checkbox 1' },
|
||
{ id: 'c02', value: 'checkbox2', name: 'Checkbox 2' },
|
||
]}
|
||
/>
|
||
</div>
|
||
<div className="m-2">
|
||
<br />
|
||
<button
|
||
className="btn-frame deepgray"
|
||
onClick={() => {
|
||
setSelectedValue([])
|
||
}}
|
||
>
|
||
QSelect DATA RESET
|
||
</button>
|
||
<QSelect
|
||
value={selectedValue}
|
||
onChange={setSelectedValue}
|
||
// placeholder="동물을 선택하세요"
|
||
options={[
|
||
{ id: 's01', value: 'cat', name: '고양이' },
|
||
{ id: 's02', value: 'dog', name: '개' },
|
||
{ id: 's03', value: 'lion', name: '사자' },
|
||
{ id: 's04', value: 'tiger', name: '호랑이' },
|
||
]}
|
||
/>
|
||
<QSelect
|
||
value={selectedValue}
|
||
onChange={setSelectedValue}
|
||
placeholder="동물을 선택하세요"
|
||
options={[
|
||
{ id: 's01', value: 'cat', name: '고양이' },
|
||
{ id: 's02', value: 'dog', name: '개' },
|
||
{ id: 's03', value: 'lion', name: '사자' },
|
||
{ id: 's04', value: 'tiger', name: '호랑이' },
|
||
]}
|
||
disabled="true"
|
||
/>
|
||
<QSelect
|
||
value={selectedValue}
|
||
onChange={setSelectedValue}
|
||
placeholder="동물을 선택하세요"
|
||
options={[
|
||
{ id: 's01', value: 'cat', name: '고양이' },
|
||
{ id: 's02', value: 'dog', name: '개' },
|
||
{ id: 's03', value: 'lion', name: '사자' },
|
||
{ id: 's04', value: 'tiger', name: '호랑이' },
|
||
]}
|
||
dark="true"
|
||
/>
|
||
</div>
|
||
<div className="w-full bg-orange-300 m-2">{testVar}</div>
|
||
<div>
|
||
<div className="m-2">
|
||
<Button onClick={handleUsers}>Button</Button>
|
||
</div>
|
||
</div>
|
||
<div className="test">
|
||
<p className="text-white">Sass 테스트입니다.</p>
|
||
</div>
|
||
<div dangerouslySetInnerHTML={{ __html: getMessage('welcome', ['<span style="color: red">test</span>']) }}></div>
|
||
<div>
|
||
<h1>React ColorPicker</h1>
|
||
<ColorPicker color={color} setColor={setColor} />
|
||
<div className="p-4">{color}</div>
|
||
</div>
|
||
<div>
|
||
<h1 className="text-2xl">캐드 파일 이미지 사용</h1>
|
||
<input type="file" name="file" ref={fileRef} />
|
||
<div>
|
||
<Button onClick={handleConvert}>Convert</Button>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<h1 className="text-2xl">구글 맵 이미지 사용</h1>
|
||
<input type="text" ref={queryRef} className="w-80 border-medium my-2" />
|
||
<div>
|
||
<Button onClick={handleDownImage}>Google map Download to Image</Button>
|
||
</div>
|
||
{useGoogleMapFile && (
|
||
<>
|
||
<div className="my-2">
|
||
<p className="text-lg">Zoom Controller : {zoom}</p>
|
||
<Button startContent={<FaAnglesUp />} className="mx-2" onClick={() => handleZoom('up')}></Button>
|
||
<Button startContent={<FaAnglesDown />} className="mx-2" onClick={() => handleZoom('down')}></Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<Image src={`/mapImages/${googleMapFileName}`} width={640} height={640} />
|
||
</div>
|
||
</>
|
||
)}
|
||
</div>
|
||
<div className="my-2">
|
||
<Button onClick={() => swalFire({ text: 'alert 테스트입니다.' })}>Sweetalert - alert</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<Button onClick={() => swalFire({ text: 'alert 아이콘 테스트입니다.', icon: 'error' })}>Sweetalert - alert - error</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<Button
|
||
onClick={() =>
|
||
swalFire({
|
||
html: `confirm 테스트입니다.<br />당신은 바보입니까?`,
|
||
type: 'confirm',
|
||
confirmFn: () => {
|
||
alert('test')
|
||
},
|
||
})
|
||
}
|
||
>
|
||
Sweetalert - confirm
|
||
</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<QPagination {...paginationProps} />
|
||
</div>
|
||
<div className="my-2">
|
||
<Button
|
||
onClick={() => {
|
||
promiseGet({ url: 'http://localhost:8080/api/user' }).then((res) => setUsers(res.data))
|
||
}}
|
||
>
|
||
axios get test
|
||
</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<Button
|
||
onClick={() => {
|
||
const result = promisePost({
|
||
url: 'http://localhost:8080/api/user',
|
||
data: {
|
||
firstName: 'Yoo',
|
||
lastName: 'Sangwook',
|
||
email: 'yoo1757@naver.com',
|
||
age: 46,
|
||
},
|
||
}).then((res) => console.log('res', res))
|
||
}}
|
||
>
|
||
axios post test
|
||
</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<QSelectBox options={codes} value={myData} sourceKey="id" targetKey="raftBaseCd" showKey="clCodeNm" />
|
||
</div>
|
||
<div className="my-2">
|
||
<Button onClick={handleChangeMyData}>QSelectBox value change!!</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<QSelectBox options={codes} value={myData2} sourceKey="id" targetKey="raftBaseCd" showKey="clCodeNm" />
|
||
</div>
|
||
<div className="my-2">
|
||
<Button onClick={handleChangeMyData2}>QSelectBox dynamic data bind change!!</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<QSelectBox title="초기값 테스트" options={[]} value={{}} sourceKey="id" targetKey="raftBaseCd" showKey="clCodeNm" />
|
||
</div>
|
||
<div className="my-2">
|
||
<SampleReducer />
|
||
</div>
|
||
<div className="my-2">
|
||
<Button onClick={() => setManagementState({ ...managementState, objectNo: '1234567890' })}>GlobalDataProvider 테스트</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<Button onClick={() => setManagementState({})}>GlobalDataProvider 초기화</Button>
|
||
</div>
|
||
{/* <div className="my-2">
|
||
<p>{managementStateLoaded?.objectNo}</p>
|
||
</div> */}
|
||
<div className="my-2">
|
||
<Button onClick={() => swalFire({ text: 'alert 테스트입니다.', type: 'alert', confirmFn: () => console.log('Alert!!!') })}>
|
||
Sweetalert - alert
|
||
</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
{tutoData &&
|
||
tutoData.map((item) => (
|
||
<div key={item.id}>
|
||
{item.name} / {item.email}
|
||
</div>
|
||
))}
|
||
</div>
|
||
<div className="my-2">
|
||
<Button onClick={() => setCallFlag(true)}>getFetcher call</Button>
|
||
</div>
|
||
<div className="my-2">
|
||
<Button disabled={isMutating} onClick={() => trigger({ id: 3, name: 'seulda kim', email: 'seulda.kim@interplug.co.kr' })}>
|
||
insert data
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</>
|
||
)
|
||
}
|