[251122] fix: DetailPanel Theme,Hotels - 1

🕐 커밋 시간: 2025. 11. 22. 21:21:31

📊 변경 통계:
  • 총 파일: 10개
  • 추가: +76줄
  • 삭제: -19줄

📁 추가된 파일:
  + com.twin.app.shoptime/HOTEL_UI_HANDLING_REPORT.md
  + com.twin.app.shoptime/HOTEL_UI_VISUAL_GUIDE.md
  + com.twin.app.shoptime/THEME_PRODUCT_UI_ANALYSIS.md
  + com.twin.app.shoptime/THEME_PRODUCT_VISUAL_GUIDE.md
  + com.twin.app.shoptime/THEME_VS_HOTEL_COMPARISON.md
  + com.twin.app.shoptime/docs/todo/251122-detailpanel-diff.md

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/api/TAxios.js
  ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx
  ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx
  ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less

🔧 함수 변경 내용:
  📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript):
     Added: extractProductMeta()
    🔄 Modified: SpotlightContainerDecorator()
     Deleted: SpotlightContainerDecorator()
  📄 com.twin.app.shoptime/HOTEL_UI_HANDLING_REPORT.md (md파일):
     Added: useEffect(), dispatch(), ThemeProduct(), setLabel(), Map(), forEach(), filter(), findIndex(), setAmenitiesInfos(), setSelectedIndex()
  📄 com.twin.app.shoptime/HOTEL_UI_VISUAL_GUIDE.md (md파일):
     Added: DetailPanel(), getThemeCurationDetailInfo(), getThemeHotelDetailInfo(), getMainCategoryDetail(), THeader(), TBody(), ThemeProduct(), Container(), rating(), TButton(), YouMayLike(), MobileSendPopUp(), selectedIndex(), setSelectedIndex(), ellipsis(), amenitiesBox(), c70850(), handleSMSClick(), dispatch(), clearThemeDetail()
  📄 com.twin.app.shoptime/THEME_PRODUCT_UI_ANALYSIS.md (md파일):
     Added: getThemeCurationDetailInfo(), productData(), Container(), ShowSingleOption(), ShowUnableOption(), useState(), useEffect(), setSelectedImage(), useMemo(), dispatch(), startVideoPlayer(), productDescription(), setTimeout(), useCallback(), isProductSoldOut(), ProductOption(), setSelectedIndex()
  📄 com.twin.app.shoptime/THEME_PRODUCT_VISUAL_GUIDE.md (md파일):
     Added: ShowProduct(), Container(), optionContainer(), ShowSingleOption(), ProductOption(), ShowUnableOption(), UnableOption(), selectedIndex(), setSelectedIndex(), descriptionClick(), setTabLabel(), setDescription(), dispatch(), handleIndicatorOptions(), handleSMSClick(), handleMobileSendPopupOpen(), setImageSelectedIndex(), StarRating(), ProductTag(), SingleOption()
  📄 com.twin.app.shoptime/THEME_VS_HOTEL_COMPARISON.md (md파일):
     Added: Product(), UnableOption(), StarRating(), dispatch(), getThemeCurationDetailInfo(), getThemeHotelDetailInfo()

🔧 주요 변경 내용:
  • API 서비스 레이어 개선
  • 개발 문서 및 가이드 개선
This commit is contained in:
2025-11-22 21:21:32 +09:00
parent ce51902150
commit ec5829eebe
10 changed files with 2514 additions and 19 deletions

View File

@@ -0,0 +1,409 @@
# DetailPanel 호텔/여행상품 UI 처리 - 시각적 가이드
## 🔄 데이터 흐름 다이어그램
```
┌─────────────────────────────────────────────────────────────────┐
│ DetailPanel (Main) │
└────────────────┬────────────────────────────────────────────────┘
┌────────┴─────────┐
│ panelInfo.type │
└────────┬─────────┘
┌───────────┼───────────┐
│ │ │
"theme" "hotel" "product"
│ │ │
▼ ▼ ▼
┌─────────┐ ┌────────┐ ┌─────────┐
│ShowPrdt │ │HotelPdt│ │SinglePdt│
└────┬────┘ └────┬───┘ └────┬────┘
│ │ │
▼ ▼ ▼
Redux Actions Redux Actions Redux Actions
┌─────────────────────────────────────────┐
│ getThemeCurationDetailInfo() [THEME] │
│ getThemeHotelDetailInfo() [HOTEL] │
│ getMainCategoryDetail() [PRODUCT] │
└──────────────┬──────────────────────────┘
┌────────────────────┐
│ Redux Reducer │
│ │
│ - productData │
│ - hotelData │
│ - hotelInfos[] │
│ - themeInfos[] │
└────────────────────┘
┌────────────────────┐
│ UI Components │
│ │
│ - ThemeIndicator │
│ - HotelProduct │
│ - ShowProduct │
└────────────────────┘
```
---
## 🏨 HotelProduct UI 구조
```
┌──────────────────────────────────────────────────────────────────┐
│ HotelProduct Component │
└──────────────────┬───────────────────────────────────────────────┘
┌──────────┴──────────┐
│ │
▼ ▼
┌─────────────┐ ┌──────────────────┐
│ThemeIndicator │ │OptionContainer │
├─────────────┤ ├──────────────────┤
│ 이미지 갤러리 │ │ 호텔 정보 카드 │
│ 774×930px │ │ 1026×990px │
│ │ │ │
│ ┌─────────┐ │ │ ┌────────────┐ │
│ │ 이미지1 │ │ │ │ 로고 + 별점 │ │
│ │ │ │ │ ├────────────┤ │
│ │ ▲ ▼ │ │ │ │ 호텔명 │ │
│ │ [•••] │ │ │ │ [타입]호텔 │ │
│ │ │ │ │ ├────────────┤ │
│ │ ◀ ───► │ │ │ │ 편의시설 │ │
│ │ 이미지2 │ │ │ │ [아이콘] │ │
│ │ 이미지3 │ │ │ │ [아이콘] │ │
│ └─────────┘ │ │ ├────────────┤ │
│ │ │ │ 예약정보 │ │
└─────────────┘ │ │ N Nights │ │
│ │ M Adults │ │
│ │ Room Type │ │
│ ├────────────┤ │
│ │ From │ │
│ │ $299 ◀─────┼──┼→ QR Code
│ │ (분홍색) │ │ 160×160px
│ ├────────────┤ │
│ │[SEE MORE]btn│ │
│ └────────────┘ │
└──────────────────┘
```
---
## 📊 컴포넌트 계층도 (DetailPanel)
```
DetailPanel
├── TPanel
│ ├── THeader (제목: 호텔명/테마명)
│ └── TBody (스크롤 가능 영역)
│ └── ThemeProduct (조건부 렌더링)
│ ├── ShowProduct
│ │ ├── Container (Spotlight)
│ │ │ ├── ThemeIndicator
│ │ │ └── IndicatorOptions
│ │ └── optionContainer
│ │ ├── ShowSingleOption
│ │ └── ShowUnableOption
│ │
│ └── HotelProduct ◀── 호텔 전용
│ ├── Container (Spotlight)
│ │ ├── ThemeIndicator
│ │ └── IndicatorOptions
│ └── optionContainer
│ ├── topLayer
│ │ ├── img (로고)
│ │ └── rating (별점)
│ ├── title
│ ├── amenitiesCotainer
│ │ └── amenitiesBox[] (반복)
│ ├── bottomLayer
│ │ ├── 예약정보
│ │ ├── 가격
│ │ └── QR코드
│ └── TButton (SEE MORE)
├── YouMayLike (조건부)
└── MobileSendPopUp (조건부)
```
---
## 🎯 선택 인덱스 상태 관리
```javascript
HotelProduct
├─ selectedIndex (props)
└─ 현재 선택된 호텔의 배열 인덱스
├─ hotelInfos[selectedIndex] 호텔 데이터
├─ hotelInfos[selectedIndex].hotelNm 호텔명
├─ hotelInfos[selectedIndex].hotelDetailInfo.price 가격
└─ hotelInfos[selectedIndex].hotelDetailInfo.amenities 편의시설 ID 배열
└─ setSelectedIndex (callback)
└─ ThemeIndicator 화살표 클릭 호출
├─ UP / LEFT selectedIndex - 1
└─ DOWN / RIGHT selectedIndex + 1
```
---
## 💾 Redux 상태 구조 (호텔 데이터)
```javascript
state.home = {
// 호텔 목록 (배열)
themeCurationHotelDetailData: [
{
hotelId: "HOTEL001",
hotelNm: "Luxury Hotel",
hotelImgUrl: "http://...",
imgUrls600: ["url1", "url2", "url3"],
qrcodeUrl: "qrcode-data",
hotelDetailInfo: {
hotelAddr: "123 Main St, NYC",
hotelType: "5-star",
price: "299.99",
currencySign: "$",
revwGrd: 4.8, // 평점
nights: 2, // 숙박일 수
adultsCount: 2, // 성인 수
roomType: "Deluxe Double Room",
amenities: ["AMN001", "AMN002", "AMN005"], // 편의시설 ID
imgUrls: ["url1", "url2", "url3"]
}
},
{ /* 다음 호텔 */ }
],
// 호텔 통합 정보
hotelData: {
hotelInfo: {
curationId: "CURATION001",
curationNm: "Dubai Vacation",
patncNm: "Travel Partner",
patnrId: "PARTNER001",
patncLogoPath: "http://logo-url"
},
amenities: [
{
amntId: "AMN001",
lgAmntNm: "Free WiFi",
lgAmntImgUrl: "http://icon-wifi.png"
},
{
amntId: "AMN002",
lgAmntNm: "Swimming Pool",
lgAmntImgUrl: "http://icon-pool.png"
},
{
amntId: "AMN005",
lgAmntNm: "Spa",
lgAmntImgUrl: "http://icon-spa.png"
}
// ... 더 많은 편의시설
]
}
}
```
---
## 🎨 스타일 적용 흐름
```
HotelProduct.module.less
├─ .themeContainer
│ └─ ThemeIndicator 감싸기
│ ├─ width: 774px
│ └─ height: 930px
├─ .optionContainer
│ └─ 호텔 정보 카드
│ ├─ width: 1026px
│ ├─ height: 990px
│ ├─ padding: 30px 120px 60px 60px
│ └─ background: #f9f9f9
├─ .topLayer
│ └─ display: flex
│ ├─ justify-content: space-between
│ └─ img (로고 42×42px)
│ rating (별점 + 텍스트)
├─ .title
│ ├─ font-size: 36px
│ ├─ font-weight: bold
│ ├─ overflow: ellipsis (2줄 말줄임)
│ └─ color: #333
├─ .amenitiesCotainer
│ ├─ width: 846px
│ ├─ height: 344px
│ ├─ display: flex
│ ├─ flex-wrap: wrap
│ ├─ background: #f2f2f2
│ └─ border: 1px solid #dadada
│ │
│ └─ .amenitiesBox (반복)
│ ├─ width: 138px
│ ├─ height: 138px
│ ├─ background: white
│ ├─ border-radius: 6px
│ ├─ display: flex (column)
│ └─ img: 36×32px, p: 18px font
├─ .bottomLayer
│ ├─ display: flex
│ ├─ justify-content: space-between
│ │
│ ├─ 좌측 (예약정보 + 가격)
│ │ ├─ .today: 24px, bold, #222
│ │ ├─ .roomType: 24px, #808080
│ │ └─ .price
│ │ ├─ title: 36px, #222
│ │ └─ value: 44px, bold, #c70850 (분홍색)
│ │
│ └─ 우측 (QR코드)
│ └─ .qrcodeContainer
│ ├─ width: 192px
│ ├─ height: 192px
│ ├─ box-shadow: 0px 3px 6px rgba(0,0,0,0.1)
│ └─ border: 1px solid #dadada
└─ .tbutton
├─ size: extra
├─ background: 테마 색상
└─ margin-top: auto
```
---
## 🔄 이벤트 흐름
```
사용자 입력
├─ 화살표 키 (▲▼◄►)
│ └─ Spotlight 포커스 변경
│ └─ setSelectedIndex() 호출
│ └─ hotelInfos[newIndex] 데이터 로드
│ └─ UI 업데이트 (이미지, 가격, 편의시설)
└─ [SEE MORE] 버튼 클릭
└─ handleSMSClick()
├─ 로깅 (sendLogTotalRecommend, sendLogShopByMobile)
└─ MobileSendPopUp 오픈
└─ SMS로 호텔 정보 전송
```
---
## 📱 반응형 고려사항
### 이미지 크기
- **thumbnailUrls**: `imgUrls600[]` (600px 기준)
- **갤러리**: 774×930px 고정
- **카드**: 1026×990px 고정
- **QR코드**: 160×160px 표시용
### 텍스트 보호
```javascript
// 호텔명 2줄 말줄임
.title {
.elip(@clamp:2); // max 2 lines
}
// 방 타입 3줄 말줄임
.roomType {
.elip(@clamp:3); // max 3 lines
}
```
---
## ⚠️ 주의사항
1. **QR 코드 이슈**: 호텔 QR 코드가 서버에서 다르게 내려와 에러 발생
```javascript
// TODO: 해결되면 주석제거
<TQRCode
text={hotelInfos[selectedIndex]?.qrcodeUrl}
width="160"
height="160"
/>
```
2. **편의시설 필터링**:
- 최대 10개로 제한
- 같은 카테고리명 중복 제거
3. **평점 없음 처리**:
```javascript
if (rating !== undefined) {
// 평점 등급 처리
}
```
4. **이미지 없음 처리**:
```javascript
const imgUrls600 = hotelInfos[selectedIndex]?.imgUrls600 || [];
```
---
## 📊 상태 관리 체크리스트
- ✅ 호텔 데이터 로드 (useEffect with panelInfo.type)
- ✅ 선택 인덱스 초기화 (panelInfo?.themeHotelId 기반)
- ✅ 이미지 길이 업데이트 (이미지 스와이프 관련)
- ✅ 편의시설 정렬 (최대 10개, 중복 제거)
- ✅ 평점 등급 계산
- ✅ SMS 로깅 (shopByMobileFlag: "Y", shopTpNm: "hotel")
- ✅ 상세 정보 로깅 (logTpNo: PRODUCT.PRODUCT_DETAIL_IMAGE)
- ✅ cleanup (clearThemeDetail, clearProductDetail)
---
## 🔗 관련 액션 (Redux Actions)
```javascript
// src/actions/homeActions.js
// 호텔 데이터 조회
getThemeHotelDetailInfo({ patnrId, curationId })
→ dispatch(GET_THEME_HOTEL_DETAIL_INFO, hotelData)
// 테마 데이터 조회
getThemeCurationDetailInfo({ patnrId, curationId, bgImgNo })
→ dispatch(GET_THEME_CURATION_DETAIL_INFO, themeData)
// 상세 정보 초기화
clearThemeDetail()
→ 호텔/테마 데이터 리셋
```
---
## 📝 필드 매핑 요약
| UI 요소 | 데이터 경로 | 설명 |
|---------|-----------|------|
| 로고 | `hotelData.hotelInfo.patncLogoPath` | 파트너 로고 |
| 별점 | `hotelInfos[i].hotelDetailInfo.revwGrd` | 0~5 평점 |
| 별점 등급 | 계산됨 (2.5~3.4=Good 등) | 동적 매핑 |
| 호텔명 | `hotelInfos[i].hotelNm` | 호텔 이름 |
| 호텔 타입 | `hotelInfos[i].hotelDetailInfo.hotelType` | 5-Star, Luxury 등 |
| 이미지 | `hotelInfos[i].hotelDetailInfo.imgUrls[]` | 갤러리 이미지 |
| 주소 | `hotelInfos[i].hotelDetailInfo.hotelAddr` | 지도 위치 |
| 편의시설 | `hotelInfos[i].hotelDetailInfo.amenities[]` | ID 배열 → 매핑 |
| 숙박일 | `hotelInfos[i].hotelDetailInfo.nights` | N Nights |
| 성인 수 | `hotelInfos[i].hotelDetailInfo.adultsCount` | M Adults |
| 방 타입 | `hotelInfos[i].hotelDetailInfo.roomType` | Deluxe Double Room |
| 가격 | `hotelInfos[i].hotelDetailInfo.price` | 숫자 (문자열) |
| 통화 | `hotelInfos[i].hotelDetailInfo.currencySign` | $ / € / ¥ |
| QR 코드 | `hotelInfos[i].qrcodeUrl` | QR 데이터 |