Compare commits

...

4 Commits

Author SHA1 Message Date
d718012f6f feat: 지붕재적합성 상세팝업 마크업 적용 및 팝업 on/off 연결 2025-05-23 13:31:42 +09:00
e833e25048 feat: Add representative and store ID fields to SD_SURVEY_SALES_BASIC_INFO model in Prisma schema 2025-05-23 11:22:02 +09:00
916946956a Merge pull request 'feature/suitable' (#44) from feature/suitable into dev
Reviewed-on: #44
2025-05-23 10:50:07 +09:00
29e7675ada refactor: Enhance authentication API and login component functionality
- Updated authentication API to improve response handling and session management.
- Refactored login component to include validation and keyboard event handling for login submission.
- Improved user feedback by displaying alerts for login success and failure messages.
2025-05-23 10:06:45 +09:00
5 changed files with 298 additions and 54 deletions

View File

@ -62,6 +62,8 @@ model SD_SURVEY_SALES_BASIC_INFO {
SUBMISSION_TARGET_ID String? @db.VarChar(200) SUBMISSION_TARGET_ID String? @db.VarChar(200)
REG_DT DateTime @default(now()) REG_DT DateTime @default(now())
UPT_DT DateTime @updatedAt UPT_DT DateTime @updatedAt
REPRESENTATIVE_ID String? @db.VarChar(100)
STORE_ID String? @db.VarChar(100)
DETAIL_INFO SD_SURVEY_SALES_DETAIL_INFO? DETAIL_INFO SD_SURVEY_SALES_DETAIL_INFO?
} }

View File

