@kiwicom/smart-faq
Version:
255 lines (241 loc) • 7.34 kB
JavaScript
// @flow
import * as React from 'react';
import Head from 'next/head';
import { withRouter } from 'react-router-dom';
import Text from '@kiwicom/nitro/lib/components/Text';
import OrbitText from '@kiwicom/orbit-components/lib/Text';
import Heading from '@kiwicom/orbit-components/lib/Heading';
import Separator from '@kiwicom/orbit-components/lib/Separator';
import Stack from '@kiwicom/orbit-components/lib/Stack';
import type { ThemeProps } from '@kiwicom/nitro/lib/records/Theme';
import { createFragmentContainer, graphql } from 'react-relay';
import { withTheme, ThemeContext } from 'styled-components';
import type { ContextRouter } from 'react-router-dom';
import FAQContentRender from '../../../SmartFAQ/common/FAQContentRender';
import GuaranteeChat from './GuaranteeChat';
import FAQArticleFeedback from '../ArticleFeedback/FAQArticleFeedback';
import { GuaranteeChatContext } from '../../context/GuaranteeChatInfo';
import {
SidebarVersion,
FullPageVersion,
} from '../../../SmartFAQ/common/PageVariant';
import type { ArticleContent_article as ArticleContentType } from './__generated__/ArticleContent_article.graphql';
import { BookingState } from '../../../SmartFAQ/context/BookingState';
import { UserContext } from '../../../SmartFAQ/context/User';
import { isWebView } from '../../../SmartFAQ/helpers/UrlHelpers';
import LogLifecycle from '../../cuckoo/components/LogLifecycle';
export const GUARANTEE_ARTICLE_ID = 28;
export const THRESHOLD = 4;
type ContainerProps = {|
...ContextRouter,
article: ArticleContentType,
|};
type Props = {|
...ContainerProps,
...ThemeProps,
isInGuaranteeArticle: boolean,
showGuaranteeChat: boolean,
|};
const ArticleContent = (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',
marginBottom: '80px',
}}
>
<NakedArticleContent {...props} />
</div>
</FullPageVersion>
<SidebarVersion>
<NakedArticleContent {...props} />
</SidebarVersion>
</>
);
const NakedArticleContent = withTheme((props: Props) => {
const { simpleToken, kwAuthToken, loginToken } = React.useContext(
UserContext,
);
const isLoggedIn = simpleToken || kwAuthToken || loginToken;
const { article, isInGuaranteeArticle, showGuaranteeChat } = props;
const showMessage =
isInGuaranteeArticle && !showGuaranteeChat && !isLoggedIn && !isWebView;
const { showBooking } = React.useContext(BookingState);
const globalStyle = `
.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 figure {
margin: 0;
}
.faq-article-text img {
max-width: 100%;
}
@supports (object-fit: scale-down) {
.faq-article-text img {
height: auto;
object-fit: scale-down;
}
.faq-article-text figure {
justify-content: center;
}
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
.faq-article-text img {
background-size: cover;
}
.faq-article-text figure {
display: flex;
}
}
.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 (
<div
className={
showBooking && isLoggedIn
? 'articleContentLoggedIn'
: 'articleContentLoggedOut'
}
data-cy="faq-article-content"
>
<Heading type="title2">{article.title ?? ''}</Heading>
<div className="faq-article-perex">
<Text
t="smartfaq.faq.article.summary"
type="attention"
weight="bold"
element="span"
/>
<OrbitText element="span"> {article.perex}</OrbitText>
</div>
<Separator />
{article.content && (
<div className="faq-article-text">
<FAQContentRender article={article}>
{article.content}
</FAQContentRender>
</div>
)}
{showGuaranteeChat && <GuaranteeChat />}
{showMessage && (
<Stack spaceAfter="large" dataTest="GuaranteeLoggedOut">
<Text
html
t="smartfaq.faq.article.guarantee.logged_out"
values={{ guaranteeChatThreshold: THRESHOLD }}
/>
</Stack>
)}
<Separator spaceAfter="medium" />
<FAQArticleFeedback articleId={Number(article.originalId)} />
<style jsx>
{`
.articleContentLoggedIn {
padding: 16px 72px 40px 80px;
}
.articleContentLoggedOut {
padding: 16px 36px 40px;
}
.faq-article-perex {
padding: 24px 0;
line-height: 20px;
}
.faq-article-text {
padding: 24px 0;
}
@media only screen and (max-width: 901px) {
.articleContentLoggedIn,
.articleContentLoggedOut {
padding: 16px;
}
}
`}
</style>
<style dangerouslySetInnerHTML={{ __html: globalStyle }} />
</div>
);
});
export const UnwrappedArticleContent = ArticleContent;
const WrappedArticle = (props: ContainerProps) => {
const { showGuaranteeChat } = React.useContext(GuaranteeChatContext);
const theme = React.useContext(ThemeContext);
// show Guarantee Chat only in Guarantee article
const articleId = props.match.params.articleId;
const isInGuaranteeArticle = Number(articleId) === GUARANTEE_ARTICLE_ID;
return (
<>
<Head>
<title>{`${props.article.title ?? ''}`} - Kiwi.com - Helpcenter</title>
</Head>
<ArticleContent
{...props}
theme={theme}
showGuaranteeChat={showGuaranteeChat && isInGuaranteeArticle}
isInGuaranteeArticle={isInGuaranteeArticle}
/>
<LogLifecycle
subCategory="FAQs"
actionMount="articleOpened"
actionUnmount="articleClosed"
props={{
articleId: articleId ?? '',
articleName: props.article.title ?? '',
}}
/>
</>
);
};
export default createFragmentContainer(
withRouter(WrappedArticle),
graphql`
fragment ArticleContent_article on FAQArticle {
...FAQContentRender_article
id
originalId: id(opaque: false)
title
perex
content
}
`,
);