Files
shoptime/com.twin.app.shoptime/HOTEL_UI_VISUAL_GUIDE.md
optrader ec5829eebe [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 서비스 레이어 개선
  • 개발 문서 및 가이드 개선
2025-11-22 21:21:32 +09:00

14 KiB
Raw Blame History

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 (조건부)

🎯 선택 인덱스 상태 관리

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 상태 구조 (호텔 데이터)

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 표시용

텍스트 보호

// 호텔명 2줄 말줄임
.title {
  .elip(@clamp:2);  // max 2 lines
}

// 방 타입 3줄 말줄임
.roomType {
  .elip(@clamp:3);  // max 3 lines
}

⚠️ 주의사항

  1. QR 코드 이슈: 호텔 QR 코드가 서버에서 다르게 내려와 에러 발생

    // TODO: 해결되면 주석제거
    <TQRCode
      text={hotelInfos[selectedIndex]?.qrcodeUrl}
      width="160"
      height="160"
    />
    
  2. 편의시설 필터링:

    • 최대 10개로 제한
    • 같은 카테고리명 중복 제거
  3. 평점 없음 처리:

    if (rating !== undefined) {
      // 평점 등급 처리
    }
    
  4. 이미지 없음 처리:

    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)

// 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 데이터