Merge branch 'dev' of https://git.hanasys.jp/qcast3/onsitesurvey into feature/survey

This commit is contained in:
Dayoung 2025-05-02 18:10:48 +09:00
commit ec9f0fa747
18 changed files with 433 additions and 34 deletions

View File

@ -37,3 +37,7 @@ const popupController = usePopupController()
onClick={() => popupController.setMemberInformationPopup(false)}
onClick={() => popupController.setZipCodePopup(false)}
```
# useEffect 정리
- client url pathname 변경시 -> @/components/ui/Header.tsx

View File

@ -1,9 +1,5 @@
import InquiryDetail from '@/components/inquiry/InquiryDetail'
import Detail from '@/components/inquiry/Detail'
export default function InquiryDetails() {
return (
<div>
<InquiryDetail />
</div>
)
export default function page() {
return <Detail />
}

View File

@ -0,0 +1,3 @@
export default function layout({ children }: { children: React.ReactNode }) {
return <div className="container">{children}</div>
}

View File

@ -0,0 +1,13 @@
import ListForm from '@/components/inquiry/ListForm'
import ListTable from '@/components/inquiry/ListTable'
export default function page() {
return (
<>
<div className="sale-contents">
<ListForm />
<ListTable />
</div>
</>
)
}

View File

@ -1,9 +0,0 @@
import InquiryList from '@/components/inquiry/InquiryList'
export default function Inquiry() {
return (
<div>
<InquiryList />
</div>
)
}

View File

@ -0,0 +1,9 @@
import RegistForm from '@/components/inquiry/RegistForm'
export default function page() {
return (
<>
<RegistForm />
</>
)
}

View File

@ -0,0 +1,38 @@
'use client'
export default function Answer() {
return (
<>
<div className="inquiry-answer-wrap">
<div className="inquiry-answer-header">
<div className="inquiry-answer-tit">Hanwha Japan </div>
<div className="inquiry-answer-date">
<span></span>/ <span>2025.04.02 16:54:00</span>
</div>
</div>
<div className="inquiry-detail-data">
<div className="inquiry-detail-category"></div>
<div className="inquiry-detail-txt">
, . ,
</div>
</div>
<div className="file-list-wrap">
<div className="file-list-tit"></div>
<ul className="file-list">
<li className="file-item">
<button className="file-item-bx">
<div className="file-item-name">.jpg </div>
</button>
</li>
<li className="file-item">
<button className="file-item-bx">
<div className="file-item-name">.jpg </div>
</button>
</li>
</ul>
</div>
</div>
</>
)
}

View File

@ -0,0 +1,87 @@
'use client'
import { useState } from 'react'
import Answer from './Answer'
export default function Detail() {
//todo: 답변 완료 표시를 위해 임시로 추가 해 놓은 state
// 추후에 api 작업 완료후 삭제
// 답변 완료 클래스 & 하단 답변내용 출력도
const [inquiry, setInquiry] = useState<Boolean>(false)
return (
<>
<div className="inquiry-frame">
<div className="inquiry-detail-wrap">
<div className="inquiry-detail-badge">
<div className={`badge ${inquiry ? 'orange' : 'blue'} block`}></div>
</div>
<div className="inquiry-detail-data-table">
<table className="sale-data-table">
<colgroup>
<col style={{ width: '80px' }} />
<col />
</colgroup>
<tbody>
<tr>
<th></th>
<td>2025.04.10</td>
</tr>
<tr>
<th></th>
<td>Hong gi</td>
</tr>
<tr>
<th></th>
<td>interplug</td>
</tr>
<tr>
<th></th>
<td>interplugs</td>
</tr>
<tr>
<th>E-mail</th>
<td>Hong@interplug.co.kr</td>
</tr>
</tbody>
</table>
</div>
<div className="inquiry-detail-data">
<div className="inquiry-detail-category"></div>
<div className="inquiry-detail-tit"></div>
<div className="inquiry-detail-txt">
.
<br />
.
<br />
.
</div>
</div>
<div className="file-list-wrap">
<div className="file-list-tit"></div>
<ul className="file-list">
<li className="file-item">
<button className="file-item-bx">
<div className="file-item-name">.jpg </div>
</button>
</li>
<li className="file-item">
<button className="file-item-bx">
<div className="file-item-name">.jpg </div>
</button>
</li>
</ul>
</div>
</div>
{inquiry && <Answer />}
<div className="sale-edit-btn">
<button className="btn-frame n-blue icon">
<i className="btn-arr"></i>
</button>
</div>
</div>
</>
)
}

View File

@ -0,0 +1,20 @@
'use client'
export default function ListForm() {
return (
<>
<div className="sale-frame">
<div className="sale-form-bx">
<button className="btn-frame n-blue icon">
<i className="btn-arr"></i>
</button>
</div>
<div className="sale-form-bx">
<div className="search-input">
<input type="text" className="search-frame" placeholder="タイトルを入力してください. (2文字以上)" />
<button className="search-icon"></button>
</div>
</div>
</div>
</>
)
}

View File

@ -0,0 +1,70 @@
'use client'
export default function ListTable() {
return (
<>
<div className="sale-frame">
<div className="inquiry-table-filter">
<div className="filter-check">
<div className="check-form-box">
<input type="checkbox" id="ch01" />
<label htmlFor="ch01"></label>
</div>
</div>
<div className="filter-select">
<select className="select-form" name="" id="">
<option value=""></option>
<option value=""></option>
<option value=""></option>
<option value=""></option>
<option value=""></option>
</select>
</div>
</div>
<div className="inquiry-list-wrap">
<div className="inquiry-list-tit">
<span>98</span>
</div>
<ul className="inquiry-list">
<li className="inquiry-item">
<div className="inquiry-item-bx">
<div className="inquiry-item-category"></div>
<div className="inquiry-item-tit"></div>
<div className="inquiry-item-date">2025.04.02</div>
<div className="inquiry-badge badge blue"></div>
</div>
</li>
<li className="inquiry-item">
<div className="inquiry-item-bx">
<div className="inquiry-item-category"></div>
<div className="inquiry-item-tit"></div>
<div className="inquiry-item-date">2025.04.02</div>
<div className="inquiry-badge badge orange"></div>
</div>
</li>
<li className="inquiry-item">
<div className="inquiry-item-bx">
<div className="inquiry-item-category"></div>
<div className="inquiry-item-tit"></div>
<div className="inquiry-item-date">2025.04.02</div>
<div className="inquiry-badge badge blue"></div>
</div>
</li>
<li className="inquiry-item">
<div className="inquiry-item-bx">
<div className="inquiry-item-category"></div>
<div className="inquiry-item-tit"></div>
<div className="inquiry-item-date">2025.04.02</div>
<div className="inquiry-badge badge orange"></div>
</div>
</li>
</ul>
<div className="sale-edit-btn">
<button className="btn-frame n-blue icon">
<i className="btn-edit"></i>
</button>
</div>
</div>
</div>
</>
)
}

View File

@ -0,0 +1,79 @@
'use client'
export default function RegistForm() {
return (
<>
<div className="inquiry-frame">
<div className="data-form-wrap">
<div className="data-input-form-bx">
<div className="data-input-form-tit">
<i className="import">*</i>
</div>
<div className="data-input">
<select className="select-form" name="" id="">
<option value=""></option>
<option value=""></option>
<option value=""></option>
<option value=""></option>
<option value=""></option>
</select>
</div>
</div>
<div className="data-input-form-bx">
<div className="data-input-form-tit">
<i className="import">*</i>
</div>
<div className="data-input">
<select className="select-form" name="" id="">
<option value=""></option>
<option value=""></option>
<option value=""></option>
<option value=""></option>
<option value=""></option>
</select>
</div>
</div>
<div className="data-input-form-bx">
<div className="data-input-form-tit">
<i className="import">*</i>
</div>
<div className="data-input">
<textarea className="textarea-form" rows={6} name="" id="" placeholder="TextArea Filed"></textarea>
</div>
</div>
</div>
<div className="inquiry-file-wrap">
<div className="filebox">
<label className="btn-frame l-blue icon" htmlFor="file">
<i className="btn-clip"></i>Attach
</label>
<input type="file" id="file" />
</div>
<div className="file-list-wrap">
<div className="file-list-tit">
<span>2</span>
</div>
<ul className="file-list">
<li className="file-item">
<div className="file-item-bx">
<div className="file-item-name">.jpg </div>
<button className="file-del"></button>
</div>
</li>
<li className="file-item">
<div className="file-item-bx">
<div className="file-item-name">.jpg </div>
<button className="file-del"></button>
</div>
</li>
</ul>
</div>
<div className="sale-edit-btn">
<button className="btn-frame n-blue icon">
<i className="btn-arr"></i>
</button>
</div>
</div>
</div>
</>
)
}

View File

@ -1,8 +1,11 @@
'use client'
import { useSurveySaleTabState } from '@/store/surveySaleTabState'
import { usePathname, useRouter } from 'next/navigation'
import { useEffect } from 'react'
export default function NavTab() {
const router = useRouter()
const pathname = usePathname()
const router = useRouter()
@ -10,15 +13,31 @@ export default function NavTab() {
return null
}
const { basicInfoSelected, roofInfoSelected, reset } = useSurveySaleTabState()
useEffect(() => {
return () => {
reset()
}
}, [])
const handleBasicInfoClick = () => {
router.push('/survey-sale/basic-info')
}
const handleRoofInfoClick = () => {
router.push('/survey-sale/roof-info')
}
return (
<>
<div className="sale-detail-tab-relative">
<div className="sale-detail-tab-wrap">
<div className="sale-detail-tab-inner">
<button className="sale-detail-tab" onClick={() => router.push('/survey-sale/basic-info')}>
<button className={`sale-detail-tab ${basicInfoSelected ? 'act' : ''}`} onClick={handleBasicInfoClick}>
</button>
<button className="sale-detail-tab" onClick={() => router.push('/survey-sale/roof-info')}>
<button className={`sale-detail-tab ${roofInfoSelected ? 'act' : ''}`} onClick={handleRoofInfoClick}>
/
</button>
</div>

View File

@ -4,6 +4,7 @@ import { useServey } from '@/hooks/useSurvey'
import { SurveyBasicRequest } from '@/types/Survey'
import { useRouter, useSearchParams } from 'next/navigation'
import { useState, useEffect } from 'react'
import { useSurveySaleTabState } from '@/store/surveySaleTabState'
const defaultBasicInfoForm: SurveyBasicRequest = {
representative: '',
@ -53,6 +54,12 @@ export default function BasicForm() {
return <div>Loading...</div>
}
const { setBasicInfoSelected } = useSurveySaleTabState()
useEffect(() => {
setBasicInfoSelected()
}, [])
return (
<>
<div className="sale-frame">

View File

@ -1,5 +1,8 @@
'use client'
import { useEffect } from 'react'
import { useSurveySaleTabState } from '@/store/surveySaleTabState'
import { useServey } from '@/hooks/useSurvey'
import { SurveyDetailRequest } from '@/types/Survey'
import { useRouter, useSearchParams } from 'next/navigation'
@ -44,6 +47,12 @@ const defaultDetailInfoForm: SurveyDetailRequest = {
}
export default function RoofInfoForm() {
const { setRoofInfoSelected } = useSurveySaleTabState()
useEffect(() => {
setRoofInfoSelected()
}, [])
const router = useRouter()
const searchParams = useSearchParams()
const id = searchParams.get('id')

View File

@ -1,10 +1,13 @@
'use client'
import { useHeaderStore } from '@/store/header'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'
export default function Main() {
const router = useRouter()
const { setBackBtn } = useHeaderStore()
useEffect(() => {
setBackBtn(false)
}, [])
@ -27,7 +30,7 @@ export default function Main() {
<div className="main-bx-icon">
<img src="/assets/images/main/main_icon01.svg" alt="" />
</div>
<button className="main-bx-arr"></button>
<button className="main-bx-arr" onClick={() => router.push('/survey-sale')}></button>
</div>
<div className="grid-bx-body">
<div className="grid-bx-body-tit">調</div>
@ -39,7 +42,7 @@ export default function Main() {
<div className="main-bx-icon">
<img src="/assets/images/main/main_icon02.svg" alt="" />
</div>
<button className="main-bx-arr"></button>
<button className="main-bx-arr" onClick={() => router.push('/survey-sale/basic-info')}></button>
</div>
<div className="grid-bx-body">
<div className="grid-bx-body-tit">調</div>
@ -51,7 +54,7 @@ export default function Main() {
<div className="main-bx-icon">
<img src="/assets/images/main/main_icon03.svg" alt="" />
</div>
<button className="main-bx-arr"></button>
<button className="main-bx-arr" onClick={() => router.push('/inquiry/list')}></button>
</div>
<div className="grid-bx-body">
<div className="grid-bx-body-tit">1:1お問い合わせ </div>
@ -63,7 +66,7 @@ export default function Main() {
<div className="main-bx-icon">
<img src="/assets/images/main/main_icon04.svg" alt="" />
</div>
<button className="main-bx-arr"></button>
<button className="main-bx-arr" onClick={() => router.push('/inquiry/regist')}></button>
</div>
<div className="grid-bx-body">
<div className="grid-bx-body-tit">1:1問い合わせ登録</div>

View File

@ -3,13 +3,14 @@
import { useEffect, useState } from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { usePathname, useRouter } from 'next/navigation'
import { Swiper, SwiperSlide } from 'swiper/react'
import type { HeaderProps } from '@/types/Header'
import 'swiper/css'
import { useSideNavState } from '@/store/sideNavState'
// type HeaderProps = {
// name: string //header 이름
@ -17,8 +18,9 @@ import 'swiper/css'
// }
export default function Header({ name }: HeaderProps) {
const router = useRouter()
const pathname = usePathname()
const [headerAct, setHeaderAct] = useState<boolean>(false)
const { sideNavIsOpen, setSideNavIsOpen, reset } = useSideNavState()
const [isShowBackBtn, setIsShowBackBtn] = useState<boolean>(false)
if (pathname === '/login') {
@ -29,6 +31,8 @@ export default function Header({ name }: HeaderProps) {
if (pathname !== '/') {
setIsShowBackBtn(true)
}
//사이드바 초기화
reset()
}, [pathname])
return (
@ -38,17 +42,17 @@ export default function Header({ name }: HeaderProps) {
<div className="header-inner">
{isShowBackBtn && (
<div className="back-button-wrap">
<button className="back-button"></button>
<button className="back-button" onClick={() => router.back()}></button>
</div>
)}
<h2 className="logo">
<Link href={'#'}>{name}</Link>
<Link href={'/'}>{name}</Link>
</h2>
<div className="side-button-wrap">
<button className="side-button" onClick={() => setHeaderAct(true)}></button>
<button className="side-button" onClick={() => setSideNavIsOpen(true)}></button>
</div>
</div>
<div className={`side-nav ${headerAct ? 'active' : ''}`}>
<div className={`side-nav ${sideNavIsOpen ? 'active' : ''}`}>
<div className="side-nav-inner">
<div className="side-nav-header">
<div className="side-header-profile">
@ -61,7 +65,7 @@ export default function Header({ name }: HeaderProps) {
</div>
</div>
<div className="side-close-wrap">
<button className="side-close-btn" onClick={() => setHeaderAct(false)}></button>
<button className="side-close-btn" onClick={() => setSideNavIsOpen(false)}></button>
</div>
</div>
<div className="side-swiper-wrap">
@ -89,16 +93,16 @@ export default function Header({ name }: HeaderProps) {
<nav className="side-nav-wrap">
<ul className="side-nav-list">
<li className="side-nav-item">
<button>調</button>
<button onClick={() => router.push('/survey-sale')}>調</button>
</li>
<li className="side-nav-item">
<button>調</button>
<button onClick={() => router.push('/survey-sale/basic-info')}>調</button>
</li>
<li className="side-nav-item">
<button>1:1お問い合わせ</button>
<button onClick={() => router.push('/inquiry/list')}>1:1お問い合わせ</button>
</li>
<li className="side-nav-item">
<button>1:1お問い合わせ登録</button>
<button onClick={() => router.push('/inquiry/regist')}>1:1お問い合わせ登録</button>
</li>
<li className="side-nav-item">
<button></button>
@ -114,7 +118,7 @@ export default function Header({ name }: HeaderProps) {
<button>Jynoadmin</button>
</li>
<li className="side-footer-item">
<button>HOME</button>
<button onClick={() => router.push('/')}>HOME</button>
</li>
</ul>
</div>

21
src/store/sideNavState.ts Normal file
View File

@ -0,0 +1,21 @@
import { create } from 'zustand'
type SideNavState = {
sideNavIsOpen: boolean
setSideNavIsOpen: (value: boolean) => void
reset: () => void
}
type InitialState = {
sideNavIsOpen: boolean
}
const initialState: InitialState = {
sideNavIsOpen: false,
}
export const useSideNavState = create<SideNavState>((set) => ({
...initialState,
setSideNavIsOpen: (value: boolean) => set((state) => ({ ...state, sideNavIsOpen: value })),
reset: () => set(initialState),
}))

View File

@ -0,0 +1,26 @@
import { create } from 'zustand'
type SurveySaleTabState = {
basicInfoSelected: boolean
roofInfoSelected: boolean
setBasicInfoSelected: () => void
setRoofInfoSelected: () => void
reset: () => void
}
type InitialState = {
basicInfoSelected: boolean
roofInfoSelected: boolean
}
const initialState: InitialState = {
basicInfoSelected: true,
roofInfoSelected: false,
}
export const useSurveySaleTabState = create<SurveySaleTabState>((set) => ({
...initialState,
setBasicInfoSelected: () => set((state) => ({ ...state, basicInfoSelected: true, roofInfoSelected: false })),
setRoofInfoSelected: () => set((state) => ({ ...state, basicInfoSelected: false, roofInfoSelected: true })),
reset: () => set(initialState),
}))