import React, { useContext, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import ItemPicker from '../../../qsm/components/item-picker'; import { SearchResultsRootState } from '../../../search-results/store/search-results-store'; import SearchResultsConfigurationContext from '../../../search-results/search-results-configuration-context'; import { getTranslations } from '../../utils/localization-util'; import { setPackagingAccoSearchDetails } from '../../../search-results/store/search-results-slice'; import { PackageMainRoom, PortalQsmType } from '@qite/tide-client'; import { PickerItem } from '../../types'; import { first } from 'lodash'; import Spinner from '../../../search-results/components/spinner/spinner'; type AccommodationFlyInProps = { isLoading: boolean; handleConfirm: () => void; }; type PackagingAccommodationResponse = { code: string; name: string; price: number; currencyCode: string; rooms: PackageMainRoom[]; }; type GroupedAccommodation = { accommodationCode: string; accommodationName: string; regimes: PickerItem[]; }; const formatPrice = (price?: number, currencyCode?: string | null) => { if (typeof price !== 'number') return ''; const safeCurrency = currencyCode ?? 'EUR'; return new Intl.NumberFormat('nl-BE', { style: 'currency', currency: safeCurrency }).format(price); }; const AccommodationFlyIn: React.FC = ({ isLoading, handleConfirm }) => { const dispatch = useDispatch(); const context = useContext(SearchResultsConfigurationContext); const language = context?.languageCode ?? 'en-GB'; const translations = getTranslations(language); if (isLoading) { return <>{context?.customSpinner ?? }; } const { packagingAccoSearchDetails, selectedPackagingAccoResultCode } = useSelector((state: SearchResultsRootState) => state.searchResults); const selectedPackagingAccoSearchDetails = useMemo(() => { return packagingAccoSearchDetails?.find((x) => x.code === selectedPackagingAccoResultCode); }, [packagingAccoSearchDetails, selectedPackagingAccoResultCode]); const groupedRooms = useMemo(() => { if (!selectedPackagingAccoSearchDetails?.rooms) return []; return selectedPackagingAccoSearchDetails.rooms.map((room) => { const groupedMap = new Map(); room.options.forEach((option) => { const key = option.accommodationCode; if (!groupedMap.has(key)) { groupedMap.set(key, { accommodationCode: option.accommodationCode, accommodationName: option.accommodationName, regimes: [] }); } groupedMap.get(key)?.regimes.push({ id: option.guid, label: option.regimeName }); }); return Array.from(groupedMap.values()); }); }, [selectedPackagingAccoSearchDetails]); const getSelectedOptionForRoom = (roomIndex: number) => { return selectedPackagingAccoSearchDetails?.rooms?.[roomIndex]?.options?.find((option) => option.isSelected); }; const getSelectedOptionForAccommodation = (roomIndex: number, accommodationCode: string) => { return selectedPackagingAccoSearchDetails?.rooms?.[roomIndex]?.options?.find( (option) => option.accommodationCode === accommodationCode && option.isSelected ); }; const handlePick = (roomIndex: number, selectedGuid?: string) => { if (!packagingAccoSearchDetails || !selectedPackagingAccoSearchDetails) return; const updatedPackagingAccoSearchDetails = packagingAccoSearchDetails.map((product) => { if (product.code !== selectedPackagingAccoSearchDetails.code) { return product; } const updatedRooms = product.rooms.map((room, currentRoomIndex) => { if (currentRoomIndex !== roomIndex) { return room; } return { ...room, options: room.options.map((option) => ({ ...option, isSelected: option.guid === selectedGuid })) }; }); return { ...product, rooms: updatedRooms }; }); dispatch(setPackagingAccoSearchDetails(updatedPackagingAccoSearchDetails)); }; if (!selectedPackagingAccoSearchDetails) { return null; } const calculateTotalPrice = () => { const selectedOptions = selectedPackagingAccoSearchDetails.rooms.flatMap((room) => room.options.filter((option) => option.isSelected)); const totalPrice = selectedOptions.reduce((total, option) => total + (option.price || 0), 0); return formatPrice(totalPrice, selectedPackagingAccoSearchDetails.currencyCode); }; const getPriceDifference = (currentSelectedPrice: number | undefined, roomIndex: number, accommodationCode: string, regimeId?: string) => { let targetPrice = 0; const selectedOption = getSelectedOptionForAccommodation(roomIndex, accommodationCode); if (selectedOption?.price) { targetPrice = selectedOption.price; } else { const firstOption = selectedPackagingAccoSearchDetails.rooms[roomIndex].options.find((option) => option.accommodationCode === accommodationCode); targetPrice = firstOption?.price || 0; } if (regimeId) { const regimeOption = selectedPackagingAccoSearchDetails.rooms[roomIndex].options.find((option) => option.guid === regimeId); targetPrice = regimeOption?.price || 0; } return targetPrice - (currentSelectedPrice || 0); }; const formatPriceDifference = (difference: number, currencyCode: string) => { if (difference === 0) { return null; } const formattedAbsoluteValue = formatPrice(Math.abs(difference), currencyCode); return `${difference > 0 ? '+' : '-'} ${formattedAbsoluteValue}`; }; const getPriceDifferenceClassName = (difference: number) => { if (difference < 0) { return 'flyin__acco__price flyin__acco__price--decrease'; } if (difference > 0) { return 'flyin__acco__price flyin__acco__price--increase'; } return 'flyin__acco__price'; }; const regimeFormatter = (roomIndex: number, accommodation: GroupedAccommodation, regimeId: string, label: string) => { const roomOption = getSelectedOptionForRoom(roomIndex); const difference = getPriceDifference(roomOption?.price, roomIndex, accommodation.accommodationCode, regimeId); return `${label} ${difference !== 0 ? `(${formatPriceDifference(difference, selectedPackagingAccoSearchDetails.currencyCode)})` : ''}`; }; return ( <>
{groupedRooms.map((roomAccommodations, roomIndex) => { const selectedRoomOption = getSelectedOptionForRoom(roomIndex); return (

Room {roomIndex + 1}

{roomAccommodations.map((accommodation) => { const selectedOption = getSelectedOptionForAccommodation(roomIndex, accommodation.accommodationCode); const priceDifference = getPriceDifference(selectedRoomOption?.price, roomIndex, accommodation.accommodationCode); return (

{accommodation.accommodationName}

handlePick(roomIndex, selectedGuid)} valueFormatter={(id, label) => regimeFormatter(roomIndex, accommodation, id, label)} />
{formatPriceDifference(priceDifference, selectedPackagingAccoSearchDetails.currencyCode)}
); })}
); })}
{translations.SHARED.TOTAL_PRICE}: {calculateTotalPrice()}
// Slicing with image and usps, not available in the current API response. // <> //
//
//
//
//
// river //
// {translations?.SHARED.TOTAL_PRICE} // +1.764,00 //
//
//
//
//

Deluxe Balcony Room

//
//
// // Sea sight //
//
// // Free wifi //
//
// // Breakfast included //
//
// // Air conditioning //
//
// // Private bathroom //
//
//
//
//
// setSelectedTravelClass(item)} // /> // //
//
//
//
// river //
// {translations?.SHARED.TOTAL_PRICE} // +1.764,00 //
//
//
//
//

Standard Room

//
//
// // Garden view //
//
// // Free wifi //
//
// // Double bed //
//
//
//
//
// // //
//
//
//
// river //
// {translations?.SHARED.TOTAL_PRICE} // +1.764,00 //
//
//
//
//

Suite

//
//
// // Sea sight //
//
// // Free wifi //
//
// // Breakfast included //
//
// // Jacuzzi //
//
// // Private terrace //
//
//
//
//
// // //
//
//
//
// {/* {isLoading && ( // // )} */} //
//
//
{translations.SHARED.TOTAL_PRICE}: €
//
// //
//
// ); }; export default AccommodationFlyIn;