@kiwicom/smart-faq
Version:
217 lines (187 loc) • 6.52 kB
JavaScript
// @flow
import * as React from 'react';
import { graphql, createFragmentContainer } from 'react-relay';
import { parsePhoneNumber } from 'libphonenumber-js';
import ValueBind from '@kiwicom/nitro/lib/components/ValueBind';
import Stack from '@kiwicom/orbit-components/lib/Stack';
import TextLink from '@kiwicom/orbit-components/lib/TextLink';
import Tooltip from '@kiwicom/orbit-components/lib/Tooltip';
import CountryFlag from '@kiwicom/orbit-components/lib/CountryFlag';
import { CODES } from '@kiwicom/orbit-components/lib/CountryFlag/consts';
import InformationCircle from '@kiwicom/orbit-components/lib/icons/InformationCircle';
import LogContext from '@kiwicom/nitro/lib/services/log/context';
import type { Context as LogContextType } from '@kiwicom/nitro/lib/services/log/context';
import addMinutes from 'date-fns/add_minutes';
import type { Phone as PhoneType } from './__generated__/Phone.graphql';
import { events } from '../const/events';
type Props = {|
data: PhoneType,
|};
const formatTime = (datetime: Date) =>
`${datetime.getUTCHours() % 12}${
datetime.getUTCMinutes() > 0 ? `:${datetime.getUTCMinutes()}` : ''
} ${datetime.getUTCHours() >= 12 ? 'pm' : 'am'}`;
const parseUTCTimeToDate = (utcString: string) => {
const hour = parseInt(utcString.split(':')[0], 10);
const minute = parseInt(utcString.split(':')[1], 10);
const now = new Date();
return new Date(
Date.UTC(now.getFullYear(), now.getMonth(), now.getDay(), hour, minute),
);
};
const convertToTimezone = addMinutes;
const convertToLocalTimezone = (datetime: Date) => {
// it's negative because the offset has to be subtracted
return convertToTimezone(datetime, -new Date().getTimezoneOffset());
};
const getTimezone = () => {
const offset = new Date().getTimezoneOffset();
const offsetHours = Math.floor(Math.abs(offset / 60));
const offsetMinutes = Math.abs(offset % 60);
const formattedOffset = `${'00'
.concat(offsetHours.toString())
.slice(-2)}:${'00'.concat(offsetMinutes.toString()).slice(-2)}`;
if (offset > 0) {
return `GMT-${formattedOffset}`;
} else if (offset === 0) {
return 'GMT';
}
return `GMT+${formattedOffset}`;
};
const formatOpenHours = (from: string, to: string): string => {
const fromDate = convertToLocalTimezone(parseUTCTimeToDate(from));
const toDate = convertToLocalTimezone(parseUTCTimeToDate(to));
return `${formatTime(fromDate)}-${formatTime(toDate)} ${getTimezone()}`;
};
const parseAvailabilityTimes = (
phoneLanguageAvailability,
hasMultipleLanguages,
language,
) => {
const { type } = phoneLanguageAvailability;
// TODO refactor to translations with variables
if (type === 'NONSTOP') {
return 'Support Available in ';
} else if (type === 'WORKING_DAYS') {
const { to, from } = phoneLanguageAvailability;
if (to && from && language) {
return `${
hasMultipleLanguages ? language : ''
} Mon - Fri ${formatOpenHours(from, to)}; `;
}
}
return '';
};
class Phone extends React.Component<Props> {
context: LogContextType;
static contextType = LogContext;
handleClickPhone = () => {
this.context.log(events.CS_PHONES_CLICKED, {});
};
render() {
const { data } = this.props;
const {
number: phoneNumber,
localeTerritory,
labels,
countryName,
supportedLanguages,
} = data;
let parsedPhoneNumber;
try {
parsedPhoneNumber = parsePhoneNumber(phoneNumber).formatInternational();
} catch (e) {
parsedPhoneNumber = phoneNumber;
}
const flagCode = localeTerritory && CODES[localeTerritory.toUpperCase()];
const hasMultipleLanguages =
supportedLanguages && supportedLanguages.length > 1;
const extraInfo = (labels && labels.join(' ')) ?? '';
const availabilityInfo = supportedLanguages
? supportedLanguages.reduce((acc, supportedLanguage) => {
const language = supportedLanguage?.language;
const languageAvailability =
supportedLanguage?.phoneLanguageAvailability ?? {};
return `${parseAvailabilityTimes(
languageAvailability,
hasMultipleLanguages,
language,
)}${acc}`;
}, 'English 24/7;') + extraInfo
: null;
// remove this nasty hardcoding of opening hours, when API is ready
// https://skypicker.slack.com/archives/CBPS7LHFD/p1561475172003700
const getTooltipContent = () => {
const frenchOpeningHours =
'Mon - Fri 8 am-8 pm, Sat - Sun 9 am-6 pm GMT+02:00;';
if (countryName === 'Canada French') {
return `French ${frenchOpeningHours} English 24/7;`;
}
if (countryName === 'France') {
return `${frenchOpeningHours} English 24/7;`;
}
if (countryName === 'Switzerland') {
return `Italian Mon - Fri 8 am-8 pm GMT+02:00; French ${frenchOpeningHours}
German Mon - Fri 9 am-5 pm GMT+02:00; English 24/7;`;
}
return availabilityInfo;
};
return (
<Stack direction="row" spacing="condensed">
{flagCode && countryName && (
<CountryFlag code={flagCode} name={countryName} />
)}
<div dir="ltr">
{parsedPhoneNumber && phoneNumber && localeTerritory && (
<div className="Phone">
<ValueBind
value={localeTerritory}
onChange={this.handleClickPhone}
>
{({ onClick }) => (
<TextLink
href={`tel:${phoneNumber.replace(/\s/g, '')}`}
onClick={onClick}
>
{parsedPhoneNumber ?? ''}
</TextLink>
)}
</ValueBind>
</div>
)}
</div>
<div dir="ltr" style={{ cursor: 'pointer' }}>
<Tooltip
content={getTooltipContent()}
preferredPosition="top"
size="medium"
>
<InformationCircle size="small" color="tertiary" />
</Tooltip>
</div>
</Stack>
);
}
}
export default createFragmentContainer(
Phone,
graphql`
fragment Phone on CustomerSupportNumber {
number
labels
countryName
localeTerritory
supportedLanguages {
language
languageCode
phoneLanguageAvailability {
type
... on CSPhoneAvailabilityWorkingDays {
from
to
}
}
}
}
`,
);