[QCAST] 로그인, 가입신청 수정 및 내정보팝업, 커뮤니티(공지사항, FAQ, 자료다운로드) 추가
This commit is contained in:
parent
7da045d397
commit
41c8fea594
@ -17,6 +17,7 @@
|
|||||||
"framer-motion": "^11.2.13",
|
"framer-motion": "^11.2.13",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"iron-session": "^8.0.2",
|
"iron-session": "^8.0.2",
|
||||||
|
"js-cookie": "^3.0.5",
|
||||||
"mathjs": "^13.0.2",
|
"mathjs": "^13.0.2",
|
||||||
"mssql": "^11.0.1",
|
"mssql": "^11.0.1",
|
||||||
"next": "14.2.3",
|
"next": "14.2.3",
|
||||||
|
|||||||
@ -7,10 +7,7 @@ export default async function CommunityArchivePage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Hero title="자료 다운로드" />
|
<Archive />
|
||||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
|
||||||
<Archive />
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import Hero from '@/components/Hero'
|
|
||||||
import Faq from '@/components/community/Faq'
|
import Faq from '@/components/community/Faq'
|
||||||
import { initCheck } from '@/util/session-util'
|
import { initCheck } from '@/util/session-util'
|
||||||
|
|
||||||
@ -7,10 +6,7 @@ export default async function CommunityFaqPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Hero title="FAQ" />
|
<Faq />
|
||||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
|
||||||
<Faq />
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import Hero from '@/components/Hero'
|
|
||||||
import Notice from '@/components/community/Notice'
|
import Notice from '@/components/community/Notice'
|
||||||
import { initCheck } from '@/util/session-util'
|
import { initCheck } from '@/util/session-util'
|
||||||
|
|
||||||
@ -7,10 +6,7 @@ export default async function CommunityNoticePage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Hero title="공지사항" />
|
<Notice />
|
||||||
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
|
|
||||||
<Notice />
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,9 @@
|
|||||||
'use client'
|
import JoinComplete from '@/components/auth/JoinComplete'
|
||||||
|
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
|
||||||
|
|
||||||
export default function CompletePage() {
|
|
||||||
const { getMessage } = useMessage()
|
|
||||||
|
|
||||||
|
export default function JoinCompletePage() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
|
<JoinComplete />
|
||||||
<h1 className="text-center text-4xl font-bold mb-10">{getMessage('join.complete.title')}</h1>
|
|
||||||
<div className="mt-10 mb-10 w-full text-center text-2xl">{getMessage('join.complete.contents')}</div>
|
|
||||||
<div className="mt-10 w-full text-center">
|
|
||||||
{getMessage('join.complete.email_comment')} : {getMessage('join.complete.email')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import { headers } from 'next/headers'
|
|||||||
import { redirect } from 'next/navigation'
|
import { redirect } from 'next/navigation'
|
||||||
import { getSession } from '@/lib/authActions'
|
import { getSession } from '@/lib/authActions'
|
||||||
import RecoilRootWrapper from './RecoilWrapper'
|
import RecoilRootWrapper from './RecoilWrapper'
|
||||||
import UIProvider from './UIProvider'
|
|
||||||
|
|
||||||
import { ToastContainer } from 'react-toastify'
|
import { ToastContainer } from 'react-toastify'
|
||||||
|
|
||||||
@ -14,6 +13,7 @@ import QModal from '@/components/common/modal/QModal'
|
|||||||
|
|
||||||
import './globals.css'
|
import './globals.css'
|
||||||
import '../styles/style.scss'
|
import '../styles/style.scss'
|
||||||
|
import '../styles/contents.scss'
|
||||||
import Dimmed from '@/components/ui/Dimmed'
|
import Dimmed from '@/components/ui/Dimmed'
|
||||||
|
|
||||||
// const inter = Inter({ subsets: ['latin'] })
|
// const inter = Inter({ subsets: ['latin'] })
|
||||||
@ -61,18 +61,21 @@ export default async function RootLayout({ children }) {
|
|||||||
<RecoilRootWrapper>
|
<RecoilRootWrapper>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body>
|
<body>
|
||||||
{headerPathname !== '/login' ? (
|
{headerPathname === '/login' || headerPathname === '/join' ? (
|
||||||
|
<QcastProvider>{children}</QcastProvider>
|
||||||
|
) : (
|
||||||
<div className="wrap">
|
<div className="wrap">
|
||||||
<Header userSession={sessionProps} />
|
<Header userSession={sessionProps} />
|
||||||
<UIProvider>
|
<div className="content">
|
||||||
<div className="content">
|
<Dimmed />
|
||||||
<Dimmed />
|
<QcastProvider>{children}</QcastProvider>
|
||||||
<QcastProvider>{children}</QcastProvider>
|
</div>
|
||||||
|
<footer>
|
||||||
|
<div className="footer-inner">
|
||||||
|
<span>COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</span>
|
||||||
</div>
|
</div>
|
||||||
</UIProvider>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<QcastProvider>{children}</QcastProvider>
|
|
||||||
)}
|
)}
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
<QModal />
|
<QModal />
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import Login from '@/components/auth/Login'
|
import Login from '@/components/auth/Login'
|
||||||
import NewLogin from '@/components/auth/NewLogin'
|
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NewLogin />
|
<Login />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,30 +1,27 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useAxios } from '@/hooks/useAxios'
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
import { redirect } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
export default function Join() {
|
export default function Join() {
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const { post } = useAxios()
|
const { post } = useAxios()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 가입 신청
|
||||||
const joinProcess = async (formData) => {
|
const joinProcess = async (formData) => {
|
||||||
|
formData.preventDefault()
|
||||||
|
|
||||||
const param = {
|
const param = {
|
||||||
langCd: 'JA',
|
|
||||||
lastEditUser: formData.get('userId'),
|
|
||||||
storeQcastNm: formData.get('storeQcastNm'),
|
storeQcastNm: formData.get('storeQcastNm'),
|
||||||
storeQcastNmKana: formData.get('storeQcastNmKana'),
|
storeQcastNmKana: formData.get('storeQcastNmKana'),
|
||||||
postCd: formData.get('postCd'),
|
postCd: formData.get('postCd'),
|
||||||
addr: formData.get('addr'),
|
addr: formData.get('addr'),
|
||||||
telNo: formData.get('telNo'),
|
telNo: formData.get('telNo'),
|
||||||
fax: formData.get('fax'),
|
fax: formData.get('fax'),
|
||||||
payTermsCd: 'JB02',
|
bizNo: formData.get('bizNo'),
|
||||||
kamId: 'E1101011',
|
|
||||||
qtCompNm: formData.get('qtCompNm'),
|
|
||||||
qtPostCd: formData.get('qtPostCd'),
|
|
||||||
qtAddr: formData.get('qtAddr'),
|
|
||||||
qtTelNo: formData.get('qtTelNo'),
|
|
||||||
qtFax: formData.get('qtFax'),
|
|
||||||
userInfo: {
|
userInfo: {
|
||||||
userId: formData.get('userId'),
|
userId: formData.get('userId'),
|
||||||
userNm: formData.get('userNm'),
|
userNm: formData.get('userNm'),
|
||||||
@ -39,7 +36,8 @@ export default function Join() {
|
|||||||
await post({ url: '/api/login/v1.0/user/join', data: param }).then((res) => {
|
await post({ url: '/api/login/v1.0/user/join', data: param }).then((res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
if (res.result.resultCode == 'S') {
|
if (res.result.resultCode == 'S') {
|
||||||
redirect('/join/complete')
|
Cookies.set('joinEmail', formData.get('email'), { expires: 1 })
|
||||||
|
router.push('/join/complete')
|
||||||
} else {
|
} else {
|
||||||
alert(res.result.resultMsg)
|
alert(res.result.resultMsg)
|
||||||
}
|
}
|
||||||
@ -48,275 +46,249 @@ export default function Join() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
|
<div className="center-page-wrap">
|
||||||
<h1 className="text-center text-4xl font-bold">{getMessage('join.title')}</h1>
|
<div className="center-page-inner">
|
||||||
<form action={joinProcess}>
|
<form onSubmit={joinProcess}>
|
||||||
<div className="mt-10">
|
<div className="center-page-tit">{getMessage('join.title')}</div>
|
||||||
<div>
|
<div className="sub-table-box signup">
|
||||||
● {getMessage('join.sub1.title')} (*{getMessage('common.require')}) <span>{getMessage('join.sub1.comment')}</span>
|
<div className="table-box-title-wrap">
|
||||||
|
<div className="title-wrap">
|
||||||
|
<h3>
|
||||||
|
{getMessage('join.sub1.title')} <span className="important">(*{getMessage('common.require')})</span>
|
||||||
|
</h3>
|
||||||
|
<span className="option">{getMessage('join.sub1.comment')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="common-table">
|
||||||
|
<table>
|
||||||
|
<colgroup>
|
||||||
|
<col style={{ width: '180px' }} />
|
||||||
|
<col />
|
||||||
|
</colgroup>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{getMessage('join.sub1.storeQcastNm')} <span className="important">*</span>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap" style={{ width: '700px' }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="storeQcastNm"
|
||||||
|
name="storeQcastNm"
|
||||||
|
required
|
||||||
|
alt={getMessage('join.sub1.storeQcastNm')}
|
||||||
|
className="input-light"
|
||||||
|
placeholder={getMessage('join.sub1.storeQcastNm_placeholder')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{getMessage('join.sub1.storeQcastNmKana')} <span className="important">*</span>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap" style={{ width: '700px' }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="storeQcastNmKana"
|
||||||
|
name="storeQcastNmKana"
|
||||||
|
required
|
||||||
|
className="input-light"
|
||||||
|
placeholder={getMessage('join.sub1.storeQcastNmKana_placeholder')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{getMessage('join.sub1.postCd')}/{getMessage('join.sub1.addr')} <span className="important">*</span>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<div className="flx-box">
|
||||||
|
<div className="input-wrap mr5" style={{ width: '200px' }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="postCd"
|
||||||
|
name="postCd"
|
||||||
|
required
|
||||||
|
className="input-light"
|
||||||
|
placeholder={getMessage('join.sub1.postCd_placeholder')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="input-wrap" style={{ width: '495px' }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="addr"
|
||||||
|
name="addr"
|
||||||
|
required
|
||||||
|
className="input-light"
|
||||||
|
placeholder={getMessage('join.sub1.addr_placeholder')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{getMessage('join.sub1.telNo')} <span className="important">*</span>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="telNo"
|
||||||
|
name="telNo"
|
||||||
|
required
|
||||||
|
className="input-light"
|
||||||
|
placeholder={getMessage('join.sub1.telNo_placeholder')}
|
||||||
|
></input>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{getMessage('join.sub1.fax')} <span className="important">*</span>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="fax"
|
||||||
|
name="fax"
|
||||||
|
required
|
||||||
|
className="input-light"
|
||||||
|
placeholder={getMessage('join.sub1.fax_placeholder')}
|
||||||
|
></input>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{getMessage('join.sub1.bizNo')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
|
<input type="text" id="bizNo" name="bizNo" className="input-light" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table className="w-full">
|
<div className="sub-table-box signup">
|
||||||
<colgroup>
|
<div className="table-box-title-wrap">
|
||||||
<col style={{ width: '20%' }} />
|
<div className="title-wrap">
|
||||||
<col style={{ width: '80%' }} />
|
<h3>
|
||||||
</colgroup>
|
{getMessage('join.sub2.title')} <span className="important">(*{getMessage('common.require')})</span>
|
||||||
<tbody>
|
</h3>
|
||||||
<tr>
|
</div>
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub1.storeQcastNm')} *</th>
|
</div>
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
<div className="common-table">
|
||||||
<input
|
<table>
|
||||||
type="text"
|
<colgroup>
|
||||||
id="storeQcastNm"
|
<col style={{ width: '180px' }} />
|
||||||
name="storeQcastNm"
|
<col />
|
||||||
required
|
</colgroup>
|
||||||
alt={getMessage('join.sub1.storeQcastNm')}
|
<tbody>
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
<tr>
|
||||||
placeholder={getMessage('join.sub1.storeQcastNm_placeholder')}
|
<th>
|
||||||
></input>
|
{getMessage('join.sub2.userNm')} <span className="important">*</span>
|
||||||
</td>
|
</th>
|
||||||
</tr>
|
<td>
|
||||||
<tr>
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub1.storeQcastNmKana')} *</th>
|
<input type="text" id="userNm" name="userNm" required className="input-light" />
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
</div>
|
||||||
<input
|
</td>
|
||||||
type="text"
|
</tr>
|
||||||
id="storeQcastNmKana"
|
<tr>
|
||||||
name="storeQcastNmKana"
|
<th>{getMessage('join.sub2.userNmKana')}</th>
|
||||||
required
|
<td>
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
placeholder={getMessage('join.sub1.storeQcastNmKana_placeholder')}
|
<input type="text" id="userNmKana" name="userNmKana" className="input-light" />
|
||||||
></input>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>
|
<th>
|
||||||
{getMessage('join.sub1.postCd')}/{getMessage('join.sub1.addr')} *
|
{getMessage('join.sub2.userId')} <span className="important">*</span>
|
||||||
</th>
|
</th>
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
<td>
|
||||||
<input
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
type="text"
|
<input type="text" id="userId" name="userId" className="input-light" />
|
||||||
id="postCd"
|
</div>
|
||||||
name="postCd"
|
</td>
|
||||||
required
|
</tr>
|
||||||
className="block border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
<tr>
|
||||||
placeholder={getMessage('join.sub1.postCd_placeholder')}
|
<th>
|
||||||
></input>
|
{getMessage('join.sub2.email')} <span className="important">*</span>
|
||||||
<input
|
</th>
|
||||||
type="text"
|
<td>
|
||||||
id="addr"
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
name="addr"
|
<input type="text" id="email" name="email" className="input-light" />
|
||||||
required
|
</div>
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
</td>
|
||||||
placeholder={getMessage('join.sub1.addr_placeholder')}
|
</tr>
|
||||||
></input>
|
<tr>
|
||||||
</td>
|
<th>
|
||||||
</tr>
|
{getMessage('join.sub2.telNo')} <span className="important">*</span>
|
||||||
<tr>
|
</th>
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub1.telNo')} *</th>
|
<td>
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="telNo"
|
id="userTelNo"
|
||||||
name="telNo"
|
name="userTelNo"
|
||||||
required
|
className="input-light"
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
placeholder={getMessage('join.sub2.telNo_placeholder')}
|
||||||
placeholder={getMessage('join.sub1.telNo_placeholder')}
|
/>
|
||||||
></input>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub1.fax')} *</th>
|
<th>
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
{getMessage('join.sub2.fax')} <span className="important">*</span>
|
||||||
<input
|
</th>
|
||||||
type="text"
|
<td>
|
||||||
id="fax"
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
name="fax"
|
<input
|
||||||
required
|
type="text"
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
id="userFax"
|
||||||
placeholder={getMessage('join.sub1.fax_placeholder')}
|
name="userFax"
|
||||||
></input>
|
className="input-light"
|
||||||
</td>
|
placeholder={getMessage('join.sub1.fax_placeholder')}
|
||||||
</tr>
|
/>
|
||||||
</tbody>
|
</div>
|
||||||
</table>
|
</td>
|
||||||
|
</tr>
|
||||||
<div className="mt-5">
|
<tr>
|
||||||
● {getMessage('join.sub2.title')} (*{getMessage('common.require')})
|
<th>{getMessage('join.sub2.category')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
|
<input type="text" id="category" name="category" className="input-light" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table className="w-full">
|
<div className="sign-up-btn-wrap">
|
||||||
<colgroup>
|
<button
|
||||||
<col style={{ width: '20%' }} />
|
type="button"
|
||||||
<col style={{ width: '80%' }} />
|
className="btn-origin grey mr5"
|
||||||
</colgroup>
|
onClick={() => {
|
||||||
<tbody>
|
router.push('/login')
|
||||||
<tr>
|
}}
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub2.userNm')} *</th>
|
>
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
{getMessage('join.btn.login_page')}
|
||||||
<input
|
</button>
|
||||||
type="text"
|
<button type="submit" className="btn-origin navy">
|
||||||
id="userNm"
|
{getMessage('join.btn.approval_request')}
|
||||||
name="userNm"
|
</button>
|
||||||
required
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub2.userNmKana')} *</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="userNmKana"
|
|
||||||
name="userNmKana"
|
|
||||||
required
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub2.userId')} *</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="userId"
|
|
||||||
name="userId"
|
|
||||||
required
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub2.email')} *</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
id="email"
|
|
||||||
name="email"
|
|
||||||
required
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
autoComplete="email"
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub2.telNo')} *</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="userTelNo"
|
|
||||||
name="userTelNo"
|
|
||||||
required
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
placeholder={getMessage('join.sub2.telNo_placeholder')}
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub2.fax')} *</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="userFax"
|
|
||||||
name="userFax"
|
|
||||||
required
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
placeholder={getMessage('join.sub1.fax_placeholder')}
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub2.category')}</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input id="category" name="category" className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div className="mt-5">
|
|
||||||
● {getMessage('join.sub3.title')} (*{getMessage('common.require')})
|
|
||||||
</div>
|
</div>
|
||||||
<table className="w-full">
|
</form>
|
||||||
<colgroup>
|
</div>
|
||||||
<col style={{ width: '20%' }} />
|
|
||||||
<col style={{ width: '80%' }} />
|
|
||||||
</colgroup>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub3.qtCompNm')}</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input type="text" id="qtCompNm" name="qtCompNm" className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
{getMessage('join.sub3.qtPostCd')}/{getMessage('join.sub3.qtAddr')}
|
|
||||||
</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="qtPostCd"
|
|
||||||
name="qtPostCd"
|
|
||||||
className="block border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
placeholder={getMessage('join.sub3.qtPostCd_placeholder')}
|
|
||||||
></input>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="qtAddr"
|
|
||||||
name="qtAddr"
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
placeholder={getMessage('join.sub3.qtAddr_placeholder')}
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub3.qtEmail')}</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
id="qtEmail"
|
|
||||||
name="qtEmail"
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
autoComplete="email"
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub3.qtTelNo')}</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="qtTelNo"
|
|
||||||
name="qtTelNo"
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
placeholder={getMessage('join.sub3.qtTelNo_placeholder')}
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th style={{ border: '1px solid gray', padding: '5px' }}>{getMessage('join.sub3.qtFax')}</th>
|
|
||||||
<td style={{ border: '1px solid gray', padding: '5px' }}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="qtFax"
|
|
||||||
name="qtFax"
|
|
||||||
className="block w-full border-0 py-1.5 ring-1 ring-inset ring-gray-300"
|
|
||||||
placeholder={getMessage('join.sub3.qtFax_placeholder')}
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div className="mt-10 mb-10">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
|
||||||
>
|
|
||||||
{getMessage('join.btn.approval_request')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/components/auth/JoinComplete.jsx
Normal file
44
src/components/auth/JoinComplete.jsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
|
export default function JoinComplete() {
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
const [emailText, setEmailText] = useState(Cookies.get('joinEmail'))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="center-page-wrap">
|
||||||
|
<div className="center-page-inner complete">
|
||||||
|
<div className="sub-table-box">
|
||||||
|
<div className="complete-box-wrap">
|
||||||
|
<div className="complete-tit">{getMessage('join.complete.title')}</div>
|
||||||
|
<div className="complete-txt">{getMessage('join.complete.contents')}</div>
|
||||||
|
<div className="complete-email-wrap">
|
||||||
|
<div className="email-info">
|
||||||
|
{getMessage('join.complete.email_comment')}: <span>{emailText}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="complete-btn">
|
||||||
|
<button
|
||||||
|
tyep="button"
|
||||||
|
className="btn-origin navy"
|
||||||
|
onClick={() => {
|
||||||
|
router.push('/login')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getMessage('join.btn.login_page')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,62 +1,45 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useState } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useRecoilState } from 'recoil'
|
||||||
import { useAxios } from '@/hooks/useAxios'
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
import { setSession } from '@/lib/authActions'
|
import { setSession } from '@/lib/authActions'
|
||||||
import { redirect } from 'next/navigation'
|
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
|
||||||
import { Button, Switch } from '@nextui-org/react'
|
|
||||||
import { useRecoilState } from 'recoil'
|
|
||||||
import { globalLocaleStore } from '@/store/localeAtom'
|
import { globalLocaleStore } from '@/store/localeAtom'
|
||||||
import { modalContent, modalState } from '@/store/modalAtom'
|
|
||||||
import { sessionStore } from '@/store/commonAtom'
|
import { sessionStore } from '@/store/commonAtom'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const { patch } = useAxios()
|
const [userId, setUserId] = useState('')
|
||||||
|
const [checkId, setCheckId] = useState('')
|
||||||
|
const [checkEmail, setCheckEmail] = useState('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (Cookies.get('chkLoginId')) {
|
||||||
|
setUserId(Cookies.get('chkLoginId'))
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const [chkLoginId, setChkLoginId] = useState(Cookies.get('chkLoginId') ? true : false)
|
||||||
|
const [passwordVisible, setPasswordVisible] = useState(false)
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const [globalLocaleState, setGlbalLocaleState] = useRecoilState(globalLocaleStore)
|
const [globalLocaleState, setGlbalLocaleState] = useRecoilState(globalLocaleStore)
|
||||||
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
||||||
const [isSelected, setIsSelected] = useState(globalLocaleState === 'ko' ? true : false)
|
|
||||||
|
|
||||||
const handleSelected = () => {
|
const [passwordReset, setPasswordReset] = useState(1)
|
||||||
if (isSelected) {
|
|
||||||
setGlbalLocaleState('ja')
|
|
||||||
} else {
|
|
||||||
setGlbalLocaleState('ko')
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsSelected(!isSelected)
|
const { post, patch } = useAxios(globalLocaleState)
|
||||||
}
|
|
||||||
|
|
||||||
// login process
|
// login process
|
||||||
const loginProcess = async (formData) => {
|
const loginProcess = async (e) => {
|
||||||
const param = {
|
e.preventDefault()
|
||||||
// langCd: currentLocale
|
const formData = new FormData(e.target)
|
||||||
langCd: globalLocaleState,
|
|
||||||
lastEditUser: formData.get('id'),
|
|
||||||
loginId: formData.get('id'),
|
|
||||||
pwd: formData.get('password'),
|
|
||||||
}
|
|
||||||
|
|
||||||
// await post({ url: '/api/login/v1.0/login', data: param }).then((res) => {
|
|
||||||
// if (res) {
|
|
||||||
// if (res.result.resultCode == 'S') {
|
|
||||||
// // console.log('res.data', res.data)
|
|
||||||
// // 비밀번호 초기화가 필요한 경우
|
|
||||||
// // if (res.data.pwdInitYn != 'Y') {
|
|
||||||
// // alert('비밀번호 초기화가 필요한 경우')
|
|
||||||
// // } else {
|
|
||||||
// setSession(res.data)
|
|
||||||
// redirect('/')
|
|
||||||
// // }
|
|
||||||
// } else {
|
|
||||||
// alert(res.result.resultMsg)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
// 임시 로그인 처리
|
// 임시 로그인 처리
|
||||||
setSession({
|
setSession({
|
||||||
userId: 'NEW016610',
|
userId: 'NEW016610',
|
||||||
@ -71,7 +54,7 @@ export default function Login() {
|
|||||||
telNo: '336610',
|
telNo: '336610',
|
||||||
fax: null,
|
fax: null,
|
||||||
email: 't10t@naver.com',
|
email: 't10t@naver.com',
|
||||||
pwdInitYn: 'N',
|
pwdInitYn: 'Y',
|
||||||
})
|
})
|
||||||
|
|
||||||
setSessionState({
|
setSessionState({
|
||||||
@ -87,155 +70,226 @@ export default function Login() {
|
|||||||
telNo: '336610',
|
telNo: '336610',
|
||||||
fax: null,
|
fax: null,
|
||||||
email: 't10t@naver.com',
|
email: 't10t@naver.com',
|
||||||
pwdInitYn: 'N',
|
pwdInitYn: 'Y',
|
||||||
})
|
})
|
||||||
|
|
||||||
redirect('/')
|
// ID SAVE 체크되어 있는 경우, 쿠키 저장
|
||||||
|
if (chkLoginId) {
|
||||||
|
Cookies.set('chkLoginId', formData.get('id'), { expires: 7 })
|
||||||
|
} else {
|
||||||
|
Cookies.remove('chkLoginId')
|
||||||
|
}
|
||||||
|
|
||||||
|
router.push('/')
|
||||||
// 임시 로그인 처리 끝
|
// 임시 로그인 처리 끝
|
||||||
|
|
||||||
|
// 로그인 처리 시작 - ** 상단 임시 로그인 추후 삭제 필요 **
|
||||||
|
// const param = {
|
||||||
|
// loginId: formData.get('id'),
|
||||||
|
// pwd: formData.get('password'),
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const res = await post({ url: '/api/login/v1.0/login', data: param })
|
||||||
|
|
||||||
|
// if (res) {
|
||||||
|
// if (res.result.resultCode == 'S') {
|
||||||
|
// setSession(res.data)
|
||||||
|
// setSessionState(res.data)
|
||||||
|
|
||||||
|
// // ID SAVE 체크되어 있는 경우, 쿠키 저장
|
||||||
|
// if (chkLoginId) {
|
||||||
|
// Cookies.set('chkLoginId', formData.get('id'), { expires: 7 })
|
||||||
|
// } else {
|
||||||
|
// Cookies.remove('chkLoginId')
|
||||||
|
// }
|
||||||
|
|
||||||
|
// router.push('/')
|
||||||
|
// } else {
|
||||||
|
// alert(res.result.resultMsg)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 비밀번호 초기화 관련
|
// 비밀번호 초기화 관련
|
||||||
const [open, setOpen] = useRecoilState(modalState)
|
const initPasswordProcess = async () => {
|
||||||
const [contents, setContent] = useRecoilState(modalContent)
|
|
||||||
|
|
||||||
const initPasswordProcess = async (formData) => {
|
|
||||||
const param = {
|
const param = {
|
||||||
langCd: currentLocale,
|
loginId: checkId,
|
||||||
lastEditUser: formData.get('checkId'),
|
email: checkEmail,
|
||||||
loginId: formData.get('checkId'),
|
|
||||||
email: formData.get('checkEmail'),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await patch({ url: '/api/login/v1.0/user/init-password', data: param }).then((res) => {
|
const res = await patch({
|
||||||
if (res) {
|
url: '/api/login/v1.0/user/init-password',
|
||||||
if (res.result.resultCode == 'S') {
|
data: param,
|
||||||
alert(getMessage('login.init_password.complete_message'))
|
|
||||||
redirect('/login')
|
|
||||||
} else {
|
|
||||||
alert(res.result.resultMsg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
if (res.result.resultCode == 'S') {
|
||||||
|
alert(getMessage('login.init_password.complete_message'))
|
||||||
|
setCheckId('')
|
||||||
|
setCheckEmail('')
|
||||||
|
setPasswordReset(1)
|
||||||
|
} else {
|
||||||
|
alert(res.result.resultMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const initPasswordContent = (
|
|
||||||
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
|
|
||||||
<form action={initPasswordProcess} className="space-y-6">
|
|
||||||
<h2 className="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{getMessage('login.init_password.title')}</h2>
|
|
||||||
<h2 className="text-center text-1xl font-bold leading-9 tracking-tight text-gray-900">{getMessage('login.init_password.sub_title')}</h2>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="checkId" className="block text-sm font-medium leading-6 text-gray-900">
|
|
||||||
ID
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="checkId"
|
|
||||||
name="checkId"
|
|
||||||
type="text"
|
|
||||||
required
|
|
||||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<label htmlFor="checkEmail" className="block text-sm font-medium leading-6 text-gray-900">
|
|
||||||
E-Mail
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="checkEmail"
|
|
||||||
name="checkEmail"
|
|
||||||
type="email"
|
|
||||||
required
|
|
||||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="mt-5 text-center text-sm text-gray-500">
|
|
||||||
<Button type="submit" className="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">
|
|
||||||
{getMessage('login.init_password.btn')}
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col align-center">
|
<div className="login-wrap">
|
||||||
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
|
<div className="login-inner">
|
||||||
<div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
<Link href={'/login'} className="login-logo">
|
||||||
<h1 className="text-center text-4xl font-bold leading-9 tracking-tight text-gray-900">{getMessage('site.name')}</h1>
|
<Image src="/static/images/main/login-logo.svg" alt="react" width={236} height={43} styles={{ width: '236px', height: '43px' }} priority />
|
||||||
<h2 className="mt-5 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{getMessage('site.sub_name')}</h2>
|
</Link>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-5 sm:mx-auto sm:w-full sm:max-w-sm">
|
{passwordReset === 1 && (
|
||||||
<form action={loginProcess} className="space-y-6">
|
<>
|
||||||
<div>
|
<div className="login-input-frame">
|
||||||
<label htmlFor="userId" className="block text-sm font-medium leading-6 text-gray-900">
|
<form onSubmit={loginProcess} className="space-y-6">
|
||||||
ID
|
<div className="login-frame-tit">
|
||||||
</label>
|
<span>{getMessage('site.name')}</span>
|
||||||
<div className="mt-2">
|
{getMessage('site.sub_name')}
|
||||||
<input
|
</div>
|
||||||
id="userId"
|
<div className="login-input-wrap">
|
||||||
name="id"
|
<div className="login-area id">
|
||||||
type="text"
|
<input
|
||||||
required
|
type="text"
|
||||||
// autoComplete="email"
|
className="login-input"
|
||||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
id="userId"
|
||||||
/>
|
name="id"
|
||||||
|
required
|
||||||
|
value={userId}
|
||||||
|
placeholder={getMessage('login.id.placeholder')}
|
||||||
|
onChange={(e) => {
|
||||||
|
setUserId(e.target.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="id-delete"
|
||||||
|
onClick={(e) => {
|
||||||
|
setUserId('')
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
<div className="login-area password">
|
||||||
|
<input
|
||||||
|
type={passwordVisible ? 'text' : 'password'}
|
||||||
|
className="login-input"
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
required
|
||||||
|
autoComplete="current-password"
|
||||||
|
placeholder={getMessage('login.password.placeholder')}
|
||||||
|
onChange={(e) => {
|
||||||
|
setPasswordVisible(passwordVisible)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className={`password-hidden ${passwordVisible ? 'visible' : ''}`}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
setPasswordVisible(!passwordVisible)
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
<div className="d-check-box login">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="ch01"
|
||||||
|
name="chkLoginId"
|
||||||
|
checked={chkLoginId}
|
||||||
|
onChange={(e) => {
|
||||||
|
setChkLoginId(e.target.checked)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<label htmlFor="ch01">{getMessage('login.id.save')}</label>
|
||||||
|
</div>
|
||||||
|
<div className="login-btn-box">
|
||||||
|
<button type="submit" className="login-btn">
|
||||||
|
{getMessage('login')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="reset-password">
|
||||||
|
<button type="button" onClick={() => setPasswordReset(2)}>
|
||||||
|
{getMessage('login.init_password.btn')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div className="login-guide-wrap">
|
||||||
|
<span>※</span>
|
||||||
|
{getMessage('login.guide.text')}
|
||||||
|
<br />
|
||||||
|
{getMessage('login.guide.sub1')} <Link href={'../join'}>{getMessage('login.guide.join.btn')}</Link>
|
||||||
|
{getMessage('login.guide.sub2')}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{passwordReset === 2 && (
|
||||||
|
<>
|
||||||
|
<div className="login-input-frame">
|
||||||
|
<div className="login-frame-tit pw-reset">
|
||||||
|
<span>{getMessage('login.init_password.title')}</span>
|
||||||
|
{getMessage('login.init_password.sub_title')}
|
||||||
|
</div>
|
||||||
|
<div className="login-input-wrap">
|
||||||
|
<div className="login-area id">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="checkId"
|
||||||
|
name="checkId"
|
||||||
|
value={checkId}
|
||||||
|
required
|
||||||
|
className="login-input"
|
||||||
|
placeholder={getMessage('login.init_password.id.placeholder')}
|
||||||
|
onChange={(e) => {
|
||||||
|
setCheckId(e.target.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="id-delete"
|
||||||
|
onClick={() => {
|
||||||
|
setCheckId('')
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
<div className="login-area email">
|
||||||
|
<input
|
||||||
|
id="checkEmail"
|
||||||
|
name="checkEmail"
|
||||||
|
type="email"
|
||||||
|
required
|
||||||
|
className="login-input"
|
||||||
|
value={checkEmail}
|
||||||
|
onChange={(e) => {
|
||||||
|
setCheckEmail(e.target.value)
|
||||||
|
}}
|
||||||
|
placeholder={getMessage('login.init_password.email.placeholder')}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="id-delete"
|
||||||
|
onClick={() => {
|
||||||
|
setCheckEmail('')
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
<div className="pwreset-btn-box">
|
||||||
|
<button type="button" className="login-btn light mr5" onClick={() => setPasswordReset(1)}>
|
||||||
|
{getMessage('login.init_password.btn.back')}
|
||||||
|
</button>
|
||||||
|
<button type="button" className="login-btn" onClick={initPasswordProcess}>
|
||||||
|
{getMessage('login.init_password.btn')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
<div>
|
)}
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<label htmlFor="password" className="block text-sm font-medium leading-6 text-gray-900">
|
|
||||||
Password
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="password"
|
|
||||||
name="password"
|
|
||||||
type="password"
|
|
||||||
required
|
|
||||||
autoComplete="current-password"
|
|
||||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="mt-10 flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
|
||||||
>
|
|
||||||
{getMessage('login')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<p className="mt-5 text-center text-sm text-gray-500">
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
setContent(initPasswordContent)
|
|
||||||
setOpen(true)
|
|
||||||
}}
|
|
||||||
className="font-semibold leading-6 text-indigo-600 hover:text-indigo-500"
|
|
||||||
>
|
|
||||||
{getMessage('login.init_password.btn')}
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="flex align-center mt-2">
|
|
||||||
<Switch isSelected={isSelected} onValueChange={handleSelected}>
|
|
||||||
{isSelected ? 'Current Locale: KO' : 'Current Locale: JA'}
|
|
||||||
</Switch>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="login-copyright">COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,244 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useState, useRef, useEffect } from 'react'
|
|
||||||
import Image from 'next/image'
|
|
||||||
import Link from 'next/link'
|
|
||||||
import { redirect } from 'next/navigation'
|
|
||||||
import { useRecoilState } from 'recoil'
|
|
||||||
import { useAxios } from '@/hooks/useAxios'
|
|
||||||
import { setSession } from '@/lib/authActions'
|
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
|
||||||
import { globalLocaleStore } from '@/store/localeAtom'
|
|
||||||
import { sessionStore } from '@/store/commonAtom'
|
|
||||||
import { modalContent, modalState } from '@/store/modalAtom'
|
|
||||||
import '@/styles/style.scss'
|
|
||||||
import { useRouter } from 'next/navigation'
|
|
||||||
|
|
||||||
export default function NewLogin() {
|
|
||||||
const [passwordVisible, setPasswordVisible] = useState(false)
|
|
||||||
const passwordRef = useRef(null)
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setOpen(false)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (passwordVisible) {
|
|
||||||
passwordRef.current.type = 'text'
|
|
||||||
} else {
|
|
||||||
passwordRef.current.type = 'password'
|
|
||||||
}
|
|
||||||
}, [passwordVisible])
|
|
||||||
|
|
||||||
const { patch } = useAxios()
|
|
||||||
|
|
||||||
const { getMessage } = useMessage()
|
|
||||||
const [globalLocaleState, setGlbalLocaleState] = useRecoilState(globalLocaleStore)
|
|
||||||
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
|
||||||
const [isSelected, setIsSelected] = useState(globalLocaleState === 'ko' ? true : false)
|
|
||||||
|
|
||||||
const handleSelected = () => {
|
|
||||||
if (isSelected) {
|
|
||||||
setGlbalLocaleState('ja')
|
|
||||||
} else {
|
|
||||||
setGlbalLocaleState('ko')
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsSelected(!isSelected)
|
|
||||||
}
|
|
||||||
|
|
||||||
// login process
|
|
||||||
const loginProcess = async (formData) => {
|
|
||||||
const param = {
|
|
||||||
// langCd: currentLocale
|
|
||||||
langCd: globalLocaleState,
|
|
||||||
lastEditUser: formData.get('id'),
|
|
||||||
loginId: formData.get('id'),
|
|
||||||
pwd: formData.get('password'),
|
|
||||||
}
|
|
||||||
|
|
||||||
// await post({ url: '/api/login/v1.0/login', data: param }).then((res) => {
|
|
||||||
// if (res) {
|
|
||||||
// if (res.result.resultCode == 'S') {
|
|
||||||
// // console.log('res.data', res.data)
|
|
||||||
// // 비밀번호 초기화가 필요한 경우
|
|
||||||
// // if (res.data.pwdInitYn != 'Y') {
|
|
||||||
// // alert('비밀번호 초기화가 필요한 경우')
|
|
||||||
// // } else {
|
|
||||||
// setSession(res.data)
|
|
||||||
// redirect('/')
|
|
||||||
// // }
|
|
||||||
// } else {
|
|
||||||
// alert(res.result.resultMsg)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
// 임시 로그인 처리
|
|
||||||
setSession({
|
|
||||||
userId: 'NEW016610',
|
|
||||||
saleStoreId: null,
|
|
||||||
name: null,
|
|
||||||
mail: null,
|
|
||||||
tel: null,
|
|
||||||
storeId: 'TEMP02',
|
|
||||||
userNm: 'ㅇㅇ6610',
|
|
||||||
userNmKana: '신규사용자 16610',
|
|
||||||
category: '인상6610',
|
|
||||||
telNo: '336610',
|
|
||||||
fax: null,
|
|
||||||
email: 't10t@naver.com',
|
|
||||||
pwdInitYn: 'Y',
|
|
||||||
})
|
|
||||||
|
|
||||||
setSessionState({
|
|
||||||
userId: 'NEW016610',
|
|
||||||
saleStoreId: null,
|
|
||||||
name: null,
|
|
||||||
mail: null,
|
|
||||||
tel: null,
|
|
||||||
storeId: 'TEMP02',
|
|
||||||
userNm: 'ㅇㅇ6610',
|
|
||||||
userNmKana: '신규사용자 16610',
|
|
||||||
category: '인상6610',
|
|
||||||
telNo: '336610',
|
|
||||||
fax: null,
|
|
||||||
email: 't10t@naver.com',
|
|
||||||
pwdInitYn: 'Y',
|
|
||||||
})
|
|
||||||
|
|
||||||
// redirect('/')
|
|
||||||
router.push('/')
|
|
||||||
// 임시 로그인 처리 끝
|
|
||||||
}
|
|
||||||
|
|
||||||
// 비밀번호 초기화 관련
|
|
||||||
const [open, setOpen] = useRecoilState(modalState)
|
|
||||||
const [contents, setContent] = useRecoilState(modalContent)
|
|
||||||
|
|
||||||
const initPasswordProcess = async (formData) => {
|
|
||||||
const param = {
|
|
||||||
langCd: currentLocale,
|
|
||||||
lastEditUser: formData.get('checkId'),
|
|
||||||
loginId: formData.get('checkId'),
|
|
||||||
email: formData.get('checkEmail'),
|
|
||||||
}
|
|
||||||
|
|
||||||
await patch({ url: '/api/login/v1.0/user/init-password', data: param }).then((res) => {
|
|
||||||
if (res) {
|
|
||||||
if (res.result.resultCode == 'S') {
|
|
||||||
alert(getMessage('login.init_password.complete_message'))
|
|
||||||
redirect('/login')
|
|
||||||
} else {
|
|
||||||
alert(res.result.resultMsg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const initPasswordContent = (
|
|
||||||
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
|
|
||||||
<form action={initPasswordProcess} className="space-y-6">
|
|
||||||
<h2 className="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{getMessage('login.init_password.title')}</h2>
|
|
||||||
<h2 className="text-center text-1xl font-bold leading-9 tracking-tight text-gray-900">{getMessage('login.init_password.sub_title')}</h2>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="checkId" className="block text-sm font-medium leading-6 text-gray-900">
|
|
||||||
ID
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="checkId"
|
|
||||||
name="checkId"
|
|
||||||
type="text"
|
|
||||||
required
|
|
||||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<label htmlFor="checkEmail" className="block text-sm font-medium leading-6 text-gray-900">
|
|
||||||
E-Mail
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="checkEmail"
|
|
||||||
name="checkEmail"
|
|
||||||
type="email"
|
|
||||||
required
|
|
||||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="mt-5 text-center text-sm text-gray-500">
|
|
||||||
<button type="submit" className="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">
|
|
||||||
{getMessage('login.init_password.btn')}
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="login-wrap">
|
|
||||||
<div className="login-inner">
|
|
||||||
<Link href={'/login'} className="login-logo">
|
|
||||||
<Image src="/static/images/main/login-logo.svg" alt="react" width={236} height={43} styles={{ width: '236px', height: '43px' }} priority />
|
|
||||||
</Link>
|
|
||||||
<form action={loginProcess} className="space-y-6">
|
|
||||||
<div className="login-input-frame">
|
|
||||||
<div className="login-frame-tit">
|
|
||||||
<span>Q.CAST III</span>
|
|
||||||
太陽光発電システム図面管理サイト
|
|
||||||
</div>
|
|
||||||
<div className="login-input-wrap">
|
|
||||||
<div className="login-area id">
|
|
||||||
<input type="text" className="login-input" id="userId" name="id" required placeholder={'IDを入力してください'} />
|
|
||||||
<button className="id-delete" onClick={(e) => e.preventDefault()}></button>
|
|
||||||
</div>
|
|
||||||
<div className="login-area password">
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
className="login-input"
|
|
||||||
id="password"
|
|
||||||
name="password"
|
|
||||||
required
|
|
||||||
autoComplete="current-password"
|
|
||||||
ref={passwordRef}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
className={`password-hidden ${passwordVisible ? 'visible' : ''}`}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault()
|
|
||||||
setPasswordVisible(!passwordVisible)
|
|
||||||
}}
|
|
||||||
></button>
|
|
||||||
</div>
|
|
||||||
<div className="d-check-box login">
|
|
||||||
<input type="checkbox" id="ch01" />
|
|
||||||
<label htmlFor="ch01">ID Save</label>
|
|
||||||
</div>
|
|
||||||
<div className="login-btn-box">
|
|
||||||
<button type="submit" className="login-btn">
|
|
||||||
Login
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="reset-password">
|
|
||||||
<Link href={'#'}>パスワードの初期化</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div className="login-guide-wrap">
|
|
||||||
<span>※</span>当サイトをご利用の際は、事前申請が必要です。
|
|
||||||
<br />
|
|
||||||
IDがない方は <Link href={'#'}>ID申請 クリックしてください。</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="login-copyright">COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -1,7 +1,71 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import Link from 'next/link'
|
||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
|
import Search from '@/components/community/Search'
|
||||||
|
import ArchiveTable from '@/components/community/ArchiveTable'
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useResetRecoilState } from 'recoil'
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
|
||||||
|
import { searchState } from '@/store/boardAtom'
|
||||||
|
|
||||||
export default function Archive() {
|
export default function Archive() {
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
const resetSearch = useResetRecoilState(searchState)
|
||||||
|
const [isInitialized, setIsInitialized] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
resetSearch()
|
||||||
|
setIsInitialized(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!isInitialized) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const boardType = {
|
||||||
|
boardTitle: getMessage('board.archive.title'),
|
||||||
|
subTitle: getMessage('board.archive.sub.title'),
|
||||||
|
clsCode: 'DOWN',
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>Community Archive</h1>
|
<div className="sub-header">
|
||||||
|
<div className="sub-header-inner">
|
||||||
|
<ul className="sub-header-title-wrap">
|
||||||
|
<li className="title-item">
|
||||||
|
<Link className="sub-header-title" href={'#'}>
|
||||||
|
{getMessage('board.archive.title')}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul className="sub-header-location">
|
||||||
|
<li className="location-item">
|
||||||
|
<span className="home">
|
||||||
|
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li className="location-item">
|
||||||
|
<span>{getMessage('header.menus.community')}</span>
|
||||||
|
</li>
|
||||||
|
<li className="location-item">
|
||||||
|
<span>{getMessage('board.archive.title')}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="sub-content">
|
||||||
|
<div className="sub-content-inner">
|
||||||
|
<div className="sub-table-box">
|
||||||
|
<Search title={boardType.boardTitle} subTitle={boardType.subTitle} isSelectUse={true} />
|
||||||
|
<ArchiveTable clsCode={boardType.clsCode} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
103
src/components/community/ArchiveTable.jsx
Normal file
103
src/components/community/ArchiveTable.jsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useRecoilState } from 'recoil'
|
||||||
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
|
|
||||||
|
import { searchState } from '@/store/boardAtom'
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
|
||||||
|
import { handleFileDown } from '@/util/board-utils'
|
||||||
|
|
||||||
|
export default function ArchiveTable({ clsCode }) {
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
|
// api 조회 관련
|
||||||
|
const { get } = useAxios()
|
||||||
|
const [search, setSearch] = useRecoilState(searchState)
|
||||||
|
const [boardList, setBoardList] = useState([])
|
||||||
|
|
||||||
|
// 목록 조회
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchData() {
|
||||||
|
const url = `${process.env.NEXT_PUBLIC_API_SERVER_PATH}/api/board/list`
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
schNoticeTpCd: 'QC',
|
||||||
|
schNoticeClsCd: clsCode,
|
||||||
|
schTitle: search.searchValue ? search.searchValue : '',
|
||||||
|
})
|
||||||
|
const apiUrl = `${url}?${params.toString()}`
|
||||||
|
|
||||||
|
const resultData = await get({ url: apiUrl })
|
||||||
|
|
||||||
|
if (resultData) {
|
||||||
|
if (resultData.result.code === 200) {
|
||||||
|
setBoardList(resultData.data)
|
||||||
|
if (resultData.data.length > 0) {
|
||||||
|
setSearch({ ...search, totalCount: resultData.data[0].totCnt })
|
||||||
|
} else {
|
||||||
|
setSearch({ ...search, totalCount: 0 })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(resultData.result.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData()
|
||||||
|
}, [search.searchValue])
|
||||||
|
|
||||||
|
// 상세 파일 목록 조회
|
||||||
|
const handleDetailFileListDown = async (noticeNo) => {
|
||||||
|
const url = `${process.env.NEXT_PUBLIC_API_SERVER_PATH}/api/board/detail`
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
noticeNo: noticeNo,
|
||||||
|
})
|
||||||
|
const apiUrl = `${url}?${params.toString()}`
|
||||||
|
|
||||||
|
const resultData = await get({ url: apiUrl })
|
||||||
|
|
||||||
|
if (resultData) {
|
||||||
|
if (resultData.result.code === 200) {
|
||||||
|
const boardDetailFileList = resultData.data.listFile
|
||||||
|
|
||||||
|
if (boardDetailFileList && Array.isArray(boardDetailFileList)) {
|
||||||
|
boardDetailFileList.forEach((boardFile) => {
|
||||||
|
handleFileDown(boardFile)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(resultData.result.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="file-down-list">
|
||||||
|
{boardList?.map((board) => (
|
||||||
|
<div key={board.noticeNo} className="file-down-item">
|
||||||
|
<div className="file-item-info">
|
||||||
|
<div className="item-num">
|
||||||
|
{/* 번호 */}
|
||||||
|
{board.rowNumber}
|
||||||
|
</div>
|
||||||
|
<div className="item-name">
|
||||||
|
{/* 제목 */}
|
||||||
|
{board.title}
|
||||||
|
</div>
|
||||||
|
<div className="item-date">
|
||||||
|
{/* 등록일 */}
|
||||||
|
{getMessage('board.sub.updDt')} : {board.uptDt ? board.uptDt : board.regDt}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="file-down-box">
|
||||||
|
{/* 첨부파일 */}
|
||||||
|
<button type="button" className="file-down-btn" onClick={() => handleDetailFileListDown(board.noticeNo)}></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,7 +1,80 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import Link from 'next/link'
|
||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
|
import Search from '@/components/community/Search'
|
||||||
|
import Pagination from '@/components/community/Pagination'
|
||||||
|
import Table from '@/components/community/Table'
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useResetRecoilState, useRecoilValue, useRecoilState } from 'recoil'
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
|
||||||
|
import { searchState } from '@/store/boardAtom'
|
||||||
|
|
||||||
export default function Faq() {
|
export default function Faq() {
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
const resetSearch = useResetRecoilState(searchState)
|
||||||
|
const [isInitialized, setIsInitialized] = useState(false)
|
||||||
|
|
||||||
|
const search = useRecoilValue(searchState)
|
||||||
|
const [searchForm, setSearchForm] = useRecoilState(searchState)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (search.mainFlag === 'N') {
|
||||||
|
resetSearch()
|
||||||
|
} else {
|
||||||
|
setSearchForm({ ...searchForm, mainFlag: 'N' })
|
||||||
|
}
|
||||||
|
setIsInitialized(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!isInitialized) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const boardType = {
|
||||||
|
boardTitle: getMessage('board.faq.title'),
|
||||||
|
subTitle: getMessage('board.faq.sub.title'),
|
||||||
|
clsCode: 'FAQ',
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>Community FAQ</h1>
|
<div className="sub-header">
|
||||||
|
<div className="sub-header-inner">
|
||||||
|
<ul className="sub-header-title-wrap">
|
||||||
|
<li className="title-item">
|
||||||
|
<Link className="sub-header-title" href={'#'}>
|
||||||
|
{getMessage('board.faq.title')}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul className="sub-header-location">
|
||||||
|
<li className="location-item">
|
||||||
|
<span className="home">
|
||||||
|
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li className="location-item">
|
||||||
|
<span>{getMessage('header.menus.community')}</span>
|
||||||
|
</li>
|
||||||
|
<li className="location-item">
|
||||||
|
<span>{getMessage('board.faq.title')}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="sub-content">
|
||||||
|
<div className="sub-content-inner">
|
||||||
|
<div className="sub-table-box">
|
||||||
|
<Search title={boardType.boardTitle} subTitle={boardType.subTitle} isSelectUse={true} />
|
||||||
|
<Table clsCode={boardType.clsCode} />
|
||||||
|
<Pagination />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,72 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import Link from 'next/link'
|
||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
|
import Search from '@/components/community/Search'
|
||||||
|
import Pagination from '@/components/community/Pagination'
|
||||||
|
import Table from '@/components/community/Table'
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useResetRecoilState } from 'recoil'
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
|
||||||
|
import { searchState } from '@/store/boardAtom'
|
||||||
|
|
||||||
export default function Notice() {
|
export default function Notice() {
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
const resetSearch = useResetRecoilState(searchState)
|
||||||
|
const [isInitialized, setIsInitialized] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
resetSearch()
|
||||||
|
setIsInitialized(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!isInitialized) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const boardType = {
|
||||||
|
boardTitle: getMessage('board.notice.title'),
|
||||||
|
subTitle: getMessage('board.notice.sub.title'),
|
||||||
|
clsCode: 'NOTICE',
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>Community Notice</h1>
|
<div className="sub-header">
|
||||||
|
<div className="sub-header-inner">
|
||||||
|
<ul className="sub-header-title-wrap">
|
||||||
|
<li className="title-item">
|
||||||
|
<Link className="sub-header-title" href={'#'}>
|
||||||
|
{getMessage('board.notice.title')}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul className="sub-header-location">
|
||||||
|
<li className="location-item">
|
||||||
|
<span className="home">
|
||||||
|
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li className="location-item">
|
||||||
|
<span>{getMessage('header.menus.community')}</span>
|
||||||
|
</li>
|
||||||
|
<li className="location-item">
|
||||||
|
<span>{getMessage('board.notice.title')}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="sub-content">
|
||||||
|
<div className="sub-content-inner">
|
||||||
|
<div className="sub-table-box">
|
||||||
|
<Search title={boardType.boardTitle} subTitle={boardType.subTitle} isSelectUse={true} />
|
||||||
|
<Table clsCode={boardType.clsCode} />
|
||||||
|
<Pagination />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
78
src/components/community/Pagination.jsx
Normal file
78
src/components/community/Pagination.jsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { searchState } from '@/store/boardAtom'
|
||||||
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
|
import { generateBlockPagination } from '@/util/board-utils'
|
||||||
|
|
||||||
|
export default function Pagination() {
|
||||||
|
const search = useRecoilValue(searchState)
|
||||||
|
|
||||||
|
const [searchForm, setSearchForm] = useRecoilState(searchState)
|
||||||
|
|
||||||
|
const handlePagination = (pageNum) => {
|
||||||
|
setSearchForm({ ...searchForm, currentPage: pageNum })
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalPages = Math.ceil(search.totalCount / search.pageBlock) > 0 ? Math.ceil(search.totalCount / search.pageBlock) : 1
|
||||||
|
const allPages = generateBlockPagination(search.currentPage, totalPages, 10)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ol className="pagination">
|
||||||
|
<li className="page-item first">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={search.currentPage === 1}
|
||||||
|
onClick={() => {
|
||||||
|
handlePagination(1)
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</li>
|
||||||
|
<li className="page-item prev">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={search.currentPage <= 1}
|
||||||
|
onClick={() => {
|
||||||
|
handlePagination(search.currentPage - 1)
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{/* 페이지목록 */}
|
||||||
|
{allPages.map((page, index) => {
|
||||||
|
return (
|
||||||
|
<li className={`page-item ${search.currentPage === page ? 'on' : ''}`} key={index}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
handlePagination(page)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{page}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
|
<li className="page-item next">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={search.currentPage >= totalPages}
|
||||||
|
onClick={() => {
|
||||||
|
handlePagination(search.currentPage + 1)
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</li>
|
||||||
|
<li className="page-item last">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={search.currentPage === totalPages}
|
||||||
|
onClick={() => {
|
||||||
|
handlePagination(totalPages)
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
117
src/components/community/Search.jsx
Normal file
117
src/components/community/Search.jsx
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { searchState } from '@/store/boardAtom'
|
||||||
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
|
||||||
|
export default function Search({ title = '', subTitle = '', isSelectUse = false }) {
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
|
const search = useRecoilValue(searchState)
|
||||||
|
const [searchForm, setSearchForm] = useRecoilState(searchState)
|
||||||
|
|
||||||
|
const [selectPageBlock, setSelectPageBlock] = useState(search.pageBlock)
|
||||||
|
const [searchValue, setSearchValue] = useState(search.searchValue)
|
||||||
|
const [searchView, setSearchView] = useState(search.searchValue ? true : false)
|
||||||
|
const [searchViewText, setSearchViewText] = useState(search.searchValue ? search.searchValue : '')
|
||||||
|
|
||||||
|
// Enter 키 처리
|
||||||
|
const handleKeyDown = (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
handleSubmit(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 조회 값 처리
|
||||||
|
const handleSearch = (text, block) => {
|
||||||
|
if (text !== '') {
|
||||||
|
setSearchView(true)
|
||||||
|
setSearchViewText(text)
|
||||||
|
setSearchForm({ ...searchForm, currentPage: 1, searchValue: text, pageBlock: block, searchFlag: true })
|
||||||
|
} else {
|
||||||
|
setSearchView(false)
|
||||||
|
setSearchViewText('')
|
||||||
|
setSearchForm({ ...searchForm, currentPage: 1, searchValue: '', pageBlock: block, searchFlag: !searchForm.searchFlag })
|
||||||
|
}
|
||||||
|
// 조회 후 값 비워주기
|
||||||
|
setSearchValue('')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
handleSearch(searchValue, selectPageBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="community-search-warp">
|
||||||
|
<div className="community-search-box">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="community-input"
|
||||||
|
placeholder={getMessage('board.sub.search.placeholder')}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSearchValue(e.target.value)
|
||||||
|
}}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
value={searchValue}
|
||||||
|
/>
|
||||||
|
<button type="button" className="community-search-ico" onClick={() => handleSearch(searchValue, selectPageBlock)}></button>
|
||||||
|
</div>
|
||||||
|
{searchView && (
|
||||||
|
<div className="community-search-keyword">
|
||||||
|
{isSelectUse ? (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: getMessage('board.sub.search.result', [`<span>${searchViewText}</span>`, `<span>${search.totalCount}</span>`]),
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: getMessage('board.sub.search.archive.result', [`<span>${searchViewText}</span>`, `<span>${search.totalCount}</span>`]),
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="table-box-title-wrap">
|
||||||
|
<div className="title-wrap">
|
||||||
|
<h3>{subTitle}</h3>
|
||||||
|
<ul className="info-wrap">
|
||||||
|
<li>
|
||||||
|
{getMessage('board.sub.total')} <span className="red">{search.totalCount}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{isSelectUse && (
|
||||||
|
<div className="left-unit-box">
|
||||||
|
<div className="select-box" style={{ width: '80px' }}>
|
||||||
|
<select
|
||||||
|
className="select-light black"
|
||||||
|
value={selectPageBlock}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSelectPageBlock(Number(e.target.value))
|
||||||
|
const text = searchValue ? searchValue : searchViewText
|
||||||
|
handleSearch(text, Number(e.target.value))
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value={100}>100</option>
|
||||||
|
<option value={200}>200</option>
|
||||||
|
<option value={300}>300</option>
|
||||||
|
<option value={400}>400</option>
|
||||||
|
<option value={500}>500</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
110
src/components/community/Table.jsx
Normal file
110
src/components/community/Table.jsx
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useRecoilState } from 'recoil'
|
||||||
|
|
||||||
|
import { searchState } from '@/store/boardAtom'
|
||||||
|
|
||||||
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
|
||||||
|
import BoardDetailModal from '../community/modal/BoardDetailModal'
|
||||||
|
|
||||||
|
export default function Table({ clsCode }) {
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
|
// api 조회 관련
|
||||||
|
const { get } = useAxios()
|
||||||
|
const [search, setSearch] = useRecoilState(searchState)
|
||||||
|
const [boardList, setBoardList] = useState([])
|
||||||
|
|
||||||
|
// 팝업 관련
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
const [modalNoticeNo, setModalNoticeNo] = useState('')
|
||||||
|
|
||||||
|
// 목록 조회
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchData() {
|
||||||
|
const startRow = (search.currentPage - 1) * search.pageBlock > 0 ? (search.currentPage - 1) * search.pageBlock + 1 : 1
|
||||||
|
const endRow = search.currentPage * search.pageBlock
|
||||||
|
|
||||||
|
const url = `/api/board/list`
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
schNoticeTpCd: 'QC',
|
||||||
|
schNoticeClsCd: clsCode,
|
||||||
|
schTitle: search.searchValue ? search.searchValue : '',
|
||||||
|
startRow: startRow,
|
||||||
|
endRow: endRow,
|
||||||
|
})
|
||||||
|
const apiUrl = `${url}?${params.toString()}`
|
||||||
|
|
||||||
|
const resultData = await get({ url: apiUrl })
|
||||||
|
|
||||||
|
if (resultData) {
|
||||||
|
if (resultData.result.code === 200) {
|
||||||
|
if (resultData.data.length > 0) {
|
||||||
|
setBoardList(resultData.data)
|
||||||
|
setSearch({ ...search, totalCount: resultData.data[0].totCnt })
|
||||||
|
} else {
|
||||||
|
setBoardList([])
|
||||||
|
setSearch({ ...search, totalCount: 0 })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(resultData.result.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData()
|
||||||
|
}, [search.currentPage, search.searchValue, search.pageBlock, search.searchFlag])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="community-table">
|
||||||
|
<table>
|
||||||
|
<colgroup>
|
||||||
|
<col width={100} />
|
||||||
|
<col />
|
||||||
|
<col width={200} />
|
||||||
|
</colgroup>
|
||||||
|
<tbody>
|
||||||
|
{boardList.length > 0 ? (
|
||||||
|
boardList?.map((board) => (
|
||||||
|
<tr
|
||||||
|
key={board.noticeNo}
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(true)
|
||||||
|
setModalNoticeNo(board.noticeNo)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<td className="al-c">
|
||||||
|
{/* 번호 */}
|
||||||
|
{board.rowNumber}
|
||||||
|
</td>
|
||||||
|
<td style={{ textAlign: 'center' }}>
|
||||||
|
{/* 제목 */}
|
||||||
|
<div className="text-frame">
|
||||||
|
<div className="text-overflow">{board.title}</div>
|
||||||
|
{board.attachYn && <span className="clip"></span>}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="al-c">
|
||||||
|
{/* 등록일 */}
|
||||||
|
{board.regDt.split(' ')[0]}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={3} className="al-c">
|
||||||
|
{getMessage('common.message.no.data')}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{open && <BoardDetailModal noticeNo={modalNoticeNo} setOpen={setOpen} />}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
77
src/components/community/modal/BoardDetailModal.jsx
Normal file
77
src/components/community/modal/BoardDetailModal.jsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
|
import { handleFileDown } from '@/util/board-utils'
|
||||||
|
|
||||||
|
export default function BoardDetailModal({ noticeNo, setOpen }) {
|
||||||
|
// api 조회 관련
|
||||||
|
const { get } = useAxios()
|
||||||
|
const [boardDetail, setBoardDetail] = useState({})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// 상세 조회
|
||||||
|
const fetchDetail = async (noticeNo) => {
|
||||||
|
const url = `/api/board/detail`
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
noticeNo: noticeNo,
|
||||||
|
})
|
||||||
|
const apiUrl = `${url}?${params.toString()}`
|
||||||
|
|
||||||
|
const resultData = await get({ url: apiUrl })
|
||||||
|
|
||||||
|
if (resultData) {
|
||||||
|
if (resultData.result.code === 200) {
|
||||||
|
const boardDetail = resultData.data
|
||||||
|
setBoardDetail(boardDetail)
|
||||||
|
} else {
|
||||||
|
alert(resultData.result.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchDetail(noticeNo)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="modal-popup community">
|
||||||
|
<div className="modal-dialog">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-header">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="modal-close"
|
||||||
|
onClick={() => {
|
||||||
|
setOpen(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
닫기
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
<div className="community_detail">
|
||||||
|
<div className="community_detail-tit">{boardDetail.title}</div>
|
||||||
|
|
||||||
|
{boardDetail.listFile && (
|
||||||
|
<dl className="community_detail-file-wrap">
|
||||||
|
<dt>첨부파일 목록</dt>
|
||||||
|
{boardDetail.listFile.map((boardFile) => (
|
||||||
|
<dd key={boardFile}>
|
||||||
|
<button type="button" className="down" onClick={() => handleFileDown(boardFile)}>
|
||||||
|
{boardFile.srcFileNm}
|
||||||
|
</button>
|
||||||
|
</dd>
|
||||||
|
))}
|
||||||
|
</dl>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="community_detail-inner">{boardDetail.contents}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -12,6 +12,8 @@ import { logout } from '@/lib/authActions'
|
|||||||
|
|
||||||
import QSelectBox from '@/components/common/select/QSelectBox'
|
import QSelectBox from '@/components/common/select/QSelectBox'
|
||||||
|
|
||||||
|
import UserInfoModal from '@/components/myInfo/UserInfoModal'
|
||||||
|
|
||||||
export const ToggleonMouse = (e, act, target) => {
|
export const ToggleonMouse = (e, act, target) => {
|
||||||
const listWrap = e.target.closest(target)
|
const listWrap = e.target.closest(target)
|
||||||
const ListItem = Array.from(listWrap.childNodes)
|
const ListItem = Array.from(listWrap.childNodes)
|
||||||
@ -28,6 +30,8 @@ export const ToggleonMouse = (e, act, target) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Header(props) {
|
export default function Header(props) {
|
||||||
|
const [userInfoModal, setUserInfoModal] = useState(false)
|
||||||
|
|
||||||
const { userSession } = props
|
const { userSession } = props
|
||||||
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
@ -137,9 +141,15 @@ export default function Header(props) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="header-left">
|
<div className="header-left">
|
||||||
<div className="profile-box">
|
<div className="profile-box">
|
||||||
<Link href="/roof2">
|
<Link
|
||||||
|
href="#"
|
||||||
|
onClick={() => {
|
||||||
|
setUserInfoModal(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<button className="profile">{userSession.userNm}</button>
|
<button className="profile">{userSession.userNm}</button>
|
||||||
</Link>
|
</Link>
|
||||||
|
{userInfoModal && <UserInfoModal userId={sessionState.userId} userInfoModal={userInfoModal} setUserInfoModal={setUserInfoModal} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="sign-out-box">
|
<div className="sign-out-box">
|
||||||
<button className="sign-out" onClick={() => logout()}>
|
<button className="sign-out" onClick={() => logout()}>
|
||||||
|
|||||||
250
src/components/myInfo/UserInfoModal.jsx
Normal file
250
src/components/myInfo/UserInfoModal.jsx
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useState, useRef, useEffect } from 'react'
|
||||||
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
|
||||||
|
export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal }) {
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
|
// api 조회 관련
|
||||||
|
const { get, patch } = useAxios()
|
||||||
|
const [info, setInfo] = useState({
|
||||||
|
userId: '',
|
||||||
|
password: '',
|
||||||
|
name: '',
|
||||||
|
nameKana: '',
|
||||||
|
category: '',
|
||||||
|
tel: '',
|
||||||
|
fax: '',
|
||||||
|
mail: '',
|
||||||
|
groupId: '',
|
||||||
|
groupName: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const [password, setPassword] = useState('')
|
||||||
|
const [showPwd, setShowPwd] = useState(false)
|
||||||
|
const [chkChgPwd, setChkChgPwd] = useState(false)
|
||||||
|
const [chgPwd, setChgPwd] = useState('')
|
||||||
|
const chgPwdInput = useRef()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchData() {
|
||||||
|
const url = `${process.env.NEXT_PUBLIC_API_SERVER_PATH}/api/my-info/my-profile`
|
||||||
|
const params = new URLSearchParams({ userId: userId })
|
||||||
|
|
||||||
|
const apiUrl = `${url}?${params.toString()}`
|
||||||
|
|
||||||
|
const resultData = await get({ url: apiUrl })
|
||||||
|
|
||||||
|
if (resultData) {
|
||||||
|
setInfo(resultData)
|
||||||
|
setPassword(resultData?.password)
|
||||||
|
} else {
|
||||||
|
alert(getMessage('common.message.no.data'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userId) {
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const pattern = /^[\u0020-\u007E]{1,10}$/
|
||||||
|
|
||||||
|
// 비밀번호 변경
|
||||||
|
const handleChangePassword = async () => {
|
||||||
|
if (chgPwd === '') {
|
||||||
|
chgPwdInput.current.focus()
|
||||||
|
return alert(getMessage('myinfo.message.validation.password1'))
|
||||||
|
}
|
||||||
|
if (password === chgPwd) {
|
||||||
|
chgPwdInput.current.focus()
|
||||||
|
return alert(getMessage('myinfo.message.validation.password2'))
|
||||||
|
}
|
||||||
|
if (!pattern.test(chgPwd)) {
|
||||||
|
chgPwdInput.current.focus()
|
||||||
|
return alert(getMessage('myinfo.message.validation.password3'))
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = { loginId: info.userId, chgType: 'C', pwd: password, chgPwd: chgPwd }
|
||||||
|
|
||||||
|
await patch({ url: '/api/login/v1.0/user/change-password', data: params }).then((res) => {
|
||||||
|
if (res) {
|
||||||
|
if (res.result.resultCode === 'S') {
|
||||||
|
alert(getMessage('myinfo.message.save'))
|
||||||
|
setChkChgPwd(false)
|
||||||
|
} else {
|
||||||
|
alert(res.result.resultMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="modal-popup">
|
||||||
|
<div className="modal-dialog ">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-header">
|
||||||
|
<h1 className="title">{getMessage('myinfo.title')}</h1>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="modal-close"
|
||||||
|
onClick={() => {
|
||||||
|
setUserInfoModal(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getMessage('myinfo.btn.close')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
<div className="modal-body-inner">
|
||||||
|
<div className="common-table">
|
||||||
|
<table>
|
||||||
|
<colgroup>
|
||||||
|
<col style={{ width: '170px' }} />
|
||||||
|
<col />
|
||||||
|
</colgroup>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>{getMessage('myinfo.info.userId')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap">
|
||||||
|
<input type="text" className="input-light" value={userId} readOnly />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{getMessage('myinfo.info.nameKana')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap">
|
||||||
|
<input type="text" className="input-light" value={info?.nameKana} readOnly />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{getMessage('myinfo.info.name')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap">
|
||||||
|
<input type="text" className="input-light" value={info?.name} readOnly />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{getMessage('myinfo.info.password')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="form-flex-wrap">
|
||||||
|
<div className="password-input mr10">
|
||||||
|
<input
|
||||||
|
type={`${showPwd ? 'text' : 'password'}`}
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => {
|
||||||
|
setPassword(e.target.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<button className={`blink ${showPwd ? 'on' : ''}`} onClick={() => setShowPwd(!showPwd)}></button>
|
||||||
|
</div>
|
||||||
|
<span className="mr10">{getMessage('myinfo.sub.validation.password')}</span>
|
||||||
|
<button
|
||||||
|
className="btn-origin grey mr5"
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setChkChgPwd(true)
|
||||||
|
setTimeout(() => {
|
||||||
|
chgPwdInput.current.focus()
|
||||||
|
}, 10)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getMessage('myinfo.btn.chg.password')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr style={{ display: chkChgPwd ? '' : 'none' }}>
|
||||||
|
<th>
|
||||||
|
{getMessage('myinfo.info.chg.password')} <span className="red">*</span>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<div className="form-flex-wrap">
|
||||||
|
<div className="input-wrap mr10" style={{ flex: 1 }}>
|
||||||
|
<input
|
||||||
|
className="input-light"
|
||||||
|
type="text"
|
||||||
|
ref={chgPwdInput}
|
||||||
|
value={chgPwd}
|
||||||
|
onChange={(e) => {
|
||||||
|
setChgPwd(e.target.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type="button" className="btn-origin grey mr5" onClick={handleChangePassword}>
|
||||||
|
{getMessage('myinfo.btn.chg')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn-origin white "
|
||||||
|
onClick={() => {
|
||||||
|
setChgPwd('')
|
||||||
|
setChkChgPwd(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getMessage('myinfo.btn.noChg')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{getMessage('myinfo.info.category')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap">
|
||||||
|
<input type="text" className="input-light" value={info?.groupName} readOnly />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{getMessage('myinfo.info.tel')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap">
|
||||||
|
<input type="text" className="input-light" value={info?.tel} readOnly />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{getMessage('myinfo.info.fax')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap">
|
||||||
|
<input type="text" className="input-light" value={info?.fax} readOnly />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{getMessage('myinfo.info.mail')}</th>
|
||||||
|
<td>
|
||||||
|
<div className="input-wrap">
|
||||||
|
<input type="text" className="input-light" value={info?.mail} readOnly />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="footer-btn-wrap">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn-origin navy "
|
||||||
|
onClick={() => {
|
||||||
|
setUserInfoModal(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{getMessage('myinfo.btn.confirm')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -322,53 +322,88 @@
|
|||||||
"commons.south": "立つ",
|
"commons.south": "立つ",
|
||||||
"commons.north": "北",
|
"commons.north": "北",
|
||||||
"site.name": "Q.CAST III",
|
"site.name": "Q.CAST III",
|
||||||
"site.sub_name": "태양광 발전 시스템 도면관리 사이트",
|
"site.sub_name": "太陽光発電システム図面管理サイト",
|
||||||
"login": "로그인",
|
"board.notice.title": "お知らせ",
|
||||||
"login.init_password.btn": "비밀번호 초기화 ja",
|
"board.notice.sub.title": "お知らせ一覧",
|
||||||
"login.init_password.title": "비밀번호 초기화",
|
"board.faq.title": "FAQ",
|
||||||
"login.init_password.sub_title": "비밀번호를 초기화할 아이디와 이메일 주소를 입력해 주세요.",
|
"board.faq.sub.title": "FAQ 一覧",
|
||||||
"login.init_password.complete_message": "비밀번호가 초기화 되었습니다. 초기화된 비밀번호는 아이디와 같습니다.",
|
"board.archive.title": "資料ダウンロード",
|
||||||
"join.title": "Q.CAST3 로그인ID 발행 신청",
|
"board.archive.sub.title": "文書一覧",
|
||||||
"join.sub1.title": "판매대리점 정보",
|
"board.list.header.rownum": "番号",
|
||||||
"join.sub1.comment": "※ 등록되는 리셀러의 회사 이름을 입력하십시오. (2차점은 「○○판매주식회사(2차점:××설비주식회사)」로 기입해 주세요.)",
|
"board.list.header.title": "タイトル",
|
||||||
"join.sub1.storeQcastNm": "판매대리점명",
|
"board.list.header.regDt": "登録日",
|
||||||
"join.sub1.storeQcastNm_placeholder": "株式会社エネルギア・ソリューション・アンド・サービス(2次店:山口住機販売有限会社)",
|
"board.sub.search.placeholder": "検索語を入力してください。",
|
||||||
"join.sub1.storeQcastNmKana": "판매대리점명 후리가나",
|
"board.sub.search.result": "{0}について、合計{1}件の投稿が検索されました。",
|
||||||
"join.sub1.storeQcastNmKana_placeholder": "カブシキガイシャエネルギア・ソリューション・アン",
|
"board.sub.search.archive.result": "{0}について、合計{1}件の文書が検索されました。",
|
||||||
"join.sub1.postCd": "우편번호",
|
"board.sub.total": "全体",
|
||||||
"join.sub1.postCd_placeholder": "숫자 7자리",
|
"board.sub.fileList": "添付ファイル一覧",
|
||||||
"join.sub1.addr": "주소",
|
"board.sub.updDt": "更新日",
|
||||||
"join.sub1.addr_placeholder": "전각50자이내",
|
"myinfo.title": "マイプロフィール",
|
||||||
"join.sub1.telNo": "전화번호",
|
"myinfo.info.userId": "ユーザーID",
|
||||||
|
"myinfo.info.nameKana": "担当者名ふりがな",
|
||||||
|
"myinfo.info.name": "担当者名",
|
||||||
|
"myinfo.info.password": "パスワード",
|
||||||
|
"myinfo.info.chg.password": "新しいパスワード入力",
|
||||||
|
"myinfo.info.category": "部署名",
|
||||||
|
"myinfo.info.tel": "電話番号",
|
||||||
|
"myinfo.info.fax": "FAX番号",
|
||||||
|
"myinfo.info.mail": "メールアドレス",
|
||||||
|
"myinfo.sub.validation.password": "※ 半角10文字以内",
|
||||||
|
"myinfo.btn.close": "閉じる",
|
||||||
|
"myinfo.btn.chg.password": "パスワード変更",
|
||||||
|
"myinfo.btn.chg": "変更",
|
||||||
|
"myinfo.btn.noChg": "変更しない",
|
||||||
|
"myinfo.btn.confirm": "確認",
|
||||||
|
"myinfo.message.validation.password1": "パスワードを入力してください。",
|
||||||
|
"myinfo.message.validation.password2": "既存のパスワードと同じです。",
|
||||||
|
"myinfo.message.validation.password3": "半角文字10文字以内で入力してください。",
|
||||||
|
"myinfo.message.save": "パスワードが変更されました。",
|
||||||
|
"login": "ログイン",
|
||||||
|
"login.id.save": "ID保存",
|
||||||
|
"login.id.placeholder": "IDを入力してください。",
|
||||||
|
"login.password.placeholder": "パスワードを入力してください。",
|
||||||
|
"login.guide.text": "当サイトを利用するには、事前申請が必要です。",
|
||||||
|
"login.guide.sub1": "IDをお持ちでない方は",
|
||||||
|
"login.guide.sub2": "をクリックしてください。",
|
||||||
|
"login.guide.join.btn": "ID申請",
|
||||||
|
"login.init_password.btn": "パスワードリセット",
|
||||||
|
"login.init_password.btn.back": "前の画面に戻る",
|
||||||
|
"login.init_password.title": "パスワードリセット",
|
||||||
|
"login.init_password.sub_title": "パスワードをリセットするIDとメールアドレスを入力してください。",
|
||||||
|
"login.init_password.complete_message": "パスワードがリセットされました。リセット後のパスワードはIDと同じです。",
|
||||||
|
"login.init_password.id.placeholder": "IDを入力してください。",
|
||||||
|
"login.init_password.email.placeholder": "メールアドレスを入力してください。",
|
||||||
|
"join.title": "Q.CAST3 ログインID発行申請",
|
||||||
|
"join.sub1.title": "販売代理店情報",
|
||||||
|
"join.sub1.comment": "※ 登録する販売店の会社名を入力してください。(2次店の場合「○○販売株式会社(2次店:××設備株式会社)」と記載してください。)",
|
||||||
|
"join.sub1.storeQcastNm": "販売代理店名",
|
||||||
|
"join.sub1.storeQcastNm_placeholder": "株式会社 エナジー ギア ソリューション アンド サービス(2次店: 山口重機販売有限会社)",
|
||||||
|
"join.sub1.storeQcastNmKana": "販売代理店名ふりがな",
|
||||||
|
"join.sub1.storeQcastNmKana_placeholder": "株式会社 エナジー ギア ソリューション",
|
||||||
|
"join.sub1.postCd": "郵便番号",
|
||||||
|
"join.sub1.postCd_placeholder": "7桁の数字",
|
||||||
|
"join.sub1.addr": "住所",
|
||||||
|
"join.sub1.addr_placeholder": "全角50文字以内",
|
||||||
|
"join.sub1.telNo": "電話番号",
|
||||||
"join.sub1.telNo_placeholder": "00-0000-0000",
|
"join.sub1.telNo_placeholder": "00-0000-0000",
|
||||||
"join.sub1.fax": "FAX 번호",
|
"join.sub1.fax": "FAX番号",
|
||||||
"join.sub1.fax_placeholder": "00-0000-0000",
|
"join.sub1.fax_placeholder": "00-0000-0000",
|
||||||
"join.sub2.title": "담당자 정보",
|
"join.sub1.bizNo": "法人番号",
|
||||||
"join.sub2.userNm": "담당자명",
|
"join.sub2.title": "担当者情報",
|
||||||
"join.sub2.userNmKana": "담당자명 후리가나",
|
"join.sub2.userNm": "担当者名",
|
||||||
"join.sub2.userId": "신청 ID",
|
"join.sub2.userNmKana": "担当者名ふりがな",
|
||||||
"join.sub2.email": "이메일 주소",
|
"join.sub2.userId": "申請ID",
|
||||||
"join.sub2.telNo": "전화번호",
|
"join.sub2.email": "メールアドレス",
|
||||||
|
"join.sub2.telNo": "電話番号",
|
||||||
"join.sub2.telNo_placeholder": "00-0000-0000",
|
"join.sub2.telNo_placeholder": "00-0000-0000",
|
||||||
"join.sub2.fax": "FAX 번호",
|
"join.sub2.fax": "FAX番号",
|
||||||
"join.sub2.fax_placeholder": "00-0000-0000",
|
"join.sub2.fax_placeholder": "00-0000-0000",
|
||||||
"join.sub2.category": "부서명",
|
"join.sub2.category": "部署名",
|
||||||
"join.sub3.title": "견적서 제출용 회사정보",
|
"join.btn.login_page": "ログイン画面に移動",
|
||||||
"join.sub3.qtCompNm": "회사명",
|
"join.btn.approval_request": "ID承認申請",
|
||||||
"join.sub3.qtPostCd": "우편번호",
|
"join.complete.title": "Q.CAST3 ログインID発行申請完了",
|
||||||
"join.sub3.qtPostCd_placeholder": "숫자 7자리",
|
"join.complete.contents": "※ 申請したIDが承認されると、担当者情報に入力されたメールアドレスにログイン案内メールが送信されます。",
|
||||||
"join.sub3.qtAddr": "주소",
|
"join.complete.email_comment": "担当者メールアドレス",
|
||||||
"join.sub3.qtAddr_placeholder": "전각50자이내",
|
|
||||||
"join.sub3.qtEmail": "이메일 주소",
|
|
||||||
"join.sub3.qtTelNo": "전화번호",
|
|
||||||
"join.sub3.qtTelNo_placeholder": "00-0000-0000",
|
|
||||||
"join.sub3.qtFax": "FAX 번호",
|
|
||||||
"join.sub3.qtFax_placeholder": "00-0000-0000",
|
|
||||||
"join.btn.approval_request": "ID 승인요청",
|
|
||||||
"join.complete.title": "Q.CAST3 로그인ID 발행신청 완료",
|
|
||||||
"join.complete.contents": "※ 신청한 ID가 승인되면, 담당자 정보에 입력한 이메일 주소로 로그인 관련 안내 메일이 전송됩니다.",
|
|
||||||
"join.complete.email_comment": "담당자 이메일 주소",
|
|
||||||
"join.complete.email": "test@naver.com",
|
|
||||||
"stuff.gridHeader.lastEditDatetime": "更新日時",
|
"stuff.gridHeader.lastEditDatetime": "更新日時",
|
||||||
"stuff.gridHeader.objectNo": "品番",
|
"stuff.gridHeader.objectNo": "品番",
|
||||||
"stuff.gridHeader.planTotCnt": "プラン数",
|
"stuff.gridHeader.planTotCnt": "プラン数",
|
||||||
|
|||||||
@ -327,11 +327,56 @@
|
|||||||
"commons.north": "북",
|
"commons.north": "북",
|
||||||
"site.name": "Q.CAST III",
|
"site.name": "Q.CAST III",
|
||||||
"site.sub_name": "태양광 발전 시스템 도면관리 사이트",
|
"site.sub_name": "태양광 발전 시스템 도면관리 사이트",
|
||||||
|
"board.notice.title": "공지사항",
|
||||||
|
"board.notice.sub.title": "공지사항 목록",
|
||||||
|
"board.faq.title": "FAQ",
|
||||||
|
"board.faq.sub.title": "FAQ 목록",
|
||||||
|
"board.archive.title": "자료 다운로드",
|
||||||
|
"board.archive.sub.title": "문서 목록",
|
||||||
|
"board.list.header.rownum": "번호",
|
||||||
|
"board.list.header.title": "제목",
|
||||||
|
"board.list.header.regDt": "등록일",
|
||||||
|
"board.sub.search.placeholder": "검색어를 입력하세요.",
|
||||||
|
"board.sub.search.result": "{0}에 대해 총 {1}건의 글이 검색 되었습니다.",
|
||||||
|
"board.sub.search.archive.result": "{0}에 대해 총 {1}건의 문서가 검색 되었습니다.",
|
||||||
|
"board.sub.total": "전체",
|
||||||
|
"board.sub.fileList": "첨부파일 목록",
|
||||||
|
"board.sub.updDt": "업데이트",
|
||||||
|
"myinfo.title": "My profile",
|
||||||
|
"myinfo.info.userId": "사용자ID",
|
||||||
|
"myinfo.info.nameKana": "담당자명 후리가나",
|
||||||
|
"myinfo.info.name": "담당자명",
|
||||||
|
"myinfo.info.password": "비밀번호",
|
||||||
|
"myinfo.info.chg.password": "변경 비밀번호 입력",
|
||||||
|
"myinfo.info.category": "부서명",
|
||||||
|
"myinfo.info.tel": "전화번호",
|
||||||
|
"myinfo.info.fax": "FAX번호",
|
||||||
|
"myinfo.info.mail": "이메일 주소",
|
||||||
|
"myinfo.sub.validation.password": "※ 반각10자 이내",
|
||||||
|
"myinfo.btn.close": "닫기",
|
||||||
|
"myinfo.btn.chg.password": "비밀번호 변경",
|
||||||
|
"myinfo.btn.chg": "변경",
|
||||||
|
"myinfo.btn.noChg": "변경안함",
|
||||||
|
"myinfo.btn.confirm": "확인",
|
||||||
|
"myinfo.message.validation.password1": "비밀번호를 입력하세요.",
|
||||||
|
"myinfo.message.validation.password2": "기존 비밀번호와 동일합니다.",
|
||||||
|
"myinfo.message.validation.password3": "반각 문자 10자이내여야 합니다.",
|
||||||
|
"myinfo.message.save": "비밀번호가 변경되었습니다.",
|
||||||
"login": "로그인",
|
"login": "로그인",
|
||||||
|
"login.id.save": "ID Save",
|
||||||
|
"login.id.placeholder": "아이디를 입력해주세요.",
|
||||||
|
"login.password.placeholder": "비밀번호를 입력해주세요.",
|
||||||
|
"login.guide.text": "당 사이트를 이용할 때는, 사전 신청이 필요합니다.",
|
||||||
|
"login.guide.sub1": "ID가 없는 분은",
|
||||||
|
"login.guide.sub2": "을 클릭해주십시오.",
|
||||||
|
"login.guide.join.btn": "ID신청",
|
||||||
"login.init_password.btn": "비밀번호 초기화",
|
"login.init_password.btn": "비밀번호 초기화",
|
||||||
|
"login.init_password.btn.back": "이전 화면으로",
|
||||||
"login.init_password.title": "비밀번호 초기화",
|
"login.init_password.title": "비밀번호 초기화",
|
||||||
"login.init_password.sub_title": "비밀번호를 초기화할 아이디와 이메일 주소를 입력해 주세요.",
|
"login.init_password.sub_title": "비밀번호를 초기화할 아이디와 이메일 주소를 입력해 주세요.",
|
||||||
"login.init_password.complete_message": "비밀번호가 초기화 되었습니다. 초기화된 비밀번호는 아이디와 같습니다.",
|
"login.init_password.complete_message": "비밀번호가 초기화 되었습니다. 초기화된 비밀번호는 아이디와 같습니다.",
|
||||||
|
"login.init_password.id.placeholder": "ID를 입력하세요.",
|
||||||
|
"login.init_password.email.placeholder": "이메일을 입력하세요.",
|
||||||
"join.title": "Q.CAST3 로그인ID 발행 신청",
|
"join.title": "Q.CAST3 로그인ID 발행 신청",
|
||||||
"join.sub1.title": "판매대리점 정보",
|
"join.sub1.title": "판매대리점 정보",
|
||||||
"join.sub1.comment": "※ 등록되는 리셀러의 회사 이름을 입력하십시오. (2차점은 「○○판매주식회사(2차점:××설비주식회사)」로 기입해 주세요.)",
|
"join.sub1.comment": "※ 등록되는 리셀러의 회사 이름을 입력하십시오. (2차점은 「○○판매주식회사(2차점:××설비주식회사)」로 기입해 주세요.)",
|
||||||
@ -347,6 +392,7 @@
|
|||||||
"join.sub1.telNo_placeholder": "00-0000-0000",
|
"join.sub1.telNo_placeholder": "00-0000-0000",
|
||||||
"join.sub1.fax": "FAX 번호",
|
"join.sub1.fax": "FAX 번호",
|
||||||
"join.sub1.fax_placeholder": "00-0000-0000",
|
"join.sub1.fax_placeholder": "00-0000-0000",
|
||||||
|
"join.sub1.bizNo": "법인번호",
|
||||||
"join.sub2.title": "담당자 정보",
|
"join.sub2.title": "담당자 정보",
|
||||||
"join.sub2.userNm": "담당자명",
|
"join.sub2.userNm": "담당자명",
|
||||||
"join.sub2.userNmKana": "담당자명 후리가나",
|
"join.sub2.userNmKana": "담당자명 후리가나",
|
||||||
@ -357,22 +403,11 @@
|
|||||||
"join.sub2.fax": "FAX 번호",
|
"join.sub2.fax": "FAX 번호",
|
||||||
"join.sub2.fax_placeholder": "00-0000-0000",
|
"join.sub2.fax_placeholder": "00-0000-0000",
|
||||||
"join.sub2.category": "부서명",
|
"join.sub2.category": "부서명",
|
||||||
"join.sub3.title": "견적서 제출용 회사정보",
|
"join.btn.login_page": "로그인 화면으로 이동",
|
||||||
"join.sub3.qtCompNm": "회사명",
|
|
||||||
"join.sub3.qtPostCd": "우편번호",
|
|
||||||
"join.sub3.qtPostCd_placeholder": "숫자 7자리",
|
|
||||||
"join.sub3.qtAddr": "주소",
|
|
||||||
"join.sub3.qtAddr_placeholder": "전각50자이내",
|
|
||||||
"join.sub3.qtEmail": "이메일 주소",
|
|
||||||
"join.sub3.qtTelNo": "전화번호",
|
|
||||||
"join.sub3.qtTelNo_placeholder": "00-0000-0000",
|
|
||||||
"join.sub3.qtFax": "FAX 번호",
|
|
||||||
"join.sub3.qtFax_placeholder": "00-0000-0000",
|
|
||||||
"join.btn.approval_request": "ID 승인요청",
|
"join.btn.approval_request": "ID 승인요청",
|
||||||
"join.complete.title": "Q.CAST3 로그인ID 발행신청 완료",
|
"join.complete.title": "Q.CAST3 로그인ID 발행신청 완료",
|
||||||
"join.complete.contents": "※ 신청한 ID가 승인되면, 담당자 정보에 입력한 이메일 주소로 로그인 관련 안내 메일이 전송됩니다.",
|
"join.complete.contents": "※ 신청한 ID가 승인되면, 담당자 정보에 입력한 이메일 주소로 로그인 관련 안내 메일이 전송됩니다.",
|
||||||
"join.complete.email_comment": "담당자 이메일 주소",
|
"join.complete.email_comment": "담당자 이메일 주소",
|
||||||
"join.complete.email": "test@naver.com",
|
|
||||||
"stuff.gridHeader.lastEditDatetime": "갱신일시",
|
"stuff.gridHeader.lastEditDatetime": "갱신일시",
|
||||||
"stuff.gridHeader.objectNo": "물건번호",
|
"stuff.gridHeader.objectNo": "물건번호",
|
||||||
"stuff.gridHeader.planTotCnt": "플랜 수",
|
"stuff.gridHeader.planTotCnt": "플랜 수",
|
||||||
|
|||||||
14
src/store/boardAtom.js
Normal file
14
src/store/boardAtom.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { atom } from 'recoil'
|
||||||
|
|
||||||
|
export const searchState = atom({
|
||||||
|
key: 'searchState',
|
||||||
|
default: {
|
||||||
|
currentPage: 1,
|
||||||
|
totalPage: 1,
|
||||||
|
pageBlock: 100,
|
||||||
|
totalCount: 0,
|
||||||
|
searchValue: '',
|
||||||
|
mainFlag: 'N',
|
||||||
|
searchFlag: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
46
src/util/board-utils.js
Normal file
46
src/util/board-utils.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
|
|
||||||
|
// 파일 다운로드
|
||||||
|
export const handleFileDown = async (file) => {
|
||||||
|
const { get } = useAxios()
|
||||||
|
|
||||||
|
const url = `/api/board/file/download`
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
encodeFileNo: file.encodeFileNo,
|
||||||
|
})
|
||||||
|
const apiUrl = `${url}?${params.toString()}`
|
||||||
|
const resultData = await get({ url: apiUrl })
|
||||||
|
|
||||||
|
if (resultData) {
|
||||||
|
const blob = new Blob([resultData])
|
||||||
|
const fileUrl = window.URL.createObjectURL(blob)
|
||||||
|
const link = document.createElement('a')
|
||||||
|
|
||||||
|
link.href = fileUrl
|
||||||
|
link.download = file.srcFileNm
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
link.remove()
|
||||||
|
window.URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 페이지 번호 생성
|
||||||
|
export const generateBlockPagination = (currentPage, totalPages, pageBlock) => {
|
||||||
|
const currentBlock = Math.ceil(currentPage / pageBlock)
|
||||||
|
|
||||||
|
let startPage = (currentBlock - 1) * pageBlock + 1
|
||||||
|
let endPage = startPage + pageBlock - 1
|
||||||
|
|
||||||
|
if (endPage > totalPages) {
|
||||||
|
endPage = totalPages
|
||||||
|
}
|
||||||
|
|
||||||
|
let pageArr = []
|
||||||
|
|
||||||
|
for (let i = startPage; i <= endPage; i++) {
|
||||||
|
pageArr.push(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pageArr
|
||||||
|
}
|
||||||
@ -5189,6 +5189,11 @@ jiti@^1.21.0:
|
|||||||
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz"
|
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz"
|
||||||
integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==
|
integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==
|
||||||
|
|
||||||
|
js-cookie@^3.0.5:
|
||||||
|
version "3.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
|
||||||
|
integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==
|
||||||
|
|
||||||
js-md4@^0.3.2:
|
js-md4@^0.3.2:
|
||||||
version "0.3.2"
|
version "0.3.2"
|
||||||
resolved "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz"
|
resolved "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user