Untitled
unknown
plain_text
a year ago
28 kB
9
Indexable
I have this full code. Why on mobile version the modal is not open (that have "HotelRoomMobileCard" component) and I get this error on my application?
TypeError: Cannot read properties of null (reading 'scrollIntoView')
And here's the full code:
import { Button, Stars, Tooltip, Typography } from '@cvccorp-components/core';
import CustomTooltip from '@cvccorp-components/flight-components/components/Common/CustomTooltip';
import Air from '@cvccorp-components/icons/dist/Air';
import DropLeft from '@cvccorp-components/icons/dist/DropLeft';
import DropRight from '@cvccorp-components/icons/dist/DropRight';
import { useMediaQuery } from '@material-ui/core';
import Grid from '@material-ui/core/Grid';
import Skeleton from '@material-ui/lab/Skeleton';
import clsx from 'clsx';
import React, { useEffect, useState } from 'react';
import Slider from 'react-slick';
import 'slick-carousel/slick/slick-theme.css';
import 'slick-carousel/slick/slick.css';
import Cookies from 'universal-cookie';
import { useStyles } from './styles';
import { useSearch } from '../../context/Search/provider';
import { ICharter, IHotel, IRoom } from '../../models';
import { formatNumber, formatPrice } from '../../utils';
import { getAmenitiesIcons } from '../../utils/getAmenitiesIcons';
import { getNoImage, imageResize } from '../../utils/getImage';
import Badge from '../Badge';
import { HotelRoomCard } from '../HotelRoomCard';
import { HotelRoomFullCard } from '../HotelRoomFullCard';
import { HotelRoomMobileCard } from '../HotelRoomMobileCard';
import { useMaps } from '../Maps/context';
import dangerIcon from '../../../assets/img/dangerRegular.svg';
import dangerRiskIcon from '../../../assets/img/dangerRisk.svg';
import { useSeller } from '../../context/Seller/provider';
import { IException } from '../../models/Error';
import PackagesService from '../../services/PackagesService';
import { dataLayerCharter, setDL } from '../../utils/dataLayer';
import { detailExclusivePackageDataLayer } from '../../utils/detailExclusivePackageDataLayer';
import { limitString } from '../../utils/limitString';
import { ModalConfirm } from '../ModalConfirm';
import { ModalItineraryDayByDay } from '../ModalItineraryDayByDay';
import { ModalListRoom } from '../ModalListRoom/ModalListVoos';
import { PackagePromotion } from '../PackagePromotion';
import { PromotionTag } from '../PromotionTag';
import { HotelSlider } from '../Summary/HotelSlider';
export interface IHotelCardProps {
charter: ICharter;
changePackAlert: boolean;
onSelect: (charter: ICharter) => void;
isSelected?: boolean;
className?: string;
}
export interface DCR {
confirmed: Number;
reserved: Number;
available: Number;
}
export const HotelCard: React.FC<IHotelCardProps> = ({ charter, isSelected, onSelect, className, changePackAlert }) => {
const {
showAlterListType,
setShowAlterList,
showRoomsSelectedHotel,
setShowRoomsSelectedHotel,
setShowHotelDetail,
charterSelected,
setHotelDetailData,
selectedRate,
isVendor
} = useSearch();
const classes = useStyles({});
const [showRooms, setShowRooms] = useState(showAlterListType === 'Room');
const { showMap, setInitialZoom } = useMaps();
const [showConfirmChange, setShowConfirmChange] = useState<boolean>(false);
const [currentHotelIndex, setCurrentHotelIndex] = useState(0);
const { assistedSaleMessage } = useSeller();
const [showModal, setShowModal] = useState(false);
useEffect(() => {
cookies.remove('PackageToken', { path: '/' });
}, []);
const onSelectHotel = () => {
clickSelectHotelDL();
if (changePackAlert) {
setShowConfirmChange(true);
} else {
handleSelectHotel();
}
};
const onConfirmChange = () => {
handleSelectHotel();
setShowConfirmChange(false);
};
const onCloseConfirmChange = () => {
setShowConfirmChange(false);
};
const [getDCRHotels, setDCRHotels] = useState({} as DCR);
const [styleTooltip, setStyleTooltip] = useState(false);
const cookies = new Cookies();
const charterHotelSelected = () => {
let hotel: IHotel = null;
if (isSelected) {
hotel = charterSelected?.hotels?.[currentHotelIndex];
} else {
hotel = charter.hotels[currentHotelIndex];
}
const room = hotel?.rooms?.find((item: IRoom) => item?.selected === true);
if (!room && isSelected && hotel?.rooms?.length > 0) {
hotel.rooms[0].selected = true;
}
return hotel;
};
const getHasMultipleHotels = () => {
if (isSelected) {
return charterSelected?.hotels?.length > 1;
}
return charter.hotels.length > 1;
};
const charterTitleSelected = () => {
if (isSelected) {
return charterSelected?.title && charterSelected?.title;
}
return charter?.title && charter?.title;
};
const selectedRoom = () => {
let room = charterHotelSelected()?.rooms?.find((item: IRoom) => item?.selected === true);
if (!room && charterHotelSelected()) {
room = charterHotelSelected().rooms[0];
}
return room;
};
const showTaxes = () => {
let pWithTax = 0;
let pWithoutTax = 0;
const rate = selectedRoom()?.rates?.[0];
if (rate?.promotionItem?.promotion !== undefined && rate?.promotionItem?.promotion !== null) {
const { priceWithTax, priceWithoutTax } = rate?.promotionItem.promotion;
pWithTax = priceWithTax;
pWithoutTax = priceWithoutTax;
} else {
const { priceWithTax, priceWithoutTax } = rate;
pWithTax = priceWithTax || 0;
pWithoutTax = priceWithoutTax || 0;
}
return formatPrice(pWithTax - pWithoutTax);
};
const showTotal = () => {
const rate = selectedRoom().rates[0];
if (rate?.promotionItem?.promotion !== undefined && rate?.promotionItem?.promotion !== null) {
return rate?.promotionItem.promotion.priceWithTax;
}
return rate?.priceWithTax;
};
const handleSelectHotel = () => {
charter.hotels[0].rooms.forEach((_room: IRoom, index: number) => {
_room.selected = index === 0;
});
onSelect(charter);
};
const handleChangeRoomClick = () => {
if (showRooms && showRoomsSelectedHotel && showAlterListType === 'Room') {
window.location.hash = '#freteRecommend';
setShowAlterList('None');
}
setShowRoomsSelectedHotel(!showRoomsSelectedHotel);
setShowRooms(!showRooms);
};
const handleSelectRoom = (room: IRoom, indexRoom: number) => {
const temp = charter;
temp.hotels[0].rooms.forEach((_room: IRoom, index: number) => {
_room.selected = _room?.name === room?.name && index === indexRoom;
});
onSelect(temp);
setShowRooms(false);
setShowRoomsSelectedHotel(false);
dataLayerCharter('click-pacote-exclusivo', charterSelected);
};
const NextArrow = (props) => {
const handleClick = (e) => {
if (props.onClick) props.onClick(e);
e.stopPropagation();
};
return (
<button
type="button"
className={clsx(classes.arrows, classes.arrowRight)}
onClick={(e) => {
handleClick(e);
}}
>
<DropRight size="medium" />
</button>
);
};
const PrevArrow = (props) => {
const handleClick = (e) => {
if (props.onClick) props.onClick(e);
e.stopPropagation();
};
return (
<button
type="button"
className={clsx(classes.arrows, classes.arrowLeft)}
onClick={(e) => {
handleClick(e);
}}
>
<DropLeft size="medium" />
</button>
);
};
const showMaps = () => {
clickDetailsDL('Veja no mapa');
setInitialZoom(18);
showMap(charterHotelSelected());
};
const changeStyleTooltip = () => {
setStyleTooltip(true);
checkCookiesDcr();
};
const checkCookiesDcr = () => {
if (cookies.get('PackageToken')) {
const cookieDCRTokenObject = cookies.get('PackageToken');
const cookieDCRSplit = cookieDCRTokenObject.split('|');
const cookieDCRObjectParsed = JSON.parse(cookieDCRSplit[1]);
const cookieDCRToken = cookieDCRSplit[0];
const charterPackageToken = charter.packageToken;
return cookieDCRToken === charterPackageToken ? setDCRHotels(cookieDCRObjectParsed) : loadDCRHotel();
}
loadDCRHotel();
};
const loadDCRHotel = async () => {
try {
setDCRHotels(null);
const packageToken = charter.packageToken;
const { data: getDCR, config } = await PackagesService.getDCR(packageToken);
const getDCRHotels0 = getDCR.dcr.hotels[0];
cookies.set('PackageToken', ${packageToken}|${JSON.stringify(getDCRHotels0)}, { path: '/', maxAge: 120 });
const otherParams = {
duration: config.meta.durationTime,
durationUnit: config.meta.unitTime,
frendlyMessage: 'Hotel DCR'
};
assistedSaleMessage('SUCCESS', 6, 'DCR', null, otherParams);
return setDCRHotels(getDCRHotels0);
} catch (error) {
const err: IException = error;
const otherParams = {
frendlyMessage: 'Erro ao carregar hotel DCR',
duration: err?.config?.meta?.durationTime || 0,
durationUnit: err?.config?.meta?.unitTime || 'milisseconds'
};
assistedSaleMessage('ERROR', 4, 'DCR', err, otherParams);
}
};
const RenderValue = () => {
const existsPromo = selectedRoom()?.rates[0].promotionItem?.promotion !== null && selectedRoom()?.rates[0].promotionItem?.promotion !== undefined;
return (
<Grid container justify={isMobile ? 'space-between' : 'center'} alignItems="center" xs={12} className={classes.totalValues}>
<Grid container justify={isMobile ? 'space-between' : 'center'} alignItems="center" item xs={12}>
<span className={clsx(classes.fontGrayRegular2, classes.fontSize14)}>{Total do ${isVendor ? 'pacote':'combo CVC'}}</span>
</Grid>
{existsPromo ? (
<PackagePromotion value={selectedRoom()?.rates[0]?.priceWithTax} promotion={showTotal()} />
) : (
<Grid container justify={isMobile ? 'flex-end' : 'center'} alignItems="baseline" xs={12} wrap="nowrap" className={classes.value}>
<div className={clsx(classes.toInfo)}>
<div className={clsx(classes.fontBlackBold, classes.fontSize14)}>R$</div>
</div>
<span className={clsx(classes.fontBlackBold, classes.fontSize26)}>{formatNumber(showTotal())}</span>
</Grid>
)}
</Grid>
);
};
const onMouseOut = () => {
setStyleTooltip(false);
};
const clickDetailsDL = (label) => {
const dlObject = {
event: 'pacote_engajamento',
category: 'pacote_exclusivo_detalhe_conteudo_outro-hotel',
action: 'click',
label
};
setDL(dlObject);
};
const clickDetailExclusivePackage = () => {
detailExclusivePackageDataLayer();
};
const clickSelectHotelDL = () => {
const dlObject = {
event: 'pacote_engajamento',
category: 'pacote_exclusivo_novo_hotel',
action: 'click',
label: 'Selecionar Hotel'
};
setDL(dlObject);
dataLayerCharter('click-pacote-exclusivo', charterSelected);
};
const getDiff = () => {
const [currentRoomRate] = selectedRoom().rates;
if (currentRoomRate?.promotionItem?.promotion) {
return (
currentRoomRate?.promotionItem?.promotion?.priceWithTax - (selectedRate?.promotionItem?.promotion?.priceWithTax || selectedRate.priceWithTax)
);
}
return currentRoomRate?.priceWithTax - (selectedRate?.promotionItem?.promotion?.priceWithTax || selectedRate.priceWithTax);
};
const isTablet = useMediaQuery('(max-width: 1024px) and (min-width:768px)');
const isMobile = useMediaQuery('(max-width: 767px) and (min-width:1px)');
let isRisk = false;
if (isVendor) isRisk = charter?.hotels?.[0]?.risk && charter?.hotels?.[0]?.risk === 'HIGH';
const isPromotion =
(selectedRoom()?.rates && selectedRoom()?.rates.length > 0 && selectedRoom().rates[0].promotionItem?.promotion) ||
(selectedRoom()?.rates && selectedRoom()?.rates.length > 0 && selectedRoom().rates[0].promotionItem?.hasCombo);
const roomImg = charterHotelSelected()?.links && charterHotelSelected()?.links?.images && charterHotelSelected()?.links?.images?.[0];
const getTooltip = () => {
const typography = (
<Typography type="body1regular" className={classes.baggageTooltipText}>
{charterHotelSelected()?.name}
{' - '}
{charterTitleSelected()}
</Typography>
);
return (
<CustomTooltip title={typography} placement="top">
<div>
{charterHotelSelected()?.name}
{' - '}
{charterHotelSelected()?.name.length > 30 ? limitString(charterTitleSelected(), 55) : limitString(charterTitleSelected(), 70)}
</div>
</CustomTooltip>
);
};
const { location } = charter?.destination;
return (
<Grid
container
xs={12}
className={clsx(className, classes.rootContainer, {
[classes.multiHotelsWrapper]: getHasMultipleHotels()
})}
>
{getHasMultipleHotels() && (
<div className={classes.multiHotelsContainer}>
<span>
Pacote para {location?.city} - {location?.state} - {location?.country}
</span>
<HotelSlider hotels={charter.hotels} activeHotelIndex={currentHotelIndex} onChangeHotelIndex={(index) => setCurrentHotelIndex(index)} />
</div>
)}
<Grid
className={clsx(classes.root, !charter.airProtection ? classes.rootHotel : classes.rootNoHotel, {
[classes.dangerContainer]: isRisk
})}
container
justify="space-between"
xs={12}
>
{charter.airProtection && (
<Grid className={classes.colNoHotel} item container alignItems="center">
<Grid item className={classes.colNoHotelIcon}>
<Air className={classes.colNoHotelIconAir} />
</Grid>
<Grid item container xs={10} direction="column">
<Typography type="headline3" className={classes.colNoHotelTitle}>
Somente passagem aérea
</Typography>
<Typography type="body1regular" className={classes.colNoHotelInfo}>
Selecione esta opção caso queira apenas o voo, sem hotel incluso.
</Typography>
</Grid>
</Grid>
)}
{!charter.airProtection && (
<Grid className={classes.colImage} item>
<Slider infinite={true} speed={500} slidesToShow={1} touchThreshold={100} nextArrow={<NextArrow />} prevArrow={<PrevArrow />}>
{charterHotelSelected().links &&
charterHotelSelected().links.images &&
charterHotelSelected().links.images.map((img, index) => (
<div key={index} className={classes.carousel}>
<img
// src={${getBaseImage('h_314,w_314')}${img.href}}
src={imageResize(img.href, '314', '314')}
className={classes.imgCarousel}
onError={({ currentTarget }) => {
currentTarget.onerror = null;
currentTarget.src = getNoImage('h_314,w_314');
}}
alt="Imagem"
/>
</div>
))}
{(!charterHotelSelected().links || !charterHotelSelected().links.images || !charterHotelSelected().links.images.length) && (
<div className={classes.carousel}>
<img src={getNoImage('h_314,w_314')} className={classes.imgCarousel} alt="Imagem" />
</div>
)}
</Slider>
</Grid>
)}
{!charter.airProtection && (
<Grid className={classes.colContent} item container>
<Grid container justify="space-between">
<Grid item container>
<Grid item xs={12}>
<Typography type="headline6">{getTooltip()}</Typography>
</Grid>
<Grid item xs={12} className={clsx(classes.addressBlock)}>
<span className={clsx(classes.fontGrayRegular, classes.fontSize12)}>
{limitString(charterHotelSelected()?.location.address, 20)}
<span className={classes.pipeMap}>|</span>
</span>
<a className={classes.link1} onClick={() => showMaps()}>
Veja no mapa
</a>
</Grid>
<Grid item container alignItems="center" xs={12} className={clsx(classes.amenitiesBlock)}>
<Grid item className={clsx(classes.marginRight16)}>
<Stars stars={charterHotelSelected().award} size="small" />
{charterHotelSelected()
.amenities?.slice(0, 5)
.map((a, i) => getAmenitiesIcons(a.code, a.name, 'small', classes.iconButtonStyle))}
</Grid>
</Grid>
<Grid item container xs={12} className={clsx(classes.linksBlock)}>
<Grid item>
<a
className={clsx(classes.link1, classes.marginRight16)}
onClick={() => {
clickDetailsDL('Detalhes do hotel');
clickDetailExclusivePackage();
setHotelDetailData(charterHotelSelected());
setShowHotelDetail(true);
}}
>
Detalhes
</a>
<a
className={clsx(classes.link1, classes.marginRight16)}
onClick={() => {
clickDetailsDL('Roteiro');
setShowModal(true);
}}
>
Roteiro
</a>
<ModalItineraryDayByDay charter={charter} isOpen={showModal} onClose={() => setShowModal(false)} baseClasses={classes} />
<Tooltip
label={
getDCRHotels ? (
<Grid>
<Grid className={classes.regNeutralSize3}>
<span>Disponíveis</span>
<span className={classes.marginLeftQuant}>{getDCRHotels.available}</span>
<br />
</Grid>
<Grid className={classes.regNeutralSize3}>
<span>Confirmados</span>
<span className={classes.marginConfQuant}>{getDCRHotels.confirmed}</span>
<br />
</Grid>
<Grid className={classes.regNeutralSize3}>
<span>Reservados</span>
<span className={classes.marginLeftQuant}>{getDCRHotels.reserved}</span>
<br />
</Grid>
</Grid>
) : (
<div>
<Skeleton className={classes.skeletonTooltip} variant="text" width="100%" height={23} />
<Skeleton className={classes.skeletonTooltip} variant="text" width="100%" height={23} />
<Skeleton className={classes.skeletonTooltip} variant="text" width="100%" height={23} />
</div>
)
}
className={styleTooltip ? classes.tooltipisPreferentialOpen : classes.tooltipisPreferential}
>
{isVendor && (
<a
onClick={() => {
clickDetailsDL('Disponibilidade');
changeStyleTooltip();
}}
onMouseOut={() => {
onMouseOut();
}}
className={clsx(classes.link1, classes.marginRight16)}
>
Disponibilidade
</a>
)}
</Tooltip>
</Grid>
{/* <Grid item>
<a className={classes.link1} onClick={() => {}}>Roteiro de atividades</a>
</Grid> */}
</Grid>
</Grid>
<Grid item container className={classes.roomBox}>
<HotelRoomCard
qtyRooms={charterHotelSelected().rooms.length}
room={selectedRoom()}
showChangeRoom={true}
alteringRoom={showRooms}
onChangeRoomClick={handleChangeRoomClick}
/>
</Grid>
</Grid>
</Grid>
)}
<Grid className={classes.colPrice} item container>
<Grid container direction="column" justify="space-between">
<Grid item container>
{isRisk && (
<Grid container justify="flex-end" alignItems="center" xs={12} className={classes.promotionTag}>
<Badge type="danger" text="Malha prioritária" />{' '}
</Grid>
)}
{isPromotion && (
<Grid container justify="flex-end" alignItems="center" xs={12} className={classes.promotionTag}>
<PromotionTag promotionItem={selectedRoom().rates[0].promotionItem} />
</Grid>
)}
<Grid container justify="space-between" alignItems="center" xs={12}>
<span className={clsx(classes.fontBlackBold, classes.fontSize11, classes.marginBottom5px)}>{Valor do ${isVendor ?'pacote':'combo CVC'} com este hotel: }</span>
</Grid>
<Grid container justify="space-between" alignItems="center" xs={12}>
<span className={clsx(classes.fontGrayRegular, classes.fontSize12)}>Valor por viajante: </span>
<span className={clsx(classes.fontBlackBold, classes.fontSize12)}>
{formatPrice(selectedRoom()?.rates[0]?.pricePerPaxWithoutTax)}
</span>
</Grid>
<Grid container justify="space-between" alignItems="center" xs={12}>
<span className={clsx(classes.fontGrayRegular, classes.fontSize12)}>Taxas</span>
<span className={clsx(classes.fontBlackBold, classes.fontSize12)}>{showTaxes()}</span>
</Grid>
{!!getDiff() && (
<Grid container justify="space-between" alignItems="center" xs={12}>
<span className={clsx(classes.fontGrayRegular, classes.fontSize12)}>Diferença</span>
<span className={clsx(classes.fontOrangeBold, classes.fontSize12)}>{formatPrice(getDiff())}</span>
</Grid>
)}
</Grid>
<Grid item container>
<RenderValue />
<Grid container justify="center" alignItems="flex-end" xs={12}>
<Button
disabled={isSelected}
onClick={onSelectHotel}
color="secondary"
className={classes.mobileBtn}
label={
isSelected
? !charter.airProtection
? 'Hotel selecionado'
: 'Selecionado'
: !charter.airProtection
? 'Selecionar hotel'
: 'Selecionar'
}
variant="contained"
size="small"
/>
</Grid>
<span className={classes.installments}>Taxas Inclusas | <strong>Em até 12x</strong></span>
</Grid>
</Grid>
</Grid>
</Grid>
{/* IS TABLET AQUI */}
{isTablet && !isMobile && (
<ModalListRoom
openModal={showRooms}
onClose={() => {
setShowRooms(false);
setShowAlterList('None');
}}
isRoom={true}
>
<Grid container item xs={12} className={classes.roomsContainer2}>
{charterHotelSelected().rooms.map((room, index) => (
<HotelRoomFullCard
key={index}
room={room}
onSelect={(room) => {
handleSelectRoom(room, index);
}}
className={classes.cardRoom}
isSelected={room.selected}
selectedRate={selectedRate}
/>
))}
</Grid>
</ModalListRoom>
)}
{showRooms && !isTablet && !isMobile && (
<Grid container item xs={12} className={classes.roomsContainer}>
{charterHotelSelected().rooms.map((room, index) => (
<HotelRoomFullCard
key={index}
room={room}
onSelect={(room) => {
handleSelectRoom(room, index);
}}
className={classes.cardRoom}
isSelected={room.selected}
selectedRate={selectedRate}
/>
))}
</Grid>
)}
{isMobile && (
<ModalListRoom
openModal={showRooms}
onClose={() => {
setShowRooms(false);
setShowAlterList('None');
}}
isRoom={true}
>
<Grid container item xs={12} className={classes.roomsContainer3}>
{charterHotelSelected().rooms.map((room, index) => (
<HotelRoomMobileCard
key={index}
room={room}
onSelect={(room) => {
handleSelectRoom(room, index);
}}
img={roomImg}
className={classes.cardRoom}
isSelected={room.selected}
selectedRate={selectedRate}
/>
))}
</Grid>
</ModalListRoom>
)}
{changePackAlert && !isRisk && (
<>
<Grid container item xs={12} className={classes.changeAlert}>
<img src={dangerIcon} />
{charter.airProtection ? (
<Typography type="headline7">A seleção deste item impactará automaticamente na alteração do voo selecionado.</Typography>
) : (
<Typography type="headline7">
Este hotel não está relacionado ao voo selecionado. Ao selecioná-lo, o voo será automaticamente alterado.
</Typography>
)}
</Grid>
</>
)}
{changePackAlert && isRisk && (
<>
<Grid container item xs={12} className={classes.highRiskAlert}>
<img src={dangerRiskIcon} />
<Typography type="headline7"> Malha Prioritária - Este hotel não está relacionado ao voo selecionado </Typography>
</Grid>
</>
)}
{!changePackAlert && isRisk && (
<>
<Grid container item xs={12} className={classes.highRiskAlert}>
<img src={dangerRiskIcon} />
<Typography type="headline7"> Malha Prioritária </Typography>
</Grid>
</>
)}
{changePackAlert && (
<>
{showConfirmChange && !charter.airProtection ? (
<ModalConfirm alert="hotel" open={showConfirmChange} confirmFunction={onConfirmChange} closeFunction={onCloseConfirmChange} />
) : (
<ModalConfirm alert="airProtection" open={showConfirmChange} confirmFunction={onConfirmChange} closeFunction={onCloseConfirmChange} />
)}
</>
)}
</Grid>
);
};Editor is loading...
Leave a Comment