@kiwicom/smart-faq
Version:
Smart FAQ
279 lines (262 loc) • 7.89 kB
JavaScript
// @flow
import * as React from 'react';
import { withRouter } from 'react-router-dom';
import { Heading, Text } from '@kiwicom/orbit-components';
import type { ThemeProps } from '@kiwicom/nitro/lib/records/Theme';
import { createFragmentContainer, graphql } from 'react-relay';
import css from 'styled-jsx/css';
import idx from 'idx';
import Translate from '@kiwicom/nitro/lib/components/Translate';
import { withTheme } from 'styled-components';
import Markdown from '../../../SmartFAQ/common/Markdown';
import GuaranteeChat from './GuaranteeChat';
import FAQArticleFeedback from '../ArticleFeedback/FAQArticleFeedback';
import {
LogladyTracker,
LogladyTimeTracker,
EnterTracker,
TimeTracker,
} from '../../helpers/analytics/trackers';
import { GuaranteeChatContext } from '../../context/GuaranteeChatInfo';
import { withToken } from '../../../SmartFAQ/context/User';
import {
SidebarVersion,
FullPageVersion,
} from '../../../SmartFAQ/common/PageVariant';
import type { ArticleContent_article } from './__generated__/ArticleContent_article.graphql';
import { BookingState } from '../../../SmartFAQ/context/BookingState';
export const GUARANTEE_ARTICLE_ID = 'RkFRQXJ0aWNsZToyOA==';
export const THRESHOLD = 4;
type Props = {
loginToken: ?string,
simpleToken: ?string,
kwAuthToken: ?string,
isInGuaranteeArticle: boolean,
article: ArticleContent_article,
showGuaranteeChat: boolean,
...ThemeProps,
};
const ArticleContent = withTheme((props: Props) => (
<>
<FullPageVersion>
<div
style={{
border: `${props.theme.orbit.borderWidthCard} ${
props.theme.orbit.borderStyleCard
} ${props.theme.orbit.borderColorCard}`,
background: props.theme.orbit.backgroundCard,
borderRadius: props.theme.orbit.borderRadiusNormal,
paddingTop: '28px',
}}
>
<NakedArticleContent {...props} />
</div>
</FullPageVersion>
<SidebarVersion>
<NakedArticleContent {...props} />
</SidebarVersion>
</>
));
const NakedArticleContent = withTheme((props: Props) => {
const isLoggedIn = props.loginToken || props.simpleToken || props.kwAuthToken;
const { article, isInGuaranteeArticle, showGuaranteeChat } = props;
const showMessage = isInGuaranteeArticle && !showGuaranteeChat && !isLoggedIn;
const globalStyle = css`
.guaranteeLoggedOut a {
color: ${props.theme.orbit.colorTextLinkPrimaryHover};
text-decoration: none;
}
.faq-article-text ul {
padding-left: 43px;
list-style: none;
}
.faq-article-text ul,
.faq-article-text ol {
margin-left: 20px;
padding-bottom: 20px;
margin-bottom: 10px;
}
.faq-article-text li:before {
content: '';
display: inline-block;
margin-right: 19px;
width: 6px;
height: 6px;
margin-bottom: 2px;
}
:global([dir='rtl']) .faq-article-text li:before {
margin-right: 0;
margin-left: 19px;
}
.faq-article-text ul li:before {
background-color: #d5dee7;
}
.faq-article-text a {
color: ${props.theme.orbit.colorTextLinkPrimaryHover};
text-decoration: none;
}
.faq-article-text img {
width: 100%;
height: auto;
object-fit: contain;
}
.faq-article-text li {
display: list-item;
padding-top: 10px;
text-indent: -25px;
}
.faq-article-text li,
.faq-article-text div {
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
`;
return (
<BookingState.Consumer>
{({ showBooking }) => (
<div
className={
showBooking && isLoggedIn
? 'articleContentLoggedIn'
: 'articleContentLoggedOut'
}
data-cy="faq-article-content"
>
<Heading type="title2">{article.title || ''}</Heading>
<div className="faq-article-perex">
<Text type="attention" weight="bold" element="span">
<Translate t={__('smartfaq.faq.article.summary')} />
</Text>
<Text element="span"> {article.perex}</Text>
</div>
<hr className="faq-article-delimiter" />
<div className="faq-article-text">
<Markdown>{article.content}</Markdown>
</div>
{showGuaranteeChat && <GuaranteeChat />}
{showMessage && (
<div className="guaranteeLoggedOut">
<Translate
html
t={__('smartfaq.faq.article.guarantee.logged_out')}
values={{ guaranteeChatThreshold: THRESHOLD }}
/>
</div>
)}
<hr className="faq-article-delimiter" />
<FAQArticleFeedback articleId={article.id} />
<style jsx>
{`
.articleContentLoggedIn {
padding: 16px 72px 40px 80px;
}
.articleContentLoggedOut {
padding: 16px 36px 40px;
}
.faq-article-perex {
padding: 24px 0;
line-height: 20px;
}
.faq-article-delimiter {
border: 0;
height: 1px;
background-color: #e8edf1;
margin: 0;
}
.faq-article-text {
padding: 24px 0;
}
.guaranteeLoggedOut {
margin-bottom: 40px;
}
@media only screen and (max-width: 901px) {
.articleContentLoggedIn,
.articleContentLoggedOut {
padding: 16px;
}
}
`}
</style>
<style jsx global>
{globalStyle}
</style>
</div>
)}
</BookingState.Consumer>
);
});
export const UnwrappedArticleContent = ArticleContent;
const LogladyTrackedDetail = LogladyTracker(
withToken(ArticleContent),
'FAQs',
'articleOpened',
(props: Props) => ({
articleId: idx(props.article, _ => _.originalId) || '',
articleName: idx(props.article, _ => _.title) || '',
}),
);
const EnterTrackedDetail = EnterTracker(
LogladyTrackedDetail,
'smartFAQCategories',
(props: Props) => ({
action: 'clickOnArticle',
articleId: idx(props.article, _ => _.id) || '',
articleName: idx(props.article, _ => _.title) || '',
}),
);
const LogladyTimeTracked = LogladyTimeTracker(
EnterTrackedDetail,
'FAQs',
'articleClosed',
(props: Props) => ({
articleId: idx(props.article, _ => _.id) || '',
articleName: idx(props.article, _ => _.title) || '',
}),
);
const TimeTrackedDetail = TimeTracker(
LogladyTimeTracked,
'smartFAQCategories',
(props: Props) => ({
action: 'articleClose',
articleId: idx(props.article, _ => _.id) || '',
articleName: idx(props.article, _ => _.title) || '',
}),
);
type ContainerProps = {
match: {
params: {
articleId: string,
categoryId: string,
[key: string]: ?string,
},
},
};
const WrappedArticle = (props: Props & ContainerProps) => (
<GuaranteeChatContext.Consumer>
{({ showGuaranteeChat }) => {
// show Guarantee Chat only in Guarantee article
const articleId = idx(props.match, _ => _.params.articleId);
const isInGuaranteeArticle = articleId === GUARANTEE_ARTICLE_ID;
return (
<TimeTrackedDetail
showGuaranteeChat={showGuaranteeChat && isInGuaranteeArticle}
isInGuaranteeArticle={isInGuaranteeArticle}
{...props}
/>
);
}}
</GuaranteeChatContext.Consumer>
);
export default createFragmentContainer(
withRouter(WrappedArticle),
graphql`
fragment ArticleContent_article on FAQArticle {
id
originalId: id(opaque: false)
title
perex
content
}
`,
);