2023-10-19 11:52:58 +05:30
|
|
|
import './Support.styles.scss';
|
|
|
|
|
|
2024-08-14 20:50:35 +05:30
|
|
|
import { Button, Card, Modal, Typography } from 'antd';
|
2024-07-23 16:32:45 +05:30
|
|
|
import logEvent from 'api/common/logEvent';
|
2025-05-24 19:14:29 +05:30
|
|
|
import updateCreditCardApi from 'api/v1/checkout/create';
|
2024-08-14 20:50:35 +05:30
|
|
|
import { FeatureKeys } from 'constants/features';
|
|
|
|
|
import { useNotifications } from 'hooks/useNotifications';
|
2023-10-19 11:52:58 +05:30
|
|
|
import {
|
|
|
|
|
Book,
|
2024-08-14 20:50:35 +05:30
|
|
|
CreditCard,
|
2023-10-19 11:52:58 +05:30
|
|
|
Github,
|
|
|
|
|
MessageSquare,
|
|
|
|
|
Slack,
|
2024-08-14 20:50:35 +05:30
|
|
|
X,
|
2023-10-19 11:52:58 +05:30
|
|
|
} from 'lucide-react';
|
2024-12-20 14:00:02 +05:30
|
|
|
import { useAppContext } from 'providers/App/App';
|
2024-08-14 20:50:35 +05:30
|
|
|
import { useEffect, useState } from 'react';
|
|
|
|
|
import { useMutation } from 'react-query';
|
2024-08-20 18:41:34 +05:30
|
|
|
import { useHistory, useLocation } from 'react-router-dom';
|
2025-05-24 19:14:29 +05:30
|
|
|
import { SuccessResponseV2 } from 'types/api';
|
2024-08-14 20:50:35 +05:30
|
|
|
import { CheckoutSuccessPayloadProps } from 'types/api/billing/checkout';
|
2025-05-24 19:14:29 +05:30
|
|
|
import APIError from 'types/api/error';
|
2023-10-19 11:52:58 +05:30
|
|
|
|
|
|
|
|
const { Title, Text } = Typography;
|
|
|
|
|
|
|
|
|
|
interface Channel {
|
|
|
|
|
key: any;
|
|
|
|
|
name?: string;
|
|
|
|
|
icon?: JSX.Element;
|
|
|
|
|
title?: string;
|
|
|
|
|
url: any;
|
|
|
|
|
btnText?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const channelsMap = {
|
|
|
|
|
documentation: 'documentation',
|
|
|
|
|
github: 'github',
|
|
|
|
|
slack_community: 'slack_community',
|
|
|
|
|
chat: 'chat',
|
|
|
|
|
schedule_call: 'schedule_call',
|
|
|
|
|
slack_connect: 'slack_connect',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const supportChannels = [
|
|
|
|
|
{
|
|
|
|
|
key: 'documentation',
|
|
|
|
|
name: 'Documentation',
|
|
|
|
|
icon: <Book />,
|
|
|
|
|
title: 'Find answers in the documentation.',
|
|
|
|
|
url: 'https://signoz.io/docs/',
|
|
|
|
|
btnText: 'Visit docs',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: 'github',
|
|
|
|
|
name: 'Github',
|
|
|
|
|
icon: <Github />,
|
|
|
|
|
title: 'Create an issue on GitHub to report bugs or request new features.',
|
|
|
|
|
url: 'https://github.com/SigNoz/signoz/issues',
|
|
|
|
|
btnText: 'Create issue',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: 'slack_community',
|
|
|
|
|
name: 'Slack Community',
|
|
|
|
|
icon: <Slack />,
|
|
|
|
|
title: 'Get support from the SigNoz community on Slack.',
|
|
|
|
|
url: 'https://signoz.io/slack',
|
|
|
|
|
btnText: 'Join Slack',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: 'chat',
|
|
|
|
|
name: 'Chat',
|
|
|
|
|
icon: <MessageSquare />,
|
|
|
|
|
title: 'Get quick support directly from the team.',
|
|
|
|
|
url: '',
|
|
|
|
|
btnText: 'Launch chat',
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export default function Support(): JSX.Element {
|
2024-06-07 14:49:34 +05:30
|
|
|
const history = useHistory();
|
2024-08-14 20:50:35 +05:30
|
|
|
const { notifications } = useNotifications();
|
2025-03-17 19:27:45 +05:30
|
|
|
const { trialInfo, featureFlags } = useAppContext();
|
2024-08-14 20:50:35 +05:30
|
|
|
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] = useState(
|
|
|
|
|
false,
|
|
|
|
|
);
|
2023-12-13 01:18:19 +05:30
|
|
|
|
2024-08-20 18:41:34 +05:30
|
|
|
const { pathname } = useLocation();
|
2023-10-19 11:52:58 +05:30
|
|
|
const handleChannelWithRedirects = (url: string): void => {
|
|
|
|
|
window.open(url, '_blank');
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-07 14:49:34 +05:30
|
|
|
useEffect(() => {
|
|
|
|
|
if (history?.location?.state) {
|
|
|
|
|
const histroyState = history?.location?.state as any;
|
|
|
|
|
|
|
|
|
|
if (histroyState && histroyState?.from) {
|
2024-07-23 16:32:45 +05:30
|
|
|
logEvent(`Support : From URL : ${histroyState.from}`, {});
|
2024-06-07 14:49:34 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, []);
|
|
|
|
|
|
2024-08-14 20:50:35 +05:30
|
|
|
const isPremiumChatSupportEnabled =
|
2024-12-20 14:00:02 +05:30
|
|
|
featureFlags?.find((flag) => flag.name === FeatureKeys.PREMIUM_SUPPORT)
|
|
|
|
|
?.active || false;
|
2024-08-14 20:50:35 +05:30
|
|
|
|
|
|
|
|
const showAddCreditCardModal =
|
2025-03-17 19:27:45 +05:30
|
|
|
!isPremiumChatSupportEnabled && !trialInfo?.trialConvertedToSubscription;
|
2024-08-14 20:50:35 +05:30
|
|
|
|
|
|
|
|
const handleBillingOnSuccess = (
|
2025-05-24 19:14:29 +05:30
|
|
|
data: SuccessResponseV2<CheckoutSuccessPayloadProps>,
|
2024-08-14 20:50:35 +05:30
|
|
|
): void => {
|
2025-05-24 19:14:29 +05:30
|
|
|
if (data?.data?.redirectURL) {
|
2024-08-14 20:50:35 +05:30
|
|
|
const newTab = document.createElement('a');
|
2025-05-24 19:14:29 +05:30
|
|
|
newTab.href = data.data.redirectURL;
|
2024-08-14 20:50:35 +05:30
|
|
|
newTab.target = '_blank';
|
|
|
|
|
newTab.rel = 'noopener noreferrer';
|
|
|
|
|
newTab.click();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-05-24 19:14:29 +05:30
|
|
|
const handleBillingOnError = (error: APIError): void => {
|
2024-08-14 20:50:35 +05:30
|
|
|
notifications.error({
|
2025-05-24 19:14:29 +05:30
|
|
|
message: error.getErrorCode(),
|
|
|
|
|
description: error.getErrorMessage(),
|
2024-08-14 20:50:35 +05:30
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const { mutate: updateCreditCard, isLoading: isLoadingBilling } = useMutation(
|
|
|
|
|
updateCreditCardApi,
|
|
|
|
|
{
|
|
|
|
|
onSuccess: (data) => {
|
|
|
|
|
handleBillingOnSuccess(data);
|
|
|
|
|
},
|
|
|
|
|
onError: handleBillingOnError,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const handleAddCreditCard = (): void => {
|
|
|
|
|
logEvent('Add Credit card modal: Clicked', {
|
2024-08-20 18:41:34 +05:30
|
|
|
source: `help & support`,
|
|
|
|
|
page: pathname,
|
2024-08-14 20:50:35 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
|
|
updateCreditCard({
|
2025-04-17 20:21:14 +05:30
|
|
|
url: window.location.origin,
|
2024-08-14 20:50:35 +05:30
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2023-10-19 11:52:58 +05:30
|
|
|
const handleChat = (): void => {
|
2024-08-14 20:50:35 +05:30
|
|
|
if (showAddCreditCardModal) {
|
2024-08-20 18:41:34 +05:30
|
|
|
logEvent('Disabled Chat Support: Clicked', {
|
|
|
|
|
source: `help & support`,
|
|
|
|
|
page: pathname,
|
|
|
|
|
});
|
2024-08-14 20:50:35 +05:30
|
|
|
setIsAddCreditCardModalOpen(true);
|
2025-05-28 07:11:11 +05:30
|
|
|
} else if (window.pylon) {
|
2023-10-19 11:52:58 +05:30
|
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
|
|
|
// @ts-ignore
|
2025-05-28 07:11:11 +05:30
|
|
|
window.Pylon('show');
|
2023-10-19 11:52:58 +05:30
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleChannelClick = (channel: Channel): void => {
|
2024-07-23 16:32:45 +05:30
|
|
|
logEvent(`Support : ${channel.name}`, {});
|
2023-12-13 01:18:19 +05:30
|
|
|
|
2023-10-19 11:52:58 +05:30
|
|
|
switch (channel.key) {
|
|
|
|
|
case channelsMap.documentation:
|
|
|
|
|
case channelsMap.github:
|
|
|
|
|
case channelsMap.slack_community:
|
|
|
|
|
handleChannelWithRedirects(channel.url);
|
|
|
|
|
break;
|
|
|
|
|
case channelsMap.chat:
|
|
|
|
|
handleChat();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
handleChannelWithRedirects('https://signoz.io/slack');
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="support-page-container">
|
|
|
|
|
<div className="support-page-header">
|
2025-06-12 19:55:32 +05:30
|
|
|
<Title level={3}> Help & Support </Title>
|
2023-10-19 11:52:58 +05:30
|
|
|
<Text style={{ fontSize: 14 }}>
|
|
|
|
|
We are here to help in case of questions or issues. Pick the channel that
|
|
|
|
|
is most convenient for you.
|
|
|
|
|
</Text>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="support-channels">
|
|
|
|
|
{supportChannels.map(
|
|
|
|
|
(channel): JSX.Element => (
|
|
|
|
|
<Card className="support-channel" key={channel.key}>
|
|
|
|
|
<div className="support-channel-content">
|
|
|
|
|
<Title ellipsis level={5} className="support-channel-title">
|
|
|
|
|
{channel.icon}
|
|
|
|
|
{channel.name}{' '}
|
|
|
|
|
</Title>
|
|
|
|
|
<Text> {channel.title} </Text>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="support-channel-action">
|
|
|
|
|
<Button
|
|
|
|
|
type="default"
|
|
|
|
|
onClick={(): void => handleChannelClick(channel)}
|
|
|
|
|
>
|
|
|
|
|
<Text ellipsis>{channel.btnText} </Text>
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
|
|
|
|
),
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2024-08-14 20:50:35 +05:30
|
|
|
|
|
|
|
|
{/* Add Credit Card Modal */}
|
|
|
|
|
<Modal
|
|
|
|
|
className="add-credit-card-modal"
|
|
|
|
|
title={<span className="title">Add Credit Card for Chat Support</span>}
|
|
|
|
|
open={isAddCreditCardModalOpen}
|
|
|
|
|
closable
|
|
|
|
|
onCancel={(): void => setIsAddCreditCardModalOpen(false)}
|
|
|
|
|
destroyOnClose
|
|
|
|
|
footer={[
|
|
|
|
|
<Button
|
|
|
|
|
key="cancel"
|
|
|
|
|
onClick={(): void => setIsAddCreditCardModalOpen(false)}
|
|
|
|
|
className="cancel-btn"
|
|
|
|
|
icon={<X size={16} />}
|
|
|
|
|
>
|
|
|
|
|
Cancel
|
|
|
|
|
</Button>,
|
|
|
|
|
<Button
|
|
|
|
|
key="submit"
|
|
|
|
|
type="primary"
|
|
|
|
|
icon={<CreditCard size={16} />}
|
|
|
|
|
size="middle"
|
|
|
|
|
loading={isLoadingBilling}
|
|
|
|
|
disabled={isLoadingBilling}
|
|
|
|
|
onClick={handleAddCreditCard}
|
|
|
|
|
className="add-credit-card-btn"
|
|
|
|
|
>
|
|
|
|
|
Add Credit Card
|
|
|
|
|
</Button>,
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<Typography.Text className="add-credit-card-text">
|
|
|
|
|
You're currently on <span className="highlight-text">Trial plan</span>
|
|
|
|
|
. Add a credit card to access SigNoz chat support to your workspace.
|
|
|
|
|
</Typography.Text>
|
|
|
|
|
</Modal>
|
2023-10-19 11:52:58 +05:30
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|