@ -15,7 +15,9 @@ export async function POST(request: Request) {
}) })
console.log('🚀 ~ result ~ result:', result.data) console.log('🚀 ~ result ~ result:', result.data)
if (result.data.result.code === 200) { let finalResult = {}
if (result.data.result.resultCode === 'S') {
tracking({ tracking({
url: `/api/auth/login`, url: `/api/auth/login`,
data: JSON.stringify({ data: JSON.stringify({
@ -72,7 +74,6 @@ export async function POST(request: Request) {
console.log('end session edit!') console.log('end session edit!')
await session.save() await session.save()
}
const resultForSession = { const resultForSession = {
LANG_CD: result.data.data.langCd, LANG_CD: result.data.data.langCd,
@ -119,5 +120,18 @@ export async function POST(request: Request) {
resultForSession.ROLE = 'User' resultForSession.ROLE = 'User'
} }
return NextResponse.json({ code: 200, message: 'Login is Succecss!!', result: resultForSession }) finalResult = {
code: 200,
message: 'Login is Succecss!!',
result: resultForSession,
}
} else {
finalResult = {
code: 400,
message: 'Login is Failed!!',
result: {},
}
}
return NextResponse.json(finalResult)
} }

View File

@ -39,6 +39,26 @@ export default function Login() {
return emailRegex.test(email) return emailRegex.test(email)
} }
const handleLogin = () => {
if (validateLogin()) {
setIsLogin(true)
}
}
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
handleLogin()
}
}
const validateLogin = () => {
if (account.loginId === '' || account.pwd === '') {
alert('Please enter your ID and password.')
return false
}
return true
}
interface LoginData { interface LoginData {
code: number code: number
message: string | null message: string | null
@ -85,6 +105,9 @@ export default function Login() {
...loginData?.result, ...loginData?.result,
}) })
router.push('/') router.push('/')
} else if (loginData?.code === 400) {
alert(loginData?.message)
setAccount({ loginId: '', pwd: '' })
} }
}, [loginData]) }, [loginData])
@ -106,6 +129,7 @@ export default function Login() {
className="login-frame" className="login-frame"
placeholder="Input Frame ID" placeholder="Input Frame ID"
value={account.loginId} value={account.loginId}
onKeyDown={(e) => handleKeyDown(e)}
onChange={(e) => setAccount({ loginId: e.target.value })} onChange={(e) => setAccount({ loginId: e.target.value })}
/> />
<button className="login-icon" onClick={() => setAccount({ loginId: '' })}> <button className="login-icon" onClick={() => setAccount({ loginId: '' })}>
@ -120,6 +144,7 @@ export default function Login() {
className="login-frame" className="login-frame"
placeholder="Input Frame PW" placeholder="Input Frame PW"
value={account.pwd} value={account.pwd}
onKeyDown={(e) => handleKeyDown(e)}
onChange={(e) => setAccount({ pwd: e.target.value })} onChange={(e) => setAccount({ pwd: e.target.value })}
/> />
<button className={`login-icon ${pwShow ? 'act' : ''}`} onClick={() => setPwShow(!pwShow)}> <button className={`login-icon ${pwShow ? 'act' : ''}`} onClick={() => setPwShow(!pwShow)}>
@ -141,7 +166,7 @@ export default function Login() {
</div> </div>
</div> </div>
<div className="login-btn-wrap"> <div className="login-btn-wrap">
<button className="btn-frame icon login" onClick={() => setIsLogin(true)}> <button className="btn-frame icon login" onClick={handleLogin}>
<i className="btn-arr"></i> <i className="btn-arr"></i>
</button> </button>
</div> </div>

View File

@ -1,4 +1,11 @@
'use client'
import Image from 'next/image'
import { usePopupController } from '@/store/popupController'
export default function SuitableDetailPopup() { export default function SuitableDetailPopup() {
const popupController = usePopupController()
return ( return (
<div className="modal-popup"> <div className="modal-popup">
<div className="modal-dialog"> <div className="modal-dialog">
@ -7,14 +14,15 @@ export default function SuitableDetailPopup() {
<div className="modal-header-inner"> <div className="modal-header-inner">
<div className="modal-name-wrap"> <div className="modal-name-wrap">
<div className="modal-img"> <div className="modal-img">
<img src="/assets/images/layout/modal_header_icon03.svg" alt="" /> <Image src="/assets/images/layout/modal_header_icon03.svg" width={22} height={22} alt="" />
</div> </div>
<div className="modal-name"> </div> <div className="modal-name"> </div>
</div> </div>
<button className="modal-close"></button> <button className="modal-close" onClick={() => popupController.setSuitableDetailPopup(false)}></button>
</div> </div>
</div> </div>
<div className="modal-body"> <div className="modal-body">
<div className="compliance-check-pop-wrap">
<div className={`compliance-check-bx act`}> <div className={`compliance-check-bx act`}>
<div className="check-name-wrap"> <div className="check-name-wrap">
<div className="check-name"></div> <div className="check-name"></div>
@ -22,7 +30,198 @@ export default function SuitableDetailPopup() {
<button className="bx-btn"></button> <button className="bx-btn"></button>
</div> </div>
</div> </div>
<div className="compliance-check-pop-contents"></div> <div className="compliance-check-pop-contents">
<div className="check-pop-data-wrap">
<div className="check-pop-data-tit"> </div>
<div className="check-pop-data-txt"></div>
</div>
<div className="check-pop-data-wrap">
<div className="check-pop-data-tit"></div>
<div className="check-pop-data-txt"></div>
</div>
<div className="check-pop-data-wrap">
<div className="check-pop-data-tit"></div>
<div className="check-pop-data-txt"></div>
</div>
<div className="check-pop-data-table-wrap">
<div className="check-pop-data-table">
<div className="pop-data-table-head">
<div className="pop-data-table-head-name"> </div>
<div className="pop-data-table-head-icon">
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_check_icon.svg'} width={22} height={22} alt=""></Image>
</div>
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_tip_icon.svg'} width={22} height={22} alt=""></Image>
</div>
</div>
</div>
<div className="pop-data-table-body"></div>
<div className="pop-data-table-footer">
<div className="pop-data-table-footer-unit"></div>
<div className="pop-data-table-footer-data">
使
</div>
</div>
</div>
<div className="check-pop-data-table">
<div className="pop-data-table-head">
<div className="pop-data-table-head-name"></div>
<div className="pop-data-table-head-icon">
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_x_icon.svg'} width={22} height={22} alt=""></Image>
</div>
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_tip_icon.svg'} width={22} height={22} alt=""></Image>
</div>
</div>
</div>
<div className="pop-data-table-body"></div>
<div className="pop-data-table-footer">
<div className="pop-data-table-footer-unit"></div>
<div className="pop-data-table-footer-data"></div>
</div>
</div>
<div className="check-pop-data-table">
<div className="pop-data-table-head">
<div className="pop-data-table-head-name">YGアンカー</div>
<div className="pop-data-table-head-icon">
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_quest_icon.svg'} width={22} height={22} alt=""></Image>
</div>
</div>
</div>
<div className="pop-data-table-body"></div>
<div className="pop-data-table-footer">
<div className="pop-data-table-footer-unit"></div>
<div className="pop-data-table-footer-data"></div>
</div>
</div>
<div className="check-pop-data-table">
<div className="pop-data-table-head">
<div className="pop-data-table-head-name"></div>
<div className="pop-data-table-head-icon">
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_check_icon.svg'} width={22} height={22} alt=""></Image>
</div>
</div>
</div>
<div className="pop-data-table-body"> () </div>
<div className="pop-data-table-footer">
<div className="pop-data-table-footer-unit"></div>
<div className="pop-data-table-footer-data"></div>
</div>
</div>
</div>
</div>
</div>
<div className={`compliance-check-bx`}>
<div className="check-name-wrap">
<div className="check-name"></div>
<div className="check-name-btn">
<button className="bx-btn"></button>
</div>
</div>
<div className="compliance-check-pop-contents">
<div className="check-pop-data-wrap">
<div className="check-pop-data-tit"> </div>
<div className="check-pop-data-txt"></div>
</div>
<div className="check-pop-data-wrap">
<div className="check-pop-data-tit"></div>
<div className="check-pop-data-txt"></div>
</div>
<div className="check-pop-data-wrap">
<div className="check-pop-data-tit"></div>
<div className="check-pop-data-txt"></div>
</div>
<div className="check-pop-data-table-wrap">
<div className="check-pop-data-table">
<div className="pop-data-table-head">
<div className="pop-data-table-head-name"> </div>
<div className="pop-data-table-head-icon">
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_check_icon.svg'} width={22} height={22} alt=""></Image>
</div>
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_tip_icon.svg'} width={22} height={22} alt=""></Image>
</div>
</div>
</div>
<div className="pop-data-table-body"></div>
<div className="pop-data-table-footer">
<div className="pop-data-table-footer-unit"></div>
<div className="pop-data-table-footer-data"></div>
</div>
</div>
<div className="check-pop-data-table">
<div className="pop-data-table-head">
<div className="pop-data-table-head-name"></div>
<div className="pop-data-table-head-icon">
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_x_icon.svg'} width={22} height={22} alt=""></Image>
</div>
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_tip_icon.svg'} width={22} height={22} alt=""></Image>
</div>
</div>
</div>
<div className="pop-data-table-body"></div>
<div className="pop-data-table-footer">
<div className="pop-data-table-footer-unit"></div>
<div className="pop-data-table-footer-data"></div>
</div>
</div>
<div className="check-pop-data-table">
<div className="pop-data-table-head">
<div className="pop-data-table-head-name">YGアンカー</div>
<div className="pop-data-table-head-icon">
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_quest_icon.svg'} width={22} height={22} alt=""></Image>
</div>
</div>
</div>
<div className="pop-data-table-body"></div>
<div className="pop-data-table-footer">
<div className="pop-data-table-footer-unit"></div>
<div className="pop-data-table-footer-data"></div>
</div>
</div>
<div className="check-pop-data-table">
<div className="pop-data-table-head">
<div className="pop-data-table-head-name"></div>
<div className="pop-data-table-head-icon">
<div className="compliance-icon">
<Image src={'/assets/images/sub/compliance_check_icon.svg'} width={22} height={22} alt=""></Image>
</div>
</div>
</div>
<div className="pop-data-table-body"> () </div>
<div className="pop-data-table-footer">
<div className="pop-data-table-footer-unit"></div>
<div className="pop-data-table-footer-data"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="btn-flex-wrap com">
<div className="btn-bx">
<button className="btn-frame n-blue icon">
<i className="btn-arr"></i>
</button>
</div>
<div className="btn-bx">
<button className="btn-frame red icon">
<i className="btn-arr"></i>
</button>
</div>
<div className="btn-bx">
<button className="btn-frame n-blue icon">
11<i className="btn-arr"></i>
</button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,6 +1,10 @@
'use client' 'use client'
import { usePopupController } from '@/store/popupController'
export default function SuitableButton() { export default function SuitableButton() {
const popupController = usePopupController()
return ( return (
<div className="float-btn-wrap"> <div className="float-btn-wrap">
<div className="btn-flex-wrap com"> <div className="btn-flex-wrap com">
@ -10,7 +14,7 @@ export default function SuitableButton() {
</button> </button>
</div> </div>
<div className="btn-bx"> <div className="btn-bx">
<button className="btn-frame red icon"> <button className="btn-frame red icon" onClick={() => popupController.setSuitableDetailPopup(true)}>
<i className="btn-arr"></i> <i className="btn-arr"></i>
</button> </button>
</div> </div>