@kiwicom/smart-faq
Version:
Smart FAQ
187 lines (166 loc) • 5.58 kB
JavaScript
// @flow
import idx from 'idx';
import * as React from 'react';
import css from 'styled-jsx/css';
import { parsePhoneNumber } from 'libphonenumber-js';
import { CountryFlag } from '@kiwicom/orbit-components';
import { InformationCircle } from '@kiwicom/orbit-components/lib/icons';
import { graphql, createFragmentContainer } from 'react-relay';
import { CODES } from '@kiwicom/orbit-components/lib/CountryFlag/consts';
import addMinutes from 'date-fns/add_minutes';
import HoverHelpTooltip from '../SmartFAQ/common/Tooltip/HoverHelpTooltip';
import type { Phone as PhoneType } from './__generated__/Phone.graphql';
const styles = css`
div.containerPhoneNumber {
padding-bottom: 10px;
}
div.containerPhoneNumber :global(.Tooltip) {
bottom: 110%;
right: -100px;
}
div.containerPhoneNumber :global(.Tooltip-inner.Tooltip-inner) {
max-width: 275px;
width: 200px;
}
div.containerPhoneNumber :global(.HelpTooltip) {
vertical-align: top;
}
span.phoneNumber {
margin-left: 4px;
margin-right: 4px;
}
a {
color: #00ad98;
text-decoration: none;
font-family: 'Roboto', -apple-system, '.SFNSText-Regular', 'San Francisco',
'Segoe UI', 'Helvetica Neue', 'Lucida Grande', sans-serif;
}
`;
type Props = {|
data: PhoneType,
|};
const getLocaleTimezoneAbbreviation = (dateInput: Date): ?string => {
// extracts timezone abbreviation from stringified date using regexp
// source: https://gist.github.com/redoPop/3915761
const dateString = dateInput.toString();
let shortTimezoneName =
// Works for the majority of modern browsers
dateString.match(/\(([^)]+)\)$/) ||
// IE outputs date strings in a different format:
dateString.match(/([A-Z]+) [\d]{4}$/);
if (shortTimezoneName) {
// Old Firefox uses the long timezone name (e.g., "Central
// Daylight Time" instead of "CDT")
const matches = shortTimezoneName[1].match(/[A-Z]/g);
if (matches) {
shortTimezoneName = matches.join('');
}
}
if (shortTimezoneName) {
return shortTimezoneName.toString();
}
};
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 formatOpenHours = (from: string, to: string): string => {
const fromDate = convertToLocalTimezone(parseUTCTimeToDate(from));
const toDate = convertToLocalTimezone(parseUTCTimeToDate(to));
// fall back to long timezone name when shit hits the fan
const timezoneName =
getLocaleTimezoneAbbreviation(new Date()) ||
Intl.DateTimeFormat().resolvedOptions().timeZone ||
'';
return `${formatTime(fromDate)}-${formatTime(toDate)} ${timezoneName}`;
};
const parseAvailabilityTimes = (
phoneLanguageAvailability,
hasMultipleLanguages,
language,
) => {
const { type } = phoneLanguageAvailability;
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 '';
};
const Phone = ({ data }: Props) => {
const { number: phoneNumber, localeTerritory, supportedLanguages } = data;
const parsedPhoneNumber = parsePhoneNumber(phoneNumber).formatInternational();
const flagCode = localeTerritory && CODES[localeTerritory.toUpperCase()];
const hasMultipleLanguages =
supportedLanguages && supportedLanguages.length > 1;
const availabilityInfo =
supportedLanguages &&
supportedLanguages.reduce((acc, supportedLanguage) => {
const language = idx(supportedLanguage, _ => _.language);
const languageAvailability =
idx(supportedLanguage, _ => _.phoneLanguageAvailability) || {};
return (
`${parseAvailabilityTimes(
languageAvailability,
hasMultipleLanguages,
language,
)}` + acc
);
}, 'English 24/7;');
return (
<div data-code={localeTerritory} className="containerPhoneNumber">
{flagCode && <CountryFlag code={flagCode} />}
<span dir="ltr" className="phoneNumber">
{phoneNumber && (
<a href={`tel:${phoneNumber.replace(/\s/g, '')}`}>
{parsedPhoneNumber}
</a>
)}
</span>
<span style={{ cursor: 'pointer' }}>
<HoverHelpTooltip tooltip={availabilityInfo} placement="top">
<InformationCircle size="small" color="tertiary" />
</HoverHelpTooltip>
</span>
<style>{styles}</style>
</div>
);
};
export default createFragmentContainer(
Phone,
graphql`
fragment Phone on CustomerSupportNumber {
number
localeTerritory
supportedLanguages {
language
languageCode
phoneLanguageAvailability {
type
... on CSPhoneAvailabilityWorkingDays {
from
to
}
}
}
}
`,
);