diff --git a/src/app/QcastProvider.js b/src/app/QcastProvider.js new file mode 100644 index 00000000..f9431eb6 --- /dev/null +++ b/src/app/QcastProvider.js @@ -0,0 +1,35 @@ +'use client' + +import { useEffect } from 'react' +import { useRecoilState, useRecoilValue } from 'recoil' +import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' +import { ErrorBoundary } from 'next/dist/client/components/error-boundary' +import ServerError from './error' + +import '@/styles/common.scss' + +import KO from '@/locales/ko.json' +import JA from '@/locales/ja.json' + +export const QcastProvider = ({ children }) => { + const globalLocale = useRecoilValue(globalLocaleStore) + const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) + + useEffect(() => { + console.log(sessionStorage.getItem('hi')) + console.log(Object.keys(appMessageState).length) + // if (Object.keys(appMessageState).length === 0) { + if (globalLocale === 'ko') { + setAppMessageState(KO) + } else { + setAppMessageState(JA) + } + // } + }, [globalLocale]) + + return ( + <> + }>{children} + + ) +} diff --git a/src/app/[locale]/management/stuff/detail/page.jsx b/src/app/[locale]/management/stuff/detail/page.jsx index 8b84287a..6759b282 100644 --- a/src/app/[locale]/management/stuff/detail/page.jsx +++ b/src/app/[locale]/management/stuff/detail/page.jsx @@ -1,11 +1,15 @@ import React from 'react' import Hero from '@/components/Hero' import StuffDetail from '@/components/management/StuffDetail' +import Link from 'next/link' export default function ManagementStuffDetailPage() { return ( <>

물건정보

+ +

도면작성

