Compare commits

...

10 Commits

Author SHA1 Message Date
f06b7cf0ac fix: fix build error 2025-06-05 13:48:20 +09:00
b368443033 Merge pull request 'feature/inquiry : 파일 다운로드 오류 해결 및 사이드바 라우팅 변경' (#60) from feature/inquiry into dev
Reviewed-on: #60
2025-06-05 13:26:27 +09:00
83bdba2cd5 Merge branch 'feature/survey' of https://git.hanasys.jp/qcast3/onsitesurvey into feature/inquiry 2025-06-05 12:55:20 +09:00
36f11d93d3 Merge branch 'feature/survey' of https://git.hanasys.jp/qcast3/onsitesurvey into feature/inquiry 2025-06-05 11:37:19 +09:00
e615521aeb feat: change route url on sidebar nav
- 사이드 바 URL 변경
- '내가 작성한 매물', '내가 작성한 문의' 카드 클릭 시 체크박스 선택 된 채로 이동하도록 구현
2025-06-05 11:36:49 +09:00
730e9a85e3 Merge branch 'dev' of https://git.hanasys.jp/qcast3/onsitesurvey into feature/inquiry 2025-06-05 11:14:34 +09:00
9801ac4c44 fix: fix file download error 2025-06-05 11:14:25 +09:00
51aa45206f refactor: simplify Footer component structure
- Removed unnecessary imports and streamlined the Footer component by consolidating content into a single div, enhancing readability and maintainability.
2025-06-05 10:21:22 +09:00
4ae536cde4 refactor: streamline spinner visibility logic in useAxios hook
- Updated responseHandler to always hide the spinner, removing the conditional check for 'spinner-state' header.
2025-06-05 10:14:13 +09:00
3e8e08c3eb fix: prevent spinner from hiding on specific response headers
- Updated responseHandler in useAxios hook to conditionally hide the spinner only when the 'spinner-state' header is undefined.
2025-06-05 10:04:58 +09:00
8 changed files with 105 additions and 40 deletions

View File

@ -1,33 +1,73 @@
import axios from 'axios'
import { NextResponse } from 'next/server'
// export async function GET(request: Request) {
// const { searchParams } = new URL(request.url)
// const encodeFileNo = searchParams.get('encodeFileNo')
// const srcFileNm = searchParams.get('srcFileNm')
// if (!encodeFileNo) {
// return NextResponse.json({ error: 'encodeFileNo is required' }, { status: 400 })
// }
// try {
// const response = await axios.get(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/file/downloadFile2`, {
// params: {
// encodeFileNo,
// },
// responseType: 'arraybuffer',
// })
// if (response.headers['content-type'] === 'text/html;charset=utf-8') {
// return NextResponse.json({ error: 'file not found' }, { status: 404 })
// }
// const contentType = response.headers['content-type'] || 'application/octet-stream'
// const contentDisposition = response.headers['content-disposition'] || 'inline'
// return new NextResponse(response.data, {
// status: 200,
// headers: {
// 'Content-Type': contentType,
// 'Content-Disposition': contentDisposition,
// },
// })
// } catch (error: any) {
// console.error('File download error:', error)
// return NextResponse.json({ error: error.response?.data || 'Failed to download file' }, { status: 500 })
// }
// }
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const encodeFileNo = searchParams.get('encodeFileNo')
const srcFileNm = searchParams.get('srcFileNm')
const srcFileNm = searchParams.get('srcFileNm') || 'downloaded-file'
if (!encodeFileNo) {
return NextResponse.json({ error: 'encodeFileNo is required' }, { status: 400 })
}
const url = `${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/file/downloadFile2?encodeFileNo=${encodeFileNo}`
try {
const response = await axios.get(`${process.env.NEXT_PUBLIC_INQUIRY_API_URL}/api/file/downloadFile2`, {
responseType: 'arraybuffer',
params: {
encodeFileNo,
},
})
if (response.headers['content-type'] === 'text/html;charset=utf-8') {
return NextResponse.json({ error: 'file not found' }, { status: 404 })
const resp = await fetch(url)
if (!resp.ok) {
return NextResponse.json({ error: 'Failed to download file' }, { status: 500 })
}
return new NextResponse(response.data, {
const contentType = resp.headers.get('content-type') || 'application/octet-stream'
const contentDisposition = resp.headers.get('content-disposition') || `attachment; filename="${srcFileNm}"`
return new NextResponse(resp.body, {
status: 200,
headers: {
'Content-Type': 'application/octet-stream;charset=UTF-8',
'Content-Disposition': `attachment; filename="${srcFileNm}"`,
'Content-Type': contentType,
'Content-Disposition': contentDisposition,
},
})
} catch (error: any) {
return NextResponse.json({ error: error.response.data }, { status: 500 })
console.error('File download error:', error)
return NextResponse.json({ error: error.response?.data || 'Failed to download file' }, { status: 500 })
}
}

View File

@ -5,7 +5,7 @@ import { useState } from 'react'
export default function ListForm() {
const router = useRouter()
const { inquiryListRequest, setInquiryListRequest, reset } = useInquiryFilterStore()
const { inquiryListRequest, setInquiryListRequest, reset, setOffset } = useInquiryFilterStore()
const [searchKeyword, setSearchKeyword] = useState(inquiryListRequest.schTitle ?? '')
const handleSearch = () => {
@ -40,6 +40,19 @@ export default function ListForm() {
onChange={(e) => setSearchKeyword(e.target.value)}
onKeyDown={handleKeyDown}
/>
{searchKeyword && (
<button
className="del-icon"
onClick={() => {
setSearchKeyword('')
setInquiryListRequest({
...inquiryListRequest,
schTitle: '',
})
setOffset(1)
}}
></button>
)}
<button className="search-icon" onClick={handleSearch}></button>
</div>
</div>

View File

@ -86,7 +86,7 @@ export default function ListTable() {
<div className="inquiry-table-filter">
<div className="filter-check">
<div className="check-form-box">
<input type="checkbox" id="ch01" onChange={handleMyInquiry} />
<input type="checkbox" id="ch01" onChange={handleMyInquiry} checked={inquiryListRequest.schRegId === session.userId} />
<label htmlFor="ch01"></label>
</div>
</div>

View File

@ -1,21 +1,10 @@
'use client'
import Link from 'next/link'
import Config from '@/config/config.export'
export default function Footer() {
return (
<>
<footer>
<div className="footer-inner">
COPYRIGHT©2025 Hanwha Japan All Rights Reserved{' '}
<span>
<Link href="/pdf/suitable">PDF</Link>
</span>
<span>{Config().mode}</span>
<span>{Config().baseUrl}</span>
<span>{process.env.NEXT_PUBLIC_API_URL}</span>
</div>
<div className="footer-inner">COPYRIGHT©2025 Hanwha Japan All Rights Reserved </div>
</footer>
</>
)

View File

@ -11,6 +11,8 @@ import { useSideNavState } from '@/store/sideNavState'
import { useHeaderStore } from '@/store/header'
import { useSessionStore } from '@/store/session'
import { usePopupController } from '@/store/popupController'
import { useSurveyFilterStore } from '@/store/surveyFilterStore'
import { useInquiryFilterStore } from '@/store/inquiryFilterStore'
import { useTitle } from '@/hooks/useTitle'
import { useAxios } from '@/hooks/useAxios'
@ -30,6 +32,9 @@ export default function Header() {
const popupController = usePopupController()
const { setIsMySurvey } = useSurveyFilterStore()
const { setInquiryListRequest, inquiryListRequest } = useInquiryFilterStore()
if (pathname === '/login') {
return null
}
@ -80,13 +85,27 @@ export default function Header() {
<div className="side-swiper-wrap">
<Swiper slidesPerView={1.6} spaceBetween={12} className="mySwiper">
<SwiperSlide>
<div className="side-swiper-card">
<div
className="side-swiper-card"
onClick={() => {
setIsMySurvey(session?.userId)
router.push('/survey-sale')
setSideNavIsOpen(false)
}}
>
<div className="side-swiper-icon icon01"></div>
<div className="side-swiper-infor"></div>
</div>
</SwiperSlide>
<SwiperSlide>
<div className="side-swiper-card">
<div
className="side-swiper-card"
onClick={() => {
setInquiryListRequest({ ...inquiryListRequest, schRegId: session?.userId })
router.push('/inquiry/list')
setSideNavIsOpen(false)
}}
>
<div className="side-swiper-icon icon02"></div>
<div className="side-swiper-infor"> </div>
</div>
@ -105,7 +124,7 @@ export default function Header() {
<button onClick={() => router.push('/survey-sale')}>調</button>
</li>
<li className="side-nav-item">
<button onClick={() => router.push('/survey-sale/basic-info')}>調</button>
<button onClick={() => router.push('/survey-sale/regist')}>調</button>
</li>
<li className="side-nav-item">
<button onClick={() => router.push('/inquiry/list')}>1:1お問い合わせ</button>

View File

@ -9,7 +9,9 @@ export function useAxios() {
}
const responseHandler = (response: AxiosResponse) => {
// if (response.headers['spinner-state'] === undefined) {
useSpinnerStore.getState().setIsShow(false)
// }
response.data = transferResponse(response)
return response
}

View File

@ -76,19 +76,22 @@ export function useInquiry(
const downloadFile = async (encodeFileNo: number, srcFileNm: string) => {
try {
const resp = await axiosInstance(null).get<Blob>(`/api/qna/file`, { params: { encodeFileNo, srcFileNm } })
const blob = new Blob([resp.data], { type: 'application/octet-stream;charset=UTF-8' })
const resp = await fetch(`/api/qna/file?encodeFileNo=${encodeFileNo}&srcFileNm=${srcFileNm}`)
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${srcFileNm}`
a.download = srcFileNm
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
return blob
} catch (error: any) {
if (error.response.status === 404) {
alert('ファイルが見つかりません')
}
} catch (error) {
console.error('File download error:', error)
alert('ファイルのダウンロードに失敗しました')
return null
}
}

View File

@ -175,10 +175,9 @@ export function useSurvey(id?: number): {
})
return resp.data.id ?? 0
},
onSuccess: (data) => {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['survey', 'list'] })
queryClient.invalidateQueries({ queryKey: ['survey', id] })
return data
},
})