diff --git a/package-lock.json b/package-lock.json index 98a452c..50673cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "@tanstack/react-query-devtools": "^5.71.0", "@types/nodemailer": "^6.4.17", "axios": "^1.8.4", - "crypto-js": "^4.2.0", "env-cmd": "^10.1.0", "iron-session": "^8.0.4", "lucide": "^0.503.0", @@ -33,7 +32,6 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4", - "@types/crypto-js": "^4.2.2", "@types/mysql": "^2.15.27", "@types/node": "^20", "@types/react": "^19", @@ -2142,13 +2140,6 @@ "integrity": "sha512-7qSgZbincDDDFyRweCIEvZULFAw5iz/DeunhvuxpL31nfntX3P4Yd4HkHBRg9H8CdqY1e5WFN1PZIz/REL9MVQ==", "license": "MIT" }, - "node_modules/@types/crypto-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", - "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/mysql": { "version": "2.15.27", "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.27.tgz", diff --git a/package.json b/package.json index 9ed3d18..064f055 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ "@tanstack/react-query-devtools": "^5.71.0", "@types/nodemailer": "^6.4.17", "axios": "^1.8.4", - "crypto-js": "^4.2.0", "env-cmd": "^10.1.0", "iron-session": "^8.0.4", "lucide": "^0.503.0", @@ -40,7 +39,6 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4", - "@types/crypto-js": "^4.2.2", "@types/mysql": "^2.15.27", "@types/node": "^20", "@types/react": "^19", diff --git a/src/app/pdf/suitable/page.tsx b/src/app/pdf/suitable/page.tsx deleted file mode 100644 index cdc520a..0000000 --- a/src/app/pdf/suitable/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import SuitableDownloadPdf from '@/components/pdf/SuitableDownloadPdf' - -export default function page() { - return ( - <> - - - ) -} diff --git a/src/components/pdf/SuitableDownloadPdf.tsx b/src/components/pdf/SuitableDownloadPdf.tsx deleted file mode 100644 index c034fe9..0000000 --- a/src/components/pdf/SuitableDownloadPdf.tsx +++ /dev/null @@ -1,132 +0,0 @@ -'use client' - -import { useEffect, useRef, useState } from 'react' -import generatePDF, { Margin, Options, Resolution, usePDF } from 'react-to-pdf' -import { useSuitable } from '@/hooks/useSuitable' -import { useSuitableStore } from '@/store/useSuitableStore' -import { SUITABLE_HEAD_CODE, type Suitable, type SuitableDetail } from '@/types/Suitable' - -export default function SuitableDownloadPdf() { - const [fileName, setFileName] = useState([]) - const [createTime, setCreateTime] = useState('') - const targetRef = useRef(null) - const { toCodeName, toSuitableDetail, selectedSuitables, isSelectedSuitablesLoading } = useSuitable() - const { selectedCategory, suitableCommCode, selectedItemsSearching, setSelectedItemsSearching } = useSuitableStore() - - const handleDownPdf = () => { - const options: Options = { - filename: `${fileName.join('_')}.pdf`, - method: 'open' as const, - resolution: Resolution.HIGH, - page: { - margin: Margin.SMALL, - format: 'A4', - orientation: 'landscape' as const, - }, - canvas: { - mimeType: 'image/png' as const, - qualityRatio: 1, - }, - overrides: { - pdf: { - compress: true, - }, - canvas: { - useCORS: true, - }, - }, - } - - generatePDF(targetRef, options) - // generatePDF(targetRef, { filename: 'page.pdf' }) - } - - const formatDateString = () => { - const now = new Date() - const year = now.getFullYear() - const month = now.getMonth() + 1 - const day = now.getDate() - const hours = now.getHours() - const minutes = now.getMinutes() - - return `${year}年${month}月${day}日 ${hours}:${minutes.toString().padStart(2, '0')}` - } - - useEffect(() => { - setCreateTime(formatDateString()) - setFileName([ - `(${suitableCommCode.get(SUITABLE_HEAD_CODE.ROOF_MATL_GRP_CD)?.find((category) => category.code === selectedCategory)?.codeJp})`, - '屋根材適合表', - ]) - if (!selectedItemsSearching) { - setSelectedItemsSearching(true) - } - }, []) - - if (!selectedCategory) return
잘못된 접근입니다.
- if (isSelectedSuitablesLoading) return
Loading...
- - return ( - <> - {/* */} -
-
-
-
ハンファジャパン株式会社
-
{fileName.join(' ')}
-
{createTime}
-
-
-

本適合表は参考資料としてご使用下さい。

-

屋根材製品の形状・仕様はメーカーより変更される場合が御座います。

-

又、現場環境(働き、勾配、瓦桟木条件等)により本適合表と異なる適合結果となる場合が御座います。予めご了承下さい。

-

屋根材以外の設置条件(垂木、野地板等の設置基準)も必ずご確認下さい。

-
-
{createTime}
-
-
-
- {selectedSuitables?.map((item: Suitable) => ( -
-
- {item.productName} - {toCodeName(SUITABLE_HEAD_CODE.MANU_FT_CD, item.manuFtCd)} - {toCodeName(SUITABLE_HEAD_CODE.ROOF_MT_CD, item.roofMtCd)} -
-
- - - - - - - - - - - - - - - - - {toSuitableDetail(item.detail).map((subItem: SuitableDetail) => ( - - - - - - - ))} - -
金具タイプ金具名設置可否備考
{toCodeName(SUITABLE_HEAD_CODE.ROOF_SH_CD, item.roofShCd)}{toCodeName(SUITABLE_HEAD_CODE.TRESTLE_MFPC_CD, subItem.trestleMfpcCd)}{subItem.trestleManufacturerProductName}{subItem.memo}
-
-
- ))} -
-
{createTime}
-
-
- - ) -} diff --git a/src/components/popup/SuitableDetailPopup.tsx b/src/components/popup/SuitableDetailPopup.tsx index e4635c0..461ac1b 100644 --- a/src/components/popup/SuitableDetailPopup.tsx +++ b/src/components/popup/SuitableDetailPopup.tsx @@ -5,16 +5,14 @@ import { useCallback, useEffect, useState } from 'react' import SuitableDetailPopupButton from './SuitableDetailPopupButton' import { useSuitable } from '@/hooks/useSuitable' import { usePopupController } from '@/store/popupController' -import { useSuitableStore } from '@/store/useSuitableStore' -import { useSpinnerStore } from '@/store/spinnerStore' import { SUITABLE_HEAD_CODE, type Suitable, type SuitableDetail } from '@/types/Suitable' export default function SuitableDetailPopup() { const popupController = usePopupController() - const { toCodeName, toSuitableDetail, suitableCheckIcon, suitableCheckMemo, selectedSuitables, isSelectedSuitablesLoading } = useSuitable() - const { setSelectedItemsSearching } = useSuitableStore() + const { toCodeName, toSuitableDetail, suitableCheckIcon, suitableCheckMemo, getSelectedSuitables } = useSuitable() const [openItems, setOpenItems] = useState>(new Set()) + const [selectedSuitables, setSelectedSuitables] = useState([]) /* 아이템 열기/닫기 */ const toggleItemOpen = useCallback((itemId: number) => { @@ -25,13 +23,10 @@ export default function SuitableDetailPopup() { }) }, []) - /* 데이터 로딩 상태 처리 */ useEffect(() => { - useSpinnerStore.getState().setIsShow(isSelectedSuitablesLoading) - }, [isSelectedSuitablesLoading]) - - useEffect(() => { - setSelectedItemsSearching(true) + getSelectedSuitables().then((res) => { + setSelectedSuitables(res) + }) }, []) return ( diff --git a/src/components/popup/SuitableDetailPopupButton.tsx b/src/components/popup/SuitableDetailPopupButton.tsx index 085dc92..8340f94 100644 --- a/src/components/popup/SuitableDetailPopupButton.tsx +++ b/src/components/popup/SuitableDetailPopupButton.tsx @@ -19,21 +19,23 @@ export default function SuitableDetailPopupButton() { } return ( -
-
- -
-
- -
-
- +
+
+
+ +
+
+ +
+
+ +
) diff --git a/src/components/suitable/SuitableList.tsx b/src/components/suitable/SuitableList.tsx index 918776a..a0dc5be 100644 --- a/src/components/suitable/SuitableList.tsx +++ b/src/components/suitable/SuitableList.tsx @@ -21,7 +21,7 @@ export default function SuitableList() { isLoading, suitableCheckIcon, } = useSuitable() - const { selectedItems, addSelectedItem, removeSelectedItem, setSelectedItemsSearching } = useSuitableStore() + const { selectedItems, addSelectedItem, removeSelectedItem } = useSuitableStore() const [openItems, setOpenItems] = useState>(new Set()) const observerTarget = useRef(null) @@ -49,7 +49,6 @@ export default function SuitableList() { /* 아이템 클릭 */ const handleItemClick = useCallback( (mainId: number, detailId?: number, detailIds?: Set): void => { - setSelectedItemsSearching(false) isItemSelected(mainId, detailId) ? removeSelectedItem(mainId, detailId) : addSelectedItem(mainId, detailId, detailIds) }, [isItemSelected, addSelectedItem, removeSelectedItem], diff --git a/src/components/suitable/SuitableSearch.tsx b/src/components/suitable/SuitableSearch.tsx index ccc6aed..7a62fe2 100644 --- a/src/components/suitable/SuitableSearch.tsx +++ b/src/components/suitable/SuitableSearch.tsx @@ -7,11 +7,12 @@ import type { CommCode } from '@/types/CommCode' import { SUITABLE_HEAD_CODE } from '@/types/Suitable' export default function SuitableSearch() { - const [searchValue, setSearchValue] = useState('') + const [searchValue, setSearchValue] = useState('') const { getSuitableCommCode, clearSuitableStore } = useSuitable() - const { suitableCommCode, selectedCategory, setSelectedCategory, setSearchKeyword } = useSuitableStore() + const { suitableCommCode, searchCategory, setSearchCategory, setSearchKeyword } = useSuitableStore() + /* 키워드 입력 글자 제한 */ const handleInputChange = (value: string) => { if (Array.from(value).length > 30) { alert('検索ワードは最大30文字まで入力できます。') @@ -21,6 +22,7 @@ export default function SuitableSearch() { setSearchValue(value) } + /* 키워드 검색 */ const handleInputSearch = async () => { if (!searchValue.trim()) { alert('屋根材の製品名を入力してください。') @@ -29,6 +31,7 @@ export default function SuitableSearch() { setSearchKeyword(searchValue) } + /* 키워드 초기화 */ const handleInputClear = () => { setSearchValue('') clearSuitableStore({ items: true, keyword: true }) @@ -42,7 +45,7 @@ export default function SuitableSearch() { return ( <>
- setSearchCategory(e.target.value)}> {suitableCommCode.get(SUITABLE_HEAD_CODE.ROOF_MATL_GRP_CD)?.map((category: CommCode, index: number) => (