+
diff --git a/src/app/[locale]/management/stuff/tempdetail/page.jsx b/src/app/[locale]/management/stuff/tempdetail/page.jsx new file mode 100644 index 00000000..8b84287a --- /dev/null +++ b/src/app/[locale]/management/stuff/tempdetail/page.jsx @@ -0,0 +1,15 @@ +import React from 'react' +import Hero from '@/components/Hero' +import StuffDetail from '@/components/management/StuffDetail' +export default function ManagementStuffDetailPage() { + return ( + <> +
+

물건정보

+
+
+ +
+ + ) +} diff --git a/src/app/[locale]/page.js b/src/app/[locale]/page.js index bbdcd96d..1b8f2258 100644 --- a/src/app/[locale]/page.js +++ b/src/app/[locale]/page.js @@ -1,21 +1,16 @@ import { getSession } from '@/lib/authActions' -import { getCurrentLocale } from '@/locales/server' import MainPage from '@/components/Main' export default async function page() { const session = await getSession() - const currentLocale = getCurrentLocale() - const mainPageProps = { - currentLocale, isLoggedIn: session?.isLoggedIn, } return ( <>
-

Main

diff --git a/src/app/community/archive/page.jsx b/src/app/community/archive/page.jsx new file mode 100644 index 00000000..6917f228 --- /dev/null +++ b/src/app/community/archive/page.jsx @@ -0,0 +1,16 @@ +import Hero from '@/components/Hero' +import Archive from '@/components/community/Archive' +import { initCheck } from '@/util/session-util' + +export default async function CommunityArchivePage() { + await initCheck() + + return ( + <> + +
+ +
+ + ) +} diff --git a/src/app/community/faq/page.jsx b/src/app/community/faq/page.jsx new file mode 100644 index 00000000..2b9d5452 --- /dev/null +++ b/src/app/community/faq/page.jsx @@ -0,0 +1,16 @@ +import Hero from '@/components/Hero' +import Faq from '@/components/community/Faq' +import { initCheck } from '@/util/session-util' + +export default async function CommunityFaqPage() { + await initCheck() + + return ( + <> + +
+ +
+ + ) +} diff --git a/src/app/community/notice/page.jsx b/src/app/community/notice/page.jsx new file mode 100644 index 00000000..d2157b20 --- /dev/null +++ b/src/app/community/notice/page.jsx @@ -0,0 +1,16 @@ +import Hero from '@/components/Hero' +import Notice from '@/components/community/Notice' +import { initCheck } from '@/util/session-util' + +export default async function CommunityNoticePage() { + await initCheck() + + return ( + <> + +
+ +
+ + ) +} diff --git a/src/app/floor-plan/page.jsx b/src/app/floor-plan/page.jsx new file mode 100644 index 00000000..f503099e --- /dev/null +++ b/src/app/floor-plan/page.jsx @@ -0,0 +1,9 @@ +import FloorPlan from '@/components/floor-plan/FloorPlan' + +export default function FloorPlanPage() { + return ( + <> + + + ) +} diff --git a/src/app/initSettingsModal/page.jsx b/src/app/initSettingsModal/page.jsx new file mode 100644 index 00000000..a081ef47 --- /dev/null +++ b/src/app/initSettingsModal/page.jsx @@ -0,0 +1,16 @@ +import Hero from '@/components/Hero' +import InitSettingsModal from '@/components/InitSettingsModal' +import { initCheck } from '@/util/session-util' + +export default async function InitSettingsModalPage() { + await initCheck() + + return ( + <> + +
+ +
+ + ) +} diff --git a/src/app/intro/page.jsx b/src/app/intro/page.jsx new file mode 100644 index 00000000..8d560ce5 --- /dev/null +++ b/src/app/intro/page.jsx @@ -0,0 +1,14 @@ +import Intro from '@/components/Intro' +import { initCheck } from '@/util/session-util' + +export default async function IntroPage() { + await initCheck() + + return ( + <> +
+ +
+ + ) +} diff --git a/src/app/join/complete/page.jsx b/src/app/join/complete/page.jsx new file mode 100644 index 00000000..3f9fc462 --- /dev/null +++ b/src/app/join/complete/page.jsx @@ -0,0 +1,19 @@ +'use client' + +import { useMessage } from '@/hooks/useMessage' + +export default function CompletePage() { + const { getMessage } = useMessage() + + return ( + <> +
+

{getMessage('join.complete.title')}

+
{getMessage('join.complete.contents')}
+
+ {getMessage('join.complete.email_comment')} : {getMessage('join.complete.email')} +
+
+ + ) +} diff --git a/src/app/join/page.jsx b/src/app/join/page.jsx new file mode 100644 index 00000000..118a25b4 --- /dev/null +++ b/src/app/join/page.jsx @@ -0,0 +1,5 @@ +import Join from '@/components/auth/Join' + +export default function JoinPage() { + return <>{} +} diff --git a/src/app/layout.js b/src/app/layout.js index 90a46e6e..c3ac72de 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -1,14 +1,19 @@ import { Inter } from 'next/font/google' +import { headers } from 'next/headers' +import { redirect } from 'next/navigation' +import { getSession } from '@/lib/authActions' import RecoilRootWrapper from './RecoilWrapper' import UIProvider from './UIProvider' import { ToastContainer } from 'react-toastify' + +import Header from '@/components/header/Header' import QModal from '@/components/common/modal/QModal' import './globals.css' import '../styles/style.scss' -import Header from '@/components/header/Header' +import { QcastProvider } from './QcastProvider' const inter = Inter({ subsets: ['latin'] }) @@ -17,16 +22,29 @@ export const metadata = { description: 'Generated by create next app', } -export default function RootLayout({ children }) { +export default async function RootLayout({ children }) { + const headersList = headers() + const headerPathname = headersList.get('x-pathname') || '' + + // console.log('headerPathname:', headerPathname) + // const isLoggedIn = await checkSession() + const session = await getSession() + console.log('session[layout]:', session) + if (!headerPathname.includes('/login') && !session.isLoggedIn) { + redirect('/login') + } + return ( {/*{headerPathname !== '/login' && }*/}
-
+
- {children} + + {children} +
diff --git a/src/app/login/page.jsx b/src/app/login/page.jsx new file mode 100644 index 00000000..0686da2e --- /dev/null +++ b/src/app/login/page.jsx @@ -0,0 +1,9 @@ +import Login from '@/components/auth/Login' + +export default function LoginPage() { + return ( + <> + + + ) +} diff --git a/src/app/management/plan/page.jsx b/src/app/management/plan/page.jsx new file mode 100644 index 00000000..5fefa62a --- /dev/null +++ b/src/app/management/plan/page.jsx @@ -0,0 +1,16 @@ +import Hero from '@/components/Hero' +import Plan from '@/components/management/Plan' +import { initCheck } from '@/util/session-util' + +export default async function ManagementPlanPage() { + await initCheck() + + return ( + <> + +
+ +
+ + ) +} diff --git a/src/app/management/stuff/detail/page.jsx b/src/app/management/stuff/detail/page.jsx new file mode 100644 index 00000000..6759b282 --- /dev/null +++ b/src/app/management/stuff/detail/page.jsx @@ -0,0 +1,19 @@ +import React from 'react' +import Hero from '@/components/Hero' +import StuffDetail from '@/components/management/StuffDetail' +import Link from 'next/link' +export default function ManagementStuffDetailPage() { + return ( + <> +
+

물건정보

+ +

도면작성

+ +
+
+ +
+ + ) +} diff --git a/src/app/management/stuff/page.jsx b/src/app/management/stuff/page.jsx new file mode 100644 index 00000000..7590a7cf --- /dev/null +++ b/src/app/management/stuff/page.jsx @@ -0,0 +1,21 @@ +import StuffSearchCondition from '@/components/management/StuffSearchCondition' +import Stuff from '@/components/management/Stuff' +import { initCheck } from '@/util/session-util' +import Hero from '@/components/Hero' +export default async function ManagementStuffPage() { + await initCheck() + + return ( + <> + +
+
+ +
+
+
+ +
+ + ) +} diff --git a/src/app/management/stuff/tempdetail/page.jsx b/src/app/management/stuff/tempdetail/page.jsx new file mode 100644 index 00000000..8b84287a --- /dev/null +++ b/src/app/management/stuff/tempdetail/page.jsx @@ -0,0 +1,15 @@ +import React from 'react' +import Hero from '@/components/Hero' +import StuffDetail from '@/components/management/StuffDetail' +export default function ManagementStuffDetailPage() { + return ( + <> +
+

물건정보

+
+
+ +
+ + ) +} diff --git a/src/app/master/company/page.jsx b/src/app/master/company/page.jsx new file mode 100644 index 00000000..15eda41c --- /dev/null +++ b/src/app/master/company/page.jsx @@ -0,0 +1,16 @@ +import Hero from '@/components/Hero' +import Company from '@/components/master/Company' +import { initCheck } from '@/util/session-util' + +export default async function MasterCompanyPage() { + await initCheck() + + return ( + <> + +
+ +
+ + ) +} diff --git a/src/app/master/price/page.jsx b/src/app/master/price/page.jsx new file mode 100644 index 00000000..a641d6bb --- /dev/null +++ b/src/app/master/price/page.jsx @@ -0,0 +1,16 @@ +import Hero from '@/components/Hero' +import Price from '@/components/master/Price' +import { initCheck } from '@/util/session-util' + +export default async function MasterPricePage() { + await initCheck() + + return ( + <> + +
+ +
+ + ) +} diff --git a/src/app/page.js b/src/app/page.js index 9c905040..25cd8640 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,5 +1,16 @@ -import Main from '@/components/Main' +import MainPage from '@/components/Main' +import { getSession } from '@/lib/authActions' -export default function Home() { - return
+export default async function Home() { + const session = await getSession() + + const mainPageProps = { + isLoggedIn: session?.isLoggedIn, + } + + return ( + <> + + + ) } diff --git a/src/app/playground/page.jsx b/src/app/playground/page.jsx new file mode 100644 index 00000000..66d83c34 --- /dev/null +++ b/src/app/playground/page.jsx @@ -0,0 +1,17 @@ +import Playground from '@/components/Playground' +import { initCheck } from '@/util/session-util' + +export default async function PlaygroundPage() { + // const { session } = await checkSession() + + // if (!session.isLoggedIn) { + // redirect('/login') + // } + await initCheck() + + return ( + <> + + + ) +} diff --git a/src/app/roof/page.jsx b/src/app/roof/page.jsx new file mode 100644 index 00000000..f5b8e611 --- /dev/null +++ b/src/app/roof/page.jsx @@ -0,0 +1,16 @@ +import Hero from '@/components/Hero' +import Roof from '@/components/Roof' +import { initCheck } from '@/util/session-util' + +export default async function RoofPage() { + await initCheck() + + return ( + <> + +
+ +
+ + ) +} diff --git a/src/app/roof2/RoofSelect.jsx b/src/app/roof2/RoofSelect.jsx new file mode 100644 index 00000000..d759398b --- /dev/null +++ b/src/app/roof2/RoofSelect.jsx @@ -0,0 +1,128 @@ +'use client' + +import { Select, SelectItem } from '@nextui-org/react' +import { useEffect, useState } from 'react' +import { useAxios } from '@/hooks/useAxios' + +export default function RoofSelect() { + const [roofMaterials, setRoofMaterials] = useState([]) + const [manufacturers, setManufacturers] = useState([]) + const [trestles, setTrestles] = useState([]) + const [modules, setModules] = useState([]) + const [originTrestles, setOriginTrestles] = useState([]) + + const [roofMaterialId, setRoofMaterialId] = useState(null) + const [manufacturerId, setManufacturerId] = useState(null) + const [trestleId, setTrestleId] = useState(null) + + const { get } = useAxios() + + useEffect(() => { + get({ url: '/api/roof-material/roof-material-infos' }).then((res) => { + //TODO: error handling + if (!res) return + + setRoofMaterials(res) + }) + }, []) + + useEffect(() => { + if (!roofMaterialId) { + return + } + + get({ url: `/api/roof-material/roof-material-infos/${roofMaterialId}/trestles` }).then((res) => { + if (res.length === 0) { + return + } + setOriginTrestles(res) + const manufactural = res.map((trestle) => { + return { id: trestle.manufacturerId, name: trestle.manufacturerName } + }) + // Remove duplicates + const uniqueManufactural = Array.from(new Set(manufactural.map((a) => a.id))).map((id) => { + return manufactural.find((a) => a.id === id) + }) + + setManufacturers(uniqueManufactural) + }) + }, [roofMaterialId]) + + useEffect(() => { + if (!manufacturerId) { + return + } + + const trestles = originTrestles.filter((trestle) => trestle.manufacturerId === manufacturerId) + setTrestles(trestles) + }, [manufacturerId]) + + useEffect(() => { + if (!trestleId) { + return + } + get({ url: `/api/module/module-infos?roofMaterialId=${roofMaterialId}&trestleId=${trestleId}` }).then((res) => { + if (res.length === 0) { + return + } + setModules(res) + }) + }, [trestleId]) + + const handleRoofMaterialOnChange = (e) => { + const roofMaterialId = e.target.value + setRoofMaterialId(roofMaterialId) + setManufacturers([]) + setManufacturerId(null) + setTrestleId(null) + setTrestles([]) + setModules([]) + } + + const handleManufacturersOnChange = (e) => { + const manufacturerId = Number(e.target.value) + setTrestles([]) + setManufacturerId(manufacturerId) + setTrestleId(null) + setModules([]) + } + + const handleTrestlesOnChange = (e) => { + const trestleId = Number(e.target.value) + setTrestleId(trestleId) + setModules([]) + } + + return ( +
+ {roofMaterials.length > 0 && ( + + )} + {manufacturers.length > 0 && ( + + )} + {trestles.length > 0 && ( + + )} + {modules.length > 0 && ( + + )} +
+ ) +} diff --git a/src/app/roof2/page.jsx b/src/app/roof2/page.jsx new file mode 100644 index 00000000..72881d11 --- /dev/null +++ b/src/app/roof2/page.jsx @@ -0,0 +1,26 @@ +import Roof2 from '@/components/Roof2' +import RoofSelect from '@/app/[locale]/roof2/RoofSelect' +import { initCheck } from '@/util/session-util' + +export default async function Roof2Page() { + const session = await initCheck() + const roof2Props = { + name: session.name || '', + userId: session.userId || '', + email: session.email || '', + isLoggedIn: session.isLoggedIn, + } + + return ( + <> +
+
+ +
+
+
+ +
+ + ) +} diff --git a/src/app/settings/page.jsx b/src/app/settings/page.jsx new file mode 100644 index 00000000..797c024c --- /dev/null +++ b/src/app/settings/page.jsx @@ -0,0 +1,16 @@ +import Hero from '@/components/Hero' +import Settings from '@/components/Settings' +import { initCheck } from '@/util/session-util' + +export default async function SettingsPage() { + await initCheck() + + return ( + <> + +
+ +
+ + ) +} diff --git a/src/common/common.js b/src/common/common.js index aaba3f45..c78673ee 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -1,19 +1,22 @@ -export const STEP = { +export const MENU = { INITIAL_CANVAS_SETTING: 'initialCanvasSetting', // 배치면 초기설정 ROOF_COVERING: { EXTERIOR_WALL_LINE: 'exteriorWallLine', // 외벽선 그리기 ROOF_SHAPE_SETTINGS: 'roofShapeSettings', // 지붕형상 설정 ROOF_SHAPE_EDITING: 'roofShapeEditing', // 지붕형상 편집 HELP_LINE_DRAWING: 'helpLineDrawing', // 보조선 그리기 + DEFAULT: 'roofCoveringDefault', // 아무것도 선택 안할 경우 }, // 지붕덮개 BATCH_CANVAS: { BATCH_DRAWING: 'batchDrawing', // 배치면 그리기 SURFACE_SHAPE_BATCH: 'surfaceShapeBatch', // 면형상 배치 OBJECT_BATCH: 'objectBatch', // 오브젝트 배치 + DEFAULT: 'batchCanvasDefault', // default }, // 배치면 MODULE_CIRCUIT_SETTING: { BASIC_SETTING: 'basicSetting', // 기본설정 CIRCUIT_TRESTLE_SETTING: 'circuitTrestleSetting', // 회로가대설정 + DEFAULT: 'moduleCircuitSettingDefault', }, // 모듈회로구성 ESTIMATE: 'estimate', // todo 견적서 POWER_GENERATION_SIMULATION: 'powerGenerationSimulation', // todo 발전 시뮬레이션 diff --git a/src/components/Main.jsx b/src/components/Main.jsx index 224ce1ea..4546f32d 100644 --- a/src/components/Main.jsx +++ b/src/components/Main.jsx @@ -1,62 +1,9 @@ 'use client' -import { logout } from '@/lib/authActions' -import { useChangeLocale, useI18n } from '@/locales/client' -import { Button, Chip } from '@nextui-org/react' -import Link from 'next/link' - export default function MainPage(props) { - const { currentLocale, isLoggedIn } = props - const t = useI18n() - const changeLocale = useChangeLocale() - - const handleChangeLocale = () => { - currentLocale === 'ja' ? changeLocale('ko') : changeLocale('ja') - } - - // console.log('MainPage', currentLocale) - - const handleLogout = async () => { - await logout() - } - return ( <> -

{t('locale', { locale: {currentLocale} })}

-
{t('hello')}
-
{t('welcome', { name: '효준' })}
-
- -
- {isLoggedIn && ( -
- -
- )} - {!isLoggedIn && ( -
- - - -
- )} -
font-test
- {/*

{t('locale', { locale: {currentLocale} })}

*/} - {/*
{t('hello')}
*/} - {/*
{t('welcome', { name: '효준' })}
*/} - {/*
*/} - {/* */} - {/*
*/} - {/*{isLoggedIn && (*/} - {/*
*/} - {/* */} - {/*
*/} - {/*)}*/} - {/*
font-test
*/} +

Main page

) } diff --git a/src/components/auth/Login.jsx b/src/components/auth/Login.jsx index 44d163a0..326f5720 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/Login.jsx @@ -1,6 +1,7 @@ 'use client' -import { post, patch } from '@/lib/Axios' +import { useState } from 'react' +import { useAxios } from '@/hooks/useAxios' import { setSession } from '@/lib/authActions' import { redirect } from 'next/navigation' import { useMessage } from '@/hooks/useMessage' @@ -9,9 +10,10 @@ import { Button, Switch } from '@nextui-org/react' import { useRecoilState } from 'recoil' import { globalLocaleStore } from '@/store/localeAtom' import { modalContent, modalState } from '@/store/modalAtom' -import { useState } from 'react' export default function Login(props) { + const { patch } = useAxios() + const { currentLocale } = props const { getMessage } = useMessage() const [globalLocaleState, setGlbalLocaleState] = useRecoilState(globalLocaleStore) diff --git a/src/components/common/draggable/withDraggable.jsx b/src/components/common/draggable/withDraggable.jsx index 9f322583..b6c2920b 100644 --- a/src/components/common/draggable/withDraggable.jsx +++ b/src/components/common/draggable/withDraggable.jsx @@ -1,15 +1,19 @@ 'use client' -import { useState } from 'react' +import { useEffect, useState } from 'react' import Draggable from 'react-draggable' -export default function WithDraggable({ isShow, children }) { +export default function WithDraggable({ isShow, children, pos }) { const [position, setPosition] = useState({ x: 0, y: 0 }) const handleOnDrag = (data) => { setPosition({ x: data.x, y: data.y }) } + useEffect(() => { + setPosition({ ...pos }) + }, []) + return ( <> {isShow && ( diff --git a/src/components/common/select/QSelectBox.jsx b/src/components/common/select/QSelectBox.jsx index 6e77a539..bcc0979d 100644 --- a/src/components/common/select/QSelectBox.jsx +++ b/src/components/common/select/QSelectBox.jsx @@ -1,16 +1,22 @@ 'use client' import { useState } from 'react' -export default function QSelectBox({ title, option }) { - const [selectAct, setSelectAct] = useState(false) +export default function QSelectBox({ title = '', options, onChange }) { + const [openSelect, setOpenSelect] = useState(false) + const [selected, setSelected] = useState(title === '' ? options[0].name : title) + + const handleClickSelectOption = (option) => { + setSelected(option.name) + onChange?.(option) + } return ( -
setSelectAct(!selectAct)}> -

{title}

+
setOpenSelect(!openSelect)}> +

{selected}

    - {option.map((el, idx) => ( -
  • - + {options?.map((option) => ( +
  • +
  • ))}
diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index 5be6a114..71c48845 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -1,45 +1,47 @@ 'use client' -import { useState } from "react" -import CanvasFrame from "./CanvasFrame"; +import { useState } from 'react' +import CanvasFrame from './CanvasFrame' +import { useRecoilState, useRecoilValue } from 'recoil' +import { currentMenuState, stepState } from '@/store/canvasAtom' -export default function CanvasLayout () { - const [plans, setPlans] = useState([{ id: 0, name: 'Plan 1' }, { id: 1, name: 'Plan 2' }, { id: 2, name: 'Plan 3' }]); - const [idxNum, setIdxNum] = useState(null); +export default function CanvasLayout() { + const [plans, setPlans] = useState([ + { id: 0, name: 'Plan 1' }, + { id: 1, name: 'Plan 2' }, + { id: 2, name: 'Plan 3' }, + ]) + const [idxNum, setIdxNum] = useState(null) - const onClickPlane = (num) => { - setIdxNum(num); - } + const onClickPlane = (num) => { + setIdxNum(num) + } - const handleDeletePlan = (e, id) => { - e.stopPropagation(); // 이벤트 버블링 방지 - setPlans(plans.filter(plan => plan.id !== id)); // 삭제할 아이디와 다른 아이템만 남김 - } + const handleDeletePlan = (e, id) => { + e.stopPropagation() // 이벤트 버블링 방지 + setPlans(plans.filter((plan) => plan.id !== id)) // 삭제할 아이디와 다른 아이템만 남김 + } - const addNewPlan = () => { - setPlans([...plans, { id: plans.length, name: `Plan ${plans.length + 1}` }]); - } + const addNewPlan = () => { + setPlans([...plans, { id: plans.length, name: `Plan ${plans.length + 1}` }]) + } - return( -
-
-
- {plans.map((plan, idx) => ( - - ))} -
- -
- + return ( +
+
+
+ {plans.map((plan, idx) => ( + + ))}
- ) -} \ No newline at end of file + +
+ +
+ ) +} diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index cf5ada46..477cdfde 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -1,23 +1,79 @@ 'use client' -import { useState } from 'react' +import { useEffect, useState } from 'react' import MenuDepth01 from './MenuDepth01' -import { useRecoilState } from 'recoil' -import { modalState } from '@/store/modalAtom' import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' +import { post } from '@/lib/Axios' +import { useRecoilState } from 'recoil' +import { settingModalFirstOptionsState } from '@/store/settingAtom' -export default function CanvasMenu() { - const [modalOption, setModalOption] = useRecoilState(modalState) //modal 열림닫힘 state +export default function CanvasMenu(props) { + const [objectNo] = useState('test123240912001') + const { setShowCanvasSettingModal, showOutlineModal, setShowOutlineModal } = props const [menuNumber, setMenuNumber] = useState(null) const [vertical, setVertical] = useState(true) + const [type, setType] = useState('') const { getMessage } = useMessage() const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }] const onClickNav = (number) => { setMenuNumber(number) - if (menuNumber === number) { - setMenuNumber(null) + if (number === 2) setType('outline') + if (number === 3) setType('surface') + if (number === 4) setType('module') + } + const menuProps = { + setShowOutlineModal, + type, + } + + const settingsModalOptions = useRecoilState(settingModalFirstOptionsState) + + useEffect(() => {}, [menuNumber, type]) + + // 저장버튼(btn08) 클릭 시 호출되는 함수 + const handleSaveSettings = async () => { + try { + // 서버에 전송할 데이터 + const dataToSend = { + option1: settingsModalOptions[0].option1.map((item) => ({ + column: item.column, + selected: item.selected, + })), + option2: settingsModalOptions[0].option2.map((item) => ({ + column: item.column, + selected: item.selected, + })), + } + + const patternData = { + objectNo, + assignDisplay: dataToSend.option1[0].selected, + drawDisplay: dataToSend.option1[1].selected, + gridDisplay: dataToSend.option1[2].selected, + charDisplay: dataToSend.option1[3].selected, + flowDisplay: dataToSend.option1[4].selected, + hallwayDimenDisplay: dataToSend.option1[5].selected, + actualDimenDisplay: dataToSend.option1[6].selected, + noDimenDisplay: dataToSend.option1[7].selected, + trestleDisplay: dataToSend.option1[8].selected, + coordiDisplay: dataToSend.option1[9].selected, + drawConverDisplay: dataToSend.option1[10].selected, + onlyBorder: dataToSend.option2[0].selected, + lineHatch: dataToSend.option2[1].selected, + allPainted: dataToSend.option2[2].selected, + } + + // HTTP POST 요청 보내기 + await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }) + + // 응답 처리 + alert('설정이 저장되었습니다.') + } catch (error) { + console.error('설정을 저장하는 동안 오류가 발생했습니다:', error) + alert('설정을 저장하는 중 오류가 발생했습니다.') } } + return (
@@ -34,10 +90,15 @@ export default function CanvasMenu() { {getMessage('plan.menu.placement.surface.initial.setting')} -
  • onClickNav(2)}> +
  • { + onClickNav(2) + }} + >
  • onClickNav(3)}> @@ -73,15 +134,17 @@ export default function CanvasMenu() {
  • -
    - {getMessage('plan.mode.vertical.horizontal')} - -
    + {menuNumber !== 4 && ( +
    + {getMessage('plan.mode.vertical.horizontal')} + +
    + )}
    - +
    @@ -92,7 +155,7 @@ export default function CanvasMenu() {
    - +
    @@ -137,9 +200,7 @@ export default function CanvasMenu() {
    - {menuNumber === 2 && } - {menuNumber === 3 && } - {menuNumber === 4 && } + {(menuNumber === 2 || menuNumber === 3 || menuNumber === 4) && }
    ) diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index e7fe4225..206c41c4 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -1,20 +1,40 @@ 'use client' import CanvasMenu from '@/components/floor-plan/CanvasMenu' -import SettingModal01 from '@/components/floor-plan/modal/settoing01/SettingModal01' -import { useState } from 'react' +import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01' import CanvasLayout from '@/components/floor-plan/CanvasLayout' import '@/styles/contents.scss' +import OuterLineWall from '@/components/floor-plan/modal/outerlinesetting/OuterLineWall' +import { useEffect, useState } from 'react' export default function FloorPlan() { - const [modalOpen, setModalOpen] = useState('option') + const [showCanvasSettingModal, setShowCanvasSettingModal] = useState(false) + const [showOutlineModal, setShowOutlineModal] = useState(false) + + const canvasSettingProps = { + setShowCanvasSettingModal, + } + + const outlineProps = { + setShowOutlineModal, + } + + const modalProps = { + setShowCanvasSettingModal, + showOutlineModal, + setShowOutlineModal, + } + + useEffect(() => {}, [showOutlineModal]) + return ( <>
    - +
    - {modalOpen === 'option' && } + {showCanvasSettingModal && } + {showOutlineModal && }
    diff --git a/src/components/floor-plan/MenuDepth01.jsx b/src/components/floor-plan/MenuDepth01.jsx index ce4bd6a4..cf0ad1e8 100644 --- a/src/components/floor-plan/MenuDepth01.jsx +++ b/src/components/floor-plan/MenuDepth01.jsx @@ -2,33 +2,63 @@ import { ToggleonMouse } from '@/components/header/Header' import { useMessage } from '@/hooks/useMessage' +import { useEffect, useState } from 'react' -export default function MenuDepth01() { +export default function MenuDepth01(props) { + const { setShowOutlineModal, type } = props const { getMessage } = useMessage() + const [activeMenu, setActiveMenu] = useState() + const onClickMenu = (menuNum) => { + setActiveMenu(menuNum) + setShowOutlineModal(menuNum === 0) + } + + const menus = [ + { id: 0, name: '外壁線を描' }, + { id: 1, name: '補助線を描' }, + { id: 2, name: '屋根形状設定' }, + { id: 3, name: '軒下変更' }, + { id: 4, name: '外壁線の上げ下げ' }, + { id: 5, name: '銅線移動' }, + { id: 6, name: '特殊コーナー形状' }, + ] + + const menuInfo = { + outline: [ + // 지붕덮개 + { id: 0, name: 'plan.menu.roof.cover.outline.drawing' }, + { id: 1, name: 'plan.menu.roof.cover.roof.shape.setting' }, + { id: 2, name: 'plan.menu.roof.cover.roof.shape.edit' }, + { id: 3, name: 'plan.menu.roof.cover.auxiliary.line.drawing' }, + ], + surface: [ + // 배치면 + { id: 0, name: 'plan.menu.placement.surface.drawing' }, + { id: 1, name: 'plan.menu.placement.surface.surface' }, + { id: 2, name: 'plan.menu.placement.surface.object' }, + ], + module: [ + // 모듈, 회로 구성 + { id: 0, name: 'plan.menu.module.circuit.setting.default' }, + { id: 1, name: 'plan.menu.module.circuit.setting.circuit.trestle.setting' }, + ], + } + + useEffect(() => { + menus.forEach((menu) => { + menu.isActive = menu.id === activeMenu + }) + }, [menus, activeMenu]) return (
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • + {menuInfo[type].map((menu) => { + return ( +
    • + +
    • + ) + })}
    • ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}> diff --git a/src/components/floor-plan/RoofCoveringMenu.jsx b/src/components/floor-plan/RoofCoveringMenu.jsx new file mode 100644 index 00000000..26da4bda --- /dev/null +++ b/src/components/floor-plan/RoofCoveringMenu.jsx @@ -0,0 +1,54 @@ +'use client' + +import { useMessage } from '@/hooks/useMessage' +import { useRecoilState, useSetRecoilState } from 'recoil' +import { currentMenuState } from '@/store/canvasAtom' +import { MENU } from '@/common/common' +import { modalState } from '@/store/modalAtom' +import { ToggleonMouse } from '@/components/header/Header' + +export default function RoofCoveringMenu() { + const { getMessage } = useMessage() + const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState) + + const setModalState = useSetRecoilState(modalState) + + const onClickNav = (menu) => { + setCurrentMenu(menu) + if (menu === MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) { + setModalState((prev) => ({ ...prev, outerwall: true })) + } else { + setModalState((prev) => ({ ...prev, outerwall: false })) + } + } + + return ( +
      +
        +
      • + +
      • +
      • + +
      • +
      • + +
      • +
      • + +
      • +
      +
        +
      • ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}> + +
      • +
      • ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}> + +
      • +
      • ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}> + +
      • +
      +
      + ) +} diff --git a/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx b/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx new file mode 100644 index 00000000..c8a61e11 --- /dev/null +++ b/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx @@ -0,0 +1,470 @@ +'use client' + +import { useEffect, useRef } from 'react' +import WithDraggable from '@/components/common/draggable/withDraggable' +import { useRecoilState, useRecoilValue } from 'recoil' +import { useMessage } from '@/hooks/useMessage' +import { useEvent } from '@/hooks/useEvent' +import { canvasState } from '@/store/canvasAtom' +import { + OUTER_LINE_TYPE, + outerLineArrow1State, + outerLineArrow2State, + outerLineLength1State, + outerLineLength2State, + outerLinePointsState, + outerLineTypeState, +} from '@/store/outerLineAtom' +import { QLine } from '@/components/fabric/QLine' +import { useLine } from '@/hooks/useLine' + +export default function OuterLineWall(props) { + const { setShowOutlineModal } = props + const { getMessage } = useMessage() + const { addCanvasMouseEventListener, addDocumentEventListener, removeAllDocumentEventListeners } = useEvent() + const { addLineText, removeLineText } = useLine() + const length1Ref = useRef(null) + const length2Ref = useRef(null) + const [length1, setLength1] = useRecoilState(outerLineLength1State) + const [length2, setLength2] = useRecoilState(outerLineLength2State) + const [arrow1, setArrow1] = useRecoilState(outerLineArrow1State) + const [arrow2, setArrow2] = useRecoilState(outerLineArrow2State) + const [points, setPoints] = useRecoilState(outerLinePointsState) + const [type, setType] = useRecoilState(outerLineTypeState) + const arrow1Ref = useRef(arrow1) + const arrow2Ref = useRef(arrow2) + + const canvas = useRecoilValue(canvasState) + + useEffect(() => { + addCanvasMouseEventListener('mouse:down', mouseDown) + }, []) + + useEffect(() => { + arrow1Ref.current = arrow1 + }, [arrow1]) + + useEffect(() => { + arrow2Ref.current = arrow2 + }, [arrow2]) + + useEffect(() => { + removeAllDocumentEventListeners() + addDocumentEventListener('keydown', document, keydown[type]) + clear() + }, [type]) + + const clear = () => { + setLength1(0) + setLength2(0) + + setArrow1('') + setArrow2('') + } + + const mouseDown = (e) => { + const pointer = canvas.getPointer(e.e) + + setPoints((prev) => [...prev, pointer]) + } + + useEffect(() => { + canvas + ?.getObjects() + .filter((obj) => obj.name === 'outerLine') + .forEach((obj) => { + canvas?.remove(obj) + removeLineText(obj) + }) + canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'startPoint')) + if (points.length === 0) { + return + } + + if (points.length === 1) { + const point = new fabric.Circle({ + radius: 5, + fill: 'transparent', + stroke: 'red', + left: points[0].x - 5, + top: points[0].y - 5, + selectable: false, + name: 'startPoint', + }) + + canvas?.add(point) + } else { + points.forEach((point, idx) => { + if (idx === 0) { + return + } + drawLine(points[idx - 1], point, idx) + }) + } + }, [points]) + + const drawLine = (point1, point2, idx) => { + const line = new QLine([point1.x, point1.y, point2.x, point2.y], { + stroke: 'black', + strokeWidth: 1, + idx: idx, + selectable: false, + name: 'outerLine', + }) + + canvas?.add(line) + addLineText(line) + } + + // 직각 완료될 경우 확인 + const checkRightAngle = () => { + const length1Num = Number(length1Ref.current.value) / 10 + const length2Num = Number(length2Ref.current.value) / 10 + + if (points.length === 0) { + return + } + + if (length1Num === 0 || length2Num === 0 || arrow1Ref.current === '' || arrow2Ref.current === '') { + return + } + + if (arrow1Ref.current === '↓' && arrow2Ref.current === '→') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length2Num, y: prev[prev.length - 1].y + length1Num }] + }) + } else if (arrow1Ref.current === '↓' && arrow2Ref.current === '←') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length2Num, y: prev[prev.length - 1].y + length1Num }] + }) + } else if (arrow1Ref.current === '↑' && arrow2Ref.current === '→') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length2Num, y: prev[prev.length - 1].y - length1Num }] + }) + } else if (arrow1Ref.current === '↑' && arrow2Ref.current === '←') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length2Num, y: prev[prev.length - 1].y - length1Num }] + }) + } else if (arrow1Ref.current === '→' && arrow2Ref.current === '↓') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length1Num, y: prev[prev.length - 1].y + length2Num }] + }) + } else if (arrow1Ref.current === '→' && arrow2Ref.current === '↑') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + length1Num, y: prev[prev.length - 1].y - length2Num }] + }) + } else if (arrow1Ref.current === '←' && arrow2Ref.current === '↓') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length1Num, y: prev[prev.length - 1].y + length2Num }] + }) + } else if (arrow1Ref.current === '←' && arrow2Ref.current === '↑') { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - length1Num, y: prev[prev.length - 1].y - length2Num }] + }) + } + } + + const keydown = { + outerLine: (e) => { + const key = e.key + + if (!length1Ref.current) { + return + } + + const lengthNum = Number(length1Ref.current.value) / 10 + if (lengthNum === 0) { + return + } + switch (key) { + case 'Down': // IE/Edge에서 사용되는 값 + case 'ArrowDown': { + setArrow1('↓') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y + lengthNum }] + }) + break + } + case 'Up': // IE/Edge에서 사용되는 값 + case 'ArrowUp': + setArrow1('↑') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y - lengthNum }] + }) + break + case 'Left': // IE/Edge에서 사용되는 값 + case 'ArrowLeft': + setArrow1('←') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - lengthNum, y: prev[prev.length - 1].y }] + }) + break + case 'Right': // IE/Edge에서 사용되는 값 + case 'ArrowRight': + setArrow1('→') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + lengthNum, y: prev[prev.length - 1].y }] + }) + break + } + }, + rightAngle: (e) => { + const key = e.key + + const activeElem = document.activeElement + const length1Num = Number(length1Ref.current.value) / 10 + const length2Num = Number(length2Ref.current.value) / 10 + + switch (key) { + case 'Down': // IE/Edge에서 사용되는 값 + case 'ArrowDown': { + if (activeElem === length1Ref.current) { + setArrow1('↓') + arrow1Ref.current = '↓' + length2Ref.current.focus() + } else if (activeElem === length2Ref.current) { + if (arrow1Ref.current === '↓' || arrow1Ref.current === '↑') { + break + } + setArrow2('↓') + arrow2Ref.current = '↓' + checkRightAngle() + } + + break + } + case 'Up': // IE/Edge에서 사용되는 값 + case 'ArrowUp': + if (activeElem === length1Ref.current) { + setArrow1('↑') + arrow1Ref.current = '↑' + length2Ref.current.focus() + } else if (activeElem === length2Ref.current) { + if (arrow1Ref.current === '↓' || arrow1Ref.current === '↑') { + break + } + setArrow2('↑') + arrow2Ref.current = '↑' + checkRightAngle() + } + + break + case 'Left': // IE/Edge에서 사용되는 값 + case 'ArrowLeft': + if (activeElem === length1Ref.current) { + setArrow1('←') + arrow1Ref.current = '←' + length2Ref.current.focus() + } else if (activeElem === length2Ref.current) { + if (arrow1Ref.current === '←' || arrow1Ref.current === '→') { + break + } + setArrow2('←') + arrow2Ref.current = '←' + checkRightAngle() + } + + break + case 'Right': // IE/Edge에서 사용되는 값 + case 'ArrowRight': + if (activeElem === length1Ref.current) { + setArrow1('→') + arrow1Ref.current = '→' + length2Ref.current.focus() + } else if (activeElem === length2Ref.current) { + if (arrow1Ref.current === '←' || arrow1Ref.current === '→') { + break + } + setArrow2('→') + arrow2Ref.current = '→' + checkRightAngle() + } + + break + } + }, + leeGubae: (e) => { + console.log('leegubae') + }, + angle: (e) => { + console.log('angle') + }, + diagonalLine: (e) => { + console.log('diagonalLine') + }, + } + + /** + * 일변전으로 돌아가기 + */ + const handleRollback = () => { + //points의 마지막 요소를 제거 + setPoints((prev) => prev.slice(0, prev.length - 1)) + } + + const handleFix = () => { + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[0].x, y: prev[0].y }] + }) + } + return ( + +
      +
      +

      {getMessage('modal.cover.outline.drawing')}

      + +
      +
      +
      + + + + + + +
      +
      +

      {getMessage('modal.cover.outline.setting')}

      + {type === OUTER_LINE_TYPE.OUTER_LINE ? ( +
      +
      + + { + setLength1(e.target.value.replace(/[^-0-9]/g, '')) + }} + placeholder="3000" + /> +
      +
      + + +
      +
      + ) : type === OUTER_LINE_TYPE.RIGHT_ANGLE ? ( +
      +
      + + { + setLength1(e.target.value.replace(/[^-0-9]/g, '')) + }} + placeholder="3000" + /> +
      +
      + + +
      +
      + + { + setLength2(e.target.value.replace(/[^-0-9]/g, '')) + }} + placeholder="3000" + /> +
      +
      + + +
      +
      + ) : ( + <> + )} +
      + + + + +
      +
      +
      +
      +
      + ) +} diff --git a/src/components/floor-plan/modal/settoing01/FirstOption.jsx b/src/components/floor-plan/modal/setting01/FirstOption.jsx similarity index 55% rename from src/components/floor-plan/modal/settoing01/FirstOption.jsx rename to src/components/floor-plan/modal/setting01/FirstOption.jsx index cddab6c0..fd2577a5 100644 --- a/src/components/floor-plan/modal/settoing01/FirstOption.jsx +++ b/src/components/floor-plan/modal/setting01/FirstOption.jsx @@ -1,11 +1,58 @@ import { useRecoilState } from 'recoil' import { settingModalFirstOptionsState } from '@/store/settingAtom' import { useMessage } from '@/hooks/useMessage' +import React, { useEffect, useState } from 'react' +import { get } from '@/lib/Axios' export default function FirstOption() { + const [objectNo] = useState('test123240912001') const [settingsModalOptions, setSettingModalOptions] = useRecoilState(settingModalFirstOptionsState) const { option1, option2 } = settingsModalOptions const { getMessage } = useMessage() + + // 초기 조회 + useEffect(() => { + console.log('useEffect 실행') + fetchSettings() + }, []) + + // Canvas Setting 조회 및 초기화 + const fetchSettings = async () => { + try { + const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) + + // console.log(res) + + const options1 = [ + 'assignDisplay', + 'drawDisplay', + 'gridDisplay', + 'charDisplay', + 'flowDisplay', + 'hallwayDimenDisplay', + 'actualDimenDisplay', + 'noDimenDisplay', + 'trestleDisplay', + 'coordiDisplay', + 'drawConverDisplay', + ] + const option1 = settingsModalOptions.option1.map((item, index) => ({ ...item, selected: res[options1[index]] })) + + const options2 = ['onlyBorder', 'lineHatch', 'allPainted'] + const option2 = settingsModalOptions.option2.map((item, index) => ({ ...item, selected: res[options2[index]] })) + + // 데이터 설정 + setSettingModalOptions({ + option1, + option2, + // rangeSetting: data.rangeSetting, + // gridSettings: data.gridSettings, + }) + } catch (error) { + console.error('Data fetching error:', error) + } + } + const onClickOption = (option) => { option.selected = !option.selected diff --git a/src/components/floor-plan/modal/settoing01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx similarity index 68% rename from src/components/floor-plan/modal/settoing01/SecondOption.jsx rename to src/components/floor-plan/modal/setting01/SecondOption.jsx index 5b417f2b..499b316c 100644 --- a/src/components/floor-plan/modal/settoing01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -1,9 +1,11 @@ import { useRecoilState } from 'recoil' import { settingModalSecondOptionsState } from '@/store/settingAtom' +import { useMessage } from '@/hooks/useMessage' export default function SecondOption() { const [settingsModalOptions, setSettingModalOptions] = useRecoilState(settingModalSecondOptionsState) const { option1, option2 } = settingsModalOptions + const { getMessage } = useMessage() const onClickOption = (option) => { option.selected = !option.selected @@ -12,31 +14,31 @@ export default function SecondOption() { return ( <>
      -

      フォントとサイズの変更

      +

      {getMessage('modal.canvas.setting.font.plan.edit')}

      {settingsModalOptions.option1.map((item) => ( ))}
      -

      吸着範囲の設定

      +

      {getMessage('modal.canvas.setting.font.plan.absorption')}

      {settingsModalOptions.option2.map((item) => ( ))}
      diff --git a/src/components/floor-plan/modal/settoing01/SettingModal01.jsx b/src/components/floor-plan/modal/setting01/SettingModal01.jsx similarity index 66% rename from src/components/floor-plan/modal/settoing01/SettingModal01.jsx rename to src/components/floor-plan/modal/setting01/SettingModal01.jsx index 6c9969d2..6ce186b7 100644 --- a/src/components/floor-plan/modal/settoing01/SettingModal01.jsx +++ b/src/components/floor-plan/modal/setting01/SettingModal01.jsx @@ -3,27 +3,20 @@ import { useState } from 'react' import FirstOption from './FirstOption' import WithDraggable from '@/components/common/draggable/withDraggable' -import SecondOption from '@/components/floor-plan/modal/settoing01/SecondOption' +import SecondOption from '@/components/floor-plan/modal/setting01/SecondOption' import { useMessage } from '@/hooks/useMessage' -export default function SettingModal01({ modalOpen, setModalOpen }) { +export default function SettingModal01(props) { + const { setShowCanvasSettingModal } = props const [buttonAct, setButtonAct] = useState(1) - const [close, setClose] = useState(false) - const HandleClickClose = () => { - setClose(true) - setTimeout(() => { - setModalOpen('') - setClose(false) - }, 180) - } const { getMessage } = useMessage() return ( - -
      + +

      {getMessage('modal.canvas.setting')}

      -
      diff --git a/src/components/header/Header.jsx b/src/components/header/Header.jsx index f81a0ca7..e8a4e872 100644 --- a/src/components/header/Header.jsx +++ b/src/components/header/Header.jsx @@ -1,8 +1,11 @@ 'use client' +import { Fragment, useState } from 'react' import Link from 'next/link' -import QSelectBox from '@/components/common/select/QSelectBox' -import { usePathname } from 'next/navigation' +import { usePathname, useRouter } from 'next/navigation' import { useMessage } from '@/hooks/useMessage' +import { logout } from '@/lib/authActions' + +import QSelectBox from '@/components/common/select/QSelectBox' export const ToggleonMouse = (e, act, target) => { const listWrap = e.target.closest(target) @@ -19,101 +22,122 @@ export const ToggleonMouse = (e, act, target) => { } } -export default function Header() { +export default function Header(props) { + const { loginedUserNm } = props const { getMessage } = useMessage() const pathName = usePathname() - if (pathName.includes('login') || pathName.includes('join')) { - return null + // if (pathName.includes('login') || pathName.includes('join')) { + // return null + // } + const [selected, setSelected] = useState('') + + const SelectOptions = [ + { id: 0, name: 'オンライン保証シ', link: '' }, + { id: 1, name: 'ステム', link: '' }, + { id: 2, name: 'TEST1', link: 'https://www.weather.go.kr/w/index.do' }, + { id: 3, name: 'TEST2', link: 'https://www.google.com' }, + ] + const menus = [ + { id: 0, name: 'header.menus.home', url: '/', children: [] }, + { + id: 1, + name: 'header.menus.management', + url: '', + children: [ + { id: 3, name: 'header.menus.management.stuff', url: '/management/stuff', children: [] }, + { id: 4, name: 'header.menus.management.plan', url: '/floor-plan', children: [] }, + ], + }, + { + id: 2, + name: 'header.menus.community', + url: '', + children: [ + { id: 5, name: 'header.menus.community.notice', url: '/community/notice', children: [] }, + { id: 6, name: 'header.menus.community.faq', url: '/community/faq', children: [] }, + { id: 7, name: 'header.menus.community.archive', url: '/community/archive', children: [] }, + ], + }, + ] + + const onChangeSelect = (option) => { + setSelected(option) + } + const navPage = () => { + if (selected.link) { + location.href = selected.link + } + } + + const getMenuTemplate = (menus) => { + return menus.map((menu) => { + return ( +
    • ToggleonMouse(e, 'add', 'nav > ul')} + onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'nav > ul')} + > + {menu.children.length === 0 ? ( + + {getMessage(menu.name)} + + ) : ( + + +
        + {menu.children.map((m) => { + return ( +
      • ToggleonMouse(e, 'add', 'li > ul')} + onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'li > ul')} + > + {getMessage(m.name)} +
      • + ) + })} +
      +
      + )} +
    • + ) + }) } - const SelectOption = [{ name: 'オンライン保証シ' }, { name: 'ステム' }] return ( -
      -
      -
      -

      - -

      - -
      -
      -
      - + !(pathName.includes('login') || pathName.includes('join')) && ( +
      +
      +
      +

      + +

      +
      -
      - -
      -
      - -
      -
      - +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      -
      -
      +
      + ) ) } diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index cf427814..6f615c3c 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -6,7 +6,7 @@ import { Button } from '@nextui-org/react' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import StuffQGrid from './StuffQGrid' -import { useRecoilValue } from 'recoil' +import { useRecoilValue, useRecoilState } from 'recoil' import { stuffSearchState } from '@/store/stuffAtom' import { queryStringFormatter, isEmptyArray } from '@/util/common-utils' import dayjs from 'dayjs' @@ -15,10 +15,12 @@ dayjs.extend(isLeapYear) export default function Stuff() { const stuffSearchParams = useRecoilValue(stuffSearchState) + const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState) const { getMessage } = useMessage() const [curPage, setCurPage] = useState(1) //현재 페이지 번호 - const [size, setSize] = useState(100) //페이지 당 게시물 수 - const { get, del } = useAxios() + const [defaultSize, setDefaultSize] = useState(100) //페이지 당 게시물 수 + const [defaultSortType, setDefaultSortType] = useState('R') + const { get } = useAxios() const gridRef = useRef() const [gridCount, setGridCount] = useState(0) @@ -38,13 +40,26 @@ export default function Stuff() { } } + //물건번호 복사버튼 옆에 영역 + const onDoubleClick = (e) => { + let objectNo = e.target.innerText + console.log(objectNo) + if (objectNo.substring(0, 1) === 'R') { + console.log('진짜') + router.push(`${pathname}/detail?objectNo=${objectNo.toString()}`) + } else { + console.log('임시') + router.push(`${pathname}/tempdetail?objectNo=${objectNo.toString()}`) + } + } + const [gridProps, setGridProps] = useState({ gridData: [], isPageable: false, // sets 10 rows per page (default is 100) - paginationPageSize: 100, + // paginationPageSize: 100, // allows the user to select the page size from a predefined list of page sizes - paginationPageSizeSelector: [100, 200, 300, 400], + // paginationPageSizeSelector: [100, 200, 300, 400], gridColumns: [ { field: 'lastEditDatetime', @@ -82,7 +97,6 @@ export default function Stuff() {
      - {params.value} + {params.value}
      ) } @@ -148,8 +162,15 @@ export default function Stuff() { return } else { console.log(' 상세이동::::::::', event.data) + //T 면 임시 R은 진짜 if (event.data.objectNo) { - router.push(`${pathname}/detail?objectNo=${event.data.objectNo.toString()}`) + if (event.data.objectNo.substring(0, 1) === 'R') { + console.log('진짜:::::::::') + router.push(`${pathname}/detail?objectNo=${event.data.objectNo.toString()}`) + } else { + console.log('임시:::::::::::::::::') + router.push(`${pathname}/tempdetail?objectNo=${event.data.objectNo.toString()}`) + } } } } @@ -175,45 +196,6 @@ export default function Stuff() { errCount++ } }) - - async function fetchDelete(data) { - console.log('물건삭제API호출!!!!!!!!!', data) - //행추가말고 api데이터만 보냄 - // let newData = data.filter((item) => item.company != null) - // console.log('삭제에 전송되는 데이타::', newData) - // await del({ url: '', data:newData }) - await get({ url: 'https://www.ag-grid.com/example-assets/space-mission-data.json' }) - // try { - // const res = await del({url:'', data:newData}) - - // if(!res || res.length === 0) { - - // } else { - fetchData() - // } - // } catch (error) { - // console.error('Data Delete error:', error); - // } - } - - // 삭제API 완료 후 fetchData Api호출 - async function fetchData() { - console.log('물건삭제후 조회API호출!!!!!!!!!!!!!', stuffSearchParams) - const data = await get({ url: 'https://www.ag-grid.com/example-assets/space-mission-data.json' }) - setGridProps({ ...gridProps, gridData: data, count: data.length }) - setGridCount(data.length) - //data.length = 10 - //setGridProps({ ...gridProps, gridData: data, count: data.length-1}) - //setGridCount(data.length - 1 ) - } - - if (errCount === 0) { - // console.log('errCount::::::::', errCount) - fetchDelete(data) - // fetchData() - } else { - alert('물건정보가 있는 행만 선택해주세요') - } } //행추가 @@ -265,15 +247,14 @@ export default function Stuff() { schDateType: 'U', schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), schToDt: dayjs(new Date()).format('YYYY-MM-DD'), - startRow: (curPage - 1) * size + 1, - endRow: curPage * size, + startRow: (curPage - 1) * defaultSize + 1, + endRow: curPage * defaultSize, + schSelSaleStoreId: '', + schSortType: 'R', } async function fetchData() { console.log('화면진입:::::::::::::', params) - console.log('현재페이지::::::', curPage) - console.log('페이지당 게시물수::::::', size) - //api에 넘길값 startRow, endRow // let startRow // let endRow @@ -288,7 +269,8 @@ export default function Stuff() { // let size // let pageCount - const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(params)}` + // const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(params)}` + const apiUrl = `/api/object/list?saleStoreId=X167&${queryStringFormatter(params)}` await get({ url: apiUrl, @@ -306,14 +288,21 @@ export default function Stuff() { useEffect(() => { if (stuffSearchParams?.code === 'E') { + stuffSearchParams.startRow = (curPage - 1) * defaultSize + 1 + stuffSearchParams.endRow = curPage * defaultSize + stuffSearchParams.schSortType = defaultSortType console.log('조회 눌럿을때 ::::::::::::::', stuffSearchParams) async function fetchData() { - const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}` + // const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}` + const apiUrl = `/api/object/list?saleStoreId=X167&${queryStringFormatter(stuffSearchParams)}` await get({ url: apiUrl }).then((res) => { console.log('API결과:::::::', res) if (!isEmptyArray(res)) { setGridProps({ ...gridProps, gridData: res, count: res.length }) setGridCount(res.length) + } else { + setGridProps({ ...gridProps, gridData: [], count: 0 }) + setGridCount(0) } }) } @@ -321,6 +310,58 @@ export default function Stuff() { } }, [stuffSearchParams]) + //페이지 갯수 변경 이벤트 + const onChangePerPage = (e) => { + let startRow = (curPage - 1) * e.target.value + 1 + stuffSearchParams.startRow = startRow + stuffSearchParams.endRow = curPage * e.target.value + setDefaultSize(e.target.value) + setStuffSearch({ + ...stuffSearch, + code: 'S', + startRow: startRow, + endRow: curPage * e.target.value, + }) + console.log('셋팅된 검색조건:::', stuffSearchParams) + //조회API호출 + // const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}` + const apiUrl = `/api/object/list?saleStoreId=X167&${queryStringFormatter(stuffSearchParams)}` + get({ url: apiUrl }).then((res) => { + console.log('보여줄개수바꿨을때 조회 ::::::::::', res) + if (!isEmptyArray(res)) { + setGridProps({ ...gridProps, gridData: res, count: res.length }) + setGridCount(res.length) + } else { + setGridProps({ ...gridProps, gridData: [], count: 0 }) + setGridCount(0) + } + }) + } + + //최근 등록일 수정일 정렬 이벤트 + const onChangeSortType = (e) => { + stuffSearchParams.schSortType = e.target.value + console.log('셋팅된 검색조건:::', stuffSearchParams) + setDefaultSortType(e.target.value) + setStuffSearch({ + ...stuffSearch, + code: 'S', + schSortType: e.target.value, + }) + // const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}` + const apiUrl = `/api/object/list?saleStoreId=X167&${queryStringFormatter(stuffSearchParams)}` + // console.log('apiUrl::', apiUrl) + get({ url: apiUrl }).then((res) => { + console.log('정렬바꿨을때 조회 ::::::::::', res) + if (!isEmptyArray(res)) { + setGridProps({ ...gridProps, gridData: res, count: res.length }) + setGridCount(res.length) + } else { + setGridProps({ ...gridProps, gridData: [], count: 0 }) + setGridCount(0) + } + }) + } return ( <>
      @@ -328,6 +369,15 @@ export default function Stuff() { 전체 : {gridCount} // 선택 : {selectedRowDataCount} + +
      {/* + {!isFormValid ? ( + <> + + + ) : ( + + )} + + + - )) ||
      상세:::::::::::
      } - - {/*
      -
      - 물건번호 - {objectNo} -
      -
      - 사양확정일 - {detailData?.specDate ? dayjs(detailData.specDate).format('YYYY.MM.DD') : null} -
      -
      - 갱신일시 - - {detailData?.lastEditDatetime - ? dayjs(detailData.lastEditDatetime).format('YYYY.MM.DD HH:mm:ss') - : detailData?.createDatetime - ? dayjs(detailData.createDatetime).format('YYYY.MM.DD HH:mm:ss') - : null} - -
      -
      - 등록일 - -
      -
      */} - {/*
      (*필수 입력항목)
      - -
      - setName2(e.target.value)} /> -
      -
      - -
      -
      - 물건명 후리가나 - setName3(e.target.value)} /> -
      -
      */} - {/*
      - 판매점명 /ID * -
      - - {(option) => {option.name}} - -
      -
      */} - {/*
      - 우편번호* - - - *우편번호 7자리를 입력한 후, 주소검색 버튼을 클릭해 주십시오 -
      */} - {/*
      - 도도부현 / 주소* - -
      */} - {/*
      - 발전량시뮬레이션지역* - -
      -
      - 기준풍속* - - m/s이하 -
      -
      - 수직적설량* - cm - - 한랭지대책시행 - -
      */} - {/*
      - 면조도구분* - { - setGubun2(e.target.value) - }} - /> - - { - setGubun2(e.target.value) - }} - /> - - - 염해지역용아이템사용 - -
      -
      - 설치높이* - - m -
      -
      - 계약조건 - { - setGubun3(e.target.value) - }} - /> - - { - setGubun3(e.target.value) - }} - /> - -
      -
      - 메모 -