[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:
409
com.twin.app.shoptime/HOTEL_UI_VISUAL_GUIDE.md
Normal file
409
com.twin.app.shoptime/HOTEL_UI_VISUAL_GUIDE.md
Normal 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 데이터 |
|
||||
Reference in New Issue
Block a user