From 908fd1035cd79d5c5997e806e3f6eb04b9bffc4e Mon Sep 17 00:00:00 2001 From: zenn Date: Tue, 19 May 2026 18:50:37 +0900 Subject: [PATCH] Fix mobile search and update resale prices --- db/nsw.resale.db.js | 14 ++--- index.html | 57 ++++++++++++++++-- script/nsw.js | 143 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 187 insertions(+), 27 deletions(-) diff --git a/db/nsw.resale.db.js b/db/nsw.resale.db.js index 890c688..2ddeeba 100644 --- a/db/nsw.resale.db.js +++ b/db/nsw.resale.db.js @@ -2416,7 +2416,7 @@ export const NSW_RESALE_DB = { "price": 1480, "sale": { "currency": "KRW", - "suggestedPrice": 12000, + "suggestedPrice": 30000, "priceRange": { "min": 10000, "max": 14000 @@ -2426,7 +2426,7 @@ export const NSW_RESALE_DB = { "confidence": "low", "memo": "한국 중고가 우선, 국내 시세가 약한/없는 일본판·희소 타이틀은 일본 중고가를 원화 환산한 대략 판매가. 상태/구성품/특전/케이스 상태에 따라 조정 필요.", "checkedAt": "2026-05-19", - "priceVerified": false + "priceVerified": true }, "itemCondition": "-", "status": "available" @@ -2606,7 +2606,7 @@ export const NSW_RESALE_DB = { "price": 6578, "sale": { "currency": "KRW", - "suggestedPrice": 28000, + "suggestedPrice": 40000, "priceRange": { "min": 24000, "max": 32000 @@ -2616,7 +2616,7 @@ export const NSW_RESALE_DB = { "confidence": "low", "memo": "한국 중고가 우선, 국내 시세가 약한/없는 일본판·희소 타이틀은 일본 중고가를 원화 환산한 대략 판매가. 상태/구성품/특전/케이스 상태에 따라 조정 필요.", "checkedAt": "2026-05-19", - "priceVerified": false + "priceVerified": true }, "itemCondition": "-", "status": "available" @@ -5456,7 +5456,7 @@ export const NSW_RESALE_DB = { "price": 2480, "sale": { "currency": "KRW", - "suggestedPrice": 12000, + "suggestedPrice": 25000, "priceRange": { "min": 10000, "max": 14000 @@ -6710,7 +6710,7 @@ export const NSW_RESALE_DB = { "price": 9172, "sale": { "currency": "KRW", - "suggestedPrice": 41000, + "suggestedPrice": 90000, "priceRange": { "min": 35000, "max": 47000 @@ -6720,7 +6720,7 @@ export const NSW_RESALE_DB = { "confidence": "medium-low", "memo": "한국 중고가 우선, 국내 시세가 약한/없는 일본판·희소 타이틀은 일본 중고가를 원화 환산한 대략 판매가. 상태/구성품/특전/케이스 상태에 따라 조정 필요.", "checkedAt": "2026-05-19", - "priceVerified": false + "priceVerified": true }, "itemCondition": "-", "status": "available" diff --git a/index.html b/index.html index 8943b44..2103354 100644 --- a/index.html +++ b/index.html @@ -15,6 +15,46 @@
+
+ +
+ + 게임명 + + + +
+
+
@@ -78,7 +118,7 @@
-
+
- + diff --git a/script/nsw.js b/script/nsw.js index 9d8d372..eb22f99 100644 --- a/script/nsw.js +++ b/script/nsw.js @@ -1,5 +1,7 @@ import NSW_DB from '../db/nsw.resale.db.js'; +window.NSW_APP_VERSION = '20260519-mobile-search'; + const SHOW_SOLD_BY_DEFAULT = false; const SHOW_RECOMMENDED_PRICE_RANGE_BY_DEFAULT = false; @@ -816,7 +818,9 @@ document.addEventListener('DOMContentLoaded', () => { cero: [], }; filterState.searchText = ''; - document.getElementById('search-input').value = ''; + document.querySelectorAll('[data-search-input]').forEach(input => { + input.value = ''; + }); // 게임 목록 다시 렌더링 renderGames(); @@ -827,25 +831,136 @@ document.addEventListener('DOMContentLoaded', () => { // 필터 체크박스 이벤트 리스너 설정 function setupFilterListeners() { - const searchInput = document.getElementById('search-input'); - const searchForm = document.getElementById('searchForm'); - const resetSearch = document.getElementById('reset-search'); + const searchInputs = [ + document.getElementById('search-input'), + document.getElementById('mobile-search-input'), + ].filter(Boolean); + const searchForms = [document.getElementById('searchForm')].filter(Boolean); + const resetSearchButtons = [ + document.getElementById('reset-search'), + document.getElementById('mobile-reset-search'), + ].filter(Boolean); - searchForm.addEventListener('submit', event => { - event.preventDefault(); - filterState.searchText = searchInput.value.trim().toLowerCase(); + function updateSearchText(value) { + filterState.searchText = value.trim().toLowerCase(); + searchInputs.forEach(input => { + if (input.value !== value) input.value = value; + }); renderGames(); + } + + window.updateNswSearch = value => { + updateSearchText(value || ''); + }; + + window.clearNswSearch = () => { + updateSearchText(''); + }; + + function updateSearchFromInput(input, options = {}) { + window.setTimeout(() => { + updateSearchText(input.value); + if (options.blur) input.blur(); + }, 0); + } + + function isSearchInput(target) { + return target instanceof HTMLInputElement && target.matches('[data-search-input]'); + } + + document.addEventListener( + 'submit', + event => { + if (!event.target.querySelector?.('[data-search-input]')) return; + event.preventDefault(); + if (event.stopImmediatePropagation) event.stopImmediatePropagation(); + event.stopPropagation(); + const searchInput = event.target.querySelector('[data-search-input]'); + if (searchInput) updateSearchFromInput(searchInput, { blur: true }); + }, + true + ); + + document.addEventListener( + 'input', + event => { + if (!isSearchInput(event.target)) return; + updateSearchText(event.target.value); + }, + true + ); + + document.addEventListener( + 'change', + event => { + if (!isSearchInput(event.target)) return; + updateSearchFromInput(event.target); + }, + true + ); + + document.addEventListener( + 'focusout', + event => { + if (!isSearchInput(event.target)) return; + updateSearchFromInput(event.target); + }, + true + ); + + searchForms.forEach(form => { + form.addEventListener( + 'submit', + event => { + event.preventDefault(); + if (event.stopImmediatePropagation) event.stopImmediatePropagation(); + event.stopPropagation(); + const searchInput = form.querySelector('[data-search-input]'); + if (searchInput) updateSearchFromInput(searchInput, { blur: true }); + }, + true + ); }); - searchInput.addEventListener('input', event => { - filterState.searchText = event.target.value.trim().toLowerCase(); - renderGames(); + searchInputs.forEach(input => { + let isComposing = false; + + input.addEventListener('compositionstart', () => { + isComposing = true; + }); + + input.addEventListener('blur', event => { + updateSearchFromInput(event.target); + }); + + input.addEventListener('compositionend', event => { + isComposing = false; + updateSearchFromInput(event.target); + }); + + input.addEventListener('keydown', event => { + if (event.key !== 'Enter') return; + if (isComposing || event.isComposing || event.keyCode === 229) return; + event.preventDefault(); + updateSearchFromInput(event.target, { blur: true }); + }); + + input.addEventListener('keyup', event => { + if (isComposing || event.isComposing || event.keyCode === 229) return; + updateSearchFromInput(event.target, { blur: event.key === 'Enter' }); + }); }); - resetSearch.addEventListener('click', () => { - filterState.searchText = ''; - searchInput.value = ''; - renderGames(); + resetSearchButtons.forEach(button => { + function clearSearch(event) { + event.preventDefault(); + event.stopPropagation(); + updateSearchText(''); + } + + button.addEventListener('pointerdown', clearSearch); + button.addEventListener('touchstart', clearSearch); + button.addEventListener('click', clearSearch); }); // 언어 필터