@ -548,7 +548,7 @@ export type ClientConfig = {
|
|||||||
authProviders: AuthProviders;
|
authProviders: AuthProviders;
|
||||||
debugMode: Scalars['Boolean'];
|
debugMode: Scalars['Boolean'];
|
||||||
signInPrefilled: Scalars['Boolean'];
|
signInPrefilled: Scalars['Boolean'];
|
||||||
supportChat: SupportChat;
|
support: Support;
|
||||||
telemetry: Telemetry;
|
telemetry: Telemetry;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1907,10 +1907,10 @@ export type StringNullableFilter = {
|
|||||||
startsWith?: InputMaybe<Scalars['String']>;
|
startsWith?: InputMaybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SupportChat = {
|
export type Support = {
|
||||||
__typename?: 'SupportChat';
|
__typename?: 'Support';
|
||||||
supportDriver: Scalars['String'];
|
supportDriver: Scalars['String'];
|
||||||
supportFrontendKey?: Maybe<Scalars['String']>;
|
supportFrontChatId?: Maybe<Scalars['String']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Telemetry = {
|
export type Telemetry = {
|
||||||
@ -1942,7 +1942,7 @@ export type User = {
|
|||||||
phoneNumber?: Maybe<Scalars['String']>;
|
phoneNumber?: Maybe<Scalars['String']>;
|
||||||
settings: UserSettings;
|
settings: UserSettings;
|
||||||
settingsId: Scalars['String'];
|
settingsId: Scalars['String'];
|
||||||
supportHMACKey?: Maybe<Scalars['String']>;
|
supportUserHash: Scalars['String'];
|
||||||
updatedAt: Scalars['DateTime'];
|
updatedAt: Scalars['DateTime'];
|
||||||
workspaceMember?: Maybe<WorkspaceMember>;
|
workspaceMember?: Maybe<WorkspaceMember>;
|
||||||
};
|
};
|
||||||
@ -2437,7 +2437,7 @@ export type VerifyMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, supportUserHash: string, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
||||||
|
|
||||||
export type RenewTokenMutationVariables = Exact<{
|
export type RenewTokenMutationVariables = Exact<{
|
||||||
refreshToken: Scalars['String'];
|
refreshToken: Scalars['String'];
|
||||||
@ -2451,12 +2451,12 @@ export type ImpersonateMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, supportUserHash: string, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } };
|
||||||
|
|
||||||
export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, debugMode: boolean, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean }, supportChat: { __typename?: 'SupportChat', supportDriver: string, supportFrontendKey?: string | null } } };
|
export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, debugMode: boolean, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean }, support: { __typename?: 'Support', supportDriver: string, supportFrontChatId?: string | null } } };
|
||||||
|
|
||||||
export type GetCompaniesQueryVariables = Exact<{
|
export type GetCompaniesQueryVariables = Exact<{
|
||||||
orderBy?: InputMaybe<Array<CompanyOrderByWithRelationInput> | CompanyOrderByWithRelationInput>;
|
orderBy?: InputMaybe<Array<CompanyOrderByWithRelationInput> | CompanyOrderByWithRelationInput>;
|
||||||
@ -2685,7 +2685,7 @@ export type SearchActivityQuery = { __typename?: 'Query', searchResults: Array<{
|
|||||||
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null, canImpersonate: boolean, supportHMACKey?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, locale: string, colorScheme: ColorScheme } } };
|
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null, canImpersonate: boolean, supportUserHash: string, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, locale: string, colorScheme: ColorScheme } } };
|
||||||
|
|
||||||
export type GetUsersQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetUsersQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
@ -3479,6 +3479,7 @@ export const VerifyDocument = gql`
|
|||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
canImpersonate
|
canImpersonate
|
||||||
|
supportUserHash
|
||||||
workspaceMember {
|
workspaceMember {
|
||||||
id
|
id
|
||||||
allowImpersonation
|
allowImpersonation
|
||||||
@ -3587,6 +3588,7 @@ export const ImpersonateDocument = gql`
|
|||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
canImpersonate
|
canImpersonate
|
||||||
|
supportUserHash
|
||||||
workspaceMember {
|
workspaceMember {
|
||||||
id
|
id
|
||||||
allowImpersonation
|
allowImpersonation
|
||||||
@ -3656,9 +3658,9 @@ export const GetClientConfigDocument = gql`
|
|||||||
enabled
|
enabled
|
||||||
anonymizationEnabled
|
anonymizationEnabled
|
||||||
}
|
}
|
||||||
supportChat {
|
support {
|
||||||
supportDriver
|
supportDriver
|
||||||
supportFrontendKey
|
supportFrontChatId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4907,7 +4909,7 @@ export const GetCurrentUserDocument = gql`
|
|||||||
locale
|
locale
|
||||||
colorScheme
|
colorScheme
|
||||||
}
|
}
|
||||||
supportHMACKey
|
supportUserHash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -40,6 +40,7 @@ export const VERIFY = gql`
|
|||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
canImpersonate
|
canImpersonate
|
||||||
|
supportUserHash
|
||||||
workspaceMember {
|
workspaceMember {
|
||||||
id
|
id
|
||||||
allowImpersonation
|
allowImpersonation
|
||||||
@ -99,6 +100,7 @@ export const IMPERSONATE = gql`
|
|||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
canImpersonate
|
canImpersonate
|
||||||
|
supportUserHash
|
||||||
workspaceMember {
|
workspaceMember {
|
||||||
id
|
id
|
||||||
allowImpersonation
|
allowImpersonation
|
||||||
|
|||||||
@ -33,7 +33,7 @@ export const ClientConfigProvider: React.FC<React.PropsWithChildren> = ({
|
|||||||
setDebugMode(data?.clientConfig.debugMode);
|
setDebugMode(data?.clientConfig.debugMode);
|
||||||
setSignInPrefilled(data?.clientConfig.signInPrefilled);
|
setSignInPrefilled(data?.clientConfig.signInPrefilled);
|
||||||
setTelemetry(data?.clientConfig.telemetry);
|
setTelemetry(data?.clientConfig.telemetry);
|
||||||
setSupportChat(data?.clientConfig.supportChat);
|
setSupportChat(data?.clientConfig.support);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
data,
|
data,
|
||||||
|
|||||||
@ -13,9 +13,9 @@ export const GET_CLIENT_CONFIG = gql`
|
|||||||
enabled
|
enabled
|
||||||
anonymizationEnabled
|
anonymizationEnabled
|
||||||
}
|
}
|
||||||
supportChat {
|
support {
|
||||||
supportDriver
|
supportDriver
|
||||||
supportFrontendKey
|
supportFrontChatId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { atom } from 'recoil';
|
import { atom } from 'recoil';
|
||||||
|
|
||||||
import { SupportChat } from '~/generated/graphql';
|
import { Support } from '~/generated/graphql';
|
||||||
|
|
||||||
export const supportChatState = atom<SupportChat>({
|
export const supportChatState = atom<Support>({
|
||||||
key: 'supportChatState',
|
key: 'supportChatState',
|
||||||
default: {
|
default: {
|
||||||
supportDriver: 'front',
|
supportDriver: 'none',
|
||||||
supportFrontendKey: null,
|
supportFrontChatId: null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -129,7 +129,7 @@ const StyledButton = styled.button<
|
|||||||
return theme.font.weight.medium;
|
return theme.font.weight.medium;
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
height: ${({ size }) => (size === 'small' ? '24px' : '32px')};
|
height: ${({ size }) => (size === 'small' ? '24px' : '32px')};
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
padding: ${({ theme, title }) => {
|
padding: ${({ theme, title }) => {
|
||||||
|
|||||||
@ -52,3 +52,4 @@ export { IconCalendar } from '@tabler/icons-react';
|
|||||||
export { IconPencil } from '@tabler/icons-react';
|
export { IconPencil } from '@tabler/icons-react';
|
||||||
export { IconCircleDot } from '@tabler/icons-react';
|
export { IconCircleDot } from '@tabler/icons-react';
|
||||||
export { IconTag } from '@tabler/icons-react';
|
export { IconTag } from '@tabler/icons-react';
|
||||||
|
export { IconHelpCircle } from '@tabler/icons-react';
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
@ -9,24 +10,12 @@ import {
|
|||||||
ButtonSize,
|
ButtonSize,
|
||||||
ButtonVariant,
|
ButtonVariant,
|
||||||
} from '@/ui/button/components/Button';
|
} from '@/ui/button/components/Button';
|
||||||
|
import { IconHelpCircle } from '@/ui/icon';
|
||||||
|
|
||||||
const StyledButtonContainer = styled.div`
|
const StyledButtonContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledQuestionMark = styled.div`
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 50%;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: ${({ theme }) => theme.spacing(0.25)};
|
|
||||||
display: flex;
|
|
||||||
height: ${({ theme }) => theme.spacing(3.5)};
|
|
||||||
justify-content: center;
|
|
||||||
margin-right: ${({ theme }) => theme.spacing(1)};
|
|
||||||
width: ${({ theme }) => theme.spacing(3.5)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
// insert a script tag into the DOM right before the closing body tag
|
|
||||||
function insertScript({
|
function insertScript({
|
||||||
src,
|
src,
|
||||||
innerHTML,
|
innerHTML,
|
||||||
@ -63,41 +52,39 @@ function configureFront(chatId: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function SupportChat() {
|
export default function SupportChat() {
|
||||||
|
const theme = useTheme();
|
||||||
const user = useRecoilValue(currentUserState);
|
const user = useRecoilValue(currentUserState);
|
||||||
const supportChatConfig = useRecoilValue(supportChatState);
|
const supportChatConfig = useRecoilValue(supportChatState);
|
||||||
const [isFrontChatLoaded, setIsFrontChatLoaded] = useState(false);
|
const [isFrontChatLoaded, setIsFrontChatLoaded] = useState(false);
|
||||||
const [isChatShowing, setIsChatShowing] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
supportChatConfig?.supportDriver === 'front' &&
|
supportChatConfig?.supportDriver === 'front' &&
|
||||||
supportChatConfig.supportFrontendKey &&
|
supportChatConfig.supportFrontChatId &&
|
||||||
!isFrontChatLoaded
|
!isFrontChatLoaded
|
||||||
) {
|
) {
|
||||||
configureFront(supportChatConfig.supportFrontendKey);
|
configureFront(supportChatConfig.supportFrontChatId);
|
||||||
setIsFrontChatLoaded(true);
|
setIsFrontChatLoaded(true);
|
||||||
}
|
}
|
||||||
if (user?.email && isFrontChatLoaded) {
|
if (user?.email && isFrontChatLoaded) {
|
||||||
window.FrontChat?.('identity', {
|
window.FrontChat?.('identity', {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
name: user.displayName,
|
name: user.displayName,
|
||||||
userHash: user?.supportHMACKey,
|
userHash: user?.supportUserHash,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
isFrontChatLoaded,
|
isFrontChatLoaded,
|
||||||
supportChatConfig?.supportDriver,
|
supportChatConfig?.supportDriver,
|
||||||
supportChatConfig.supportFrontendKey,
|
supportChatConfig.supportFrontChatId,
|
||||||
user?.displayName,
|
user?.displayName,
|
||||||
user?.email,
|
user?.email,
|
||||||
user?.supportHMACKey,
|
user?.supportUserHash,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function handleSupportClick() {
|
function handleSupportClick() {
|
||||||
if (supportChatConfig?.supportDriver === 'front') {
|
if (supportChatConfig?.supportDriver === 'front') {
|
||||||
const action = isChatShowing ? 'hide' : 'show';
|
window.FrontChat?.('show');
|
||||||
setIsChatShowing(!isChatShowing);
|
|
||||||
window.FrontChat?.(action);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +94,7 @@ export default function SupportChat() {
|
|||||||
variant={ButtonVariant.Tertiary}
|
variant={ButtonVariant.Tertiary}
|
||||||
size={ButtonSize.Small}
|
size={ButtonSize.Small}
|
||||||
title="Support"
|
title="Support"
|
||||||
icon={<StyledQuestionMark>?</StyledQuestionMark>}
|
icon={<IconHelpCircle size={theme.icon.size.md} />}
|
||||||
onClick={handleSupportClick}
|
onClick={handleSupportClick}
|
||||||
/>
|
/>
|
||||||
</StyledButtonContainer>
|
</StyledButtonContainer>
|
||||||
|
|||||||
@ -27,7 +27,7 @@ export const GET_CURRENT_USER = gql`
|
|||||||
locale
|
locale
|
||||||
colorScheme
|
colorScheme
|
||||||
}
|
}
|
||||||
supportHMACKey
|
supportUserHash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -207,9 +207,9 @@ export const graphqlMocks = [
|
|||||||
debugMode: false,
|
debugMode: false,
|
||||||
authProviders: { google: true, password: true, magicLink: false },
|
authProviders: { google: true, password: true, magicLink: false },
|
||||||
telemetry: { enabled: false, anonymizationEnabled: true },
|
telemetry: { enabled: false, anonymizationEnabled: true },
|
||||||
supportChat: {
|
support: {
|
||||||
supportDriver: 'front',
|
supportDriver: 'front',
|
||||||
supportFrontendKey: null,
|
supportFrontChatId: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -17,6 +17,7 @@ export const mockedUsersData: Array<MockedUser> = [
|
|||||||
lastName: 'Test',
|
lastName: 'Test',
|
||||||
avatarUrl: null,
|
avatarUrl: null,
|
||||||
canImpersonate: false,
|
canImpersonate: false,
|
||||||
|
supportUserHash: '',
|
||||||
workspaceMember: {
|
workspaceMember: {
|
||||||
__typename: 'WorkspaceMember',
|
__typename: 'WorkspaceMember',
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
||||||
@ -45,6 +46,7 @@ export const mockedUsersData: Array<MockedUser> = [
|
|||||||
firstName: 'Felix',
|
firstName: 'Felix',
|
||||||
lastName: 'Test',
|
lastName: 'Test',
|
||||||
canImpersonate: false,
|
canImpersonate: false,
|
||||||
|
supportUserHash: '',
|
||||||
workspaceMember: {
|
workspaceMember: {
|
||||||
__typename: 'WorkspaceMember',
|
__typename: 'WorkspaceMember',
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
||||||
@ -77,6 +79,7 @@ export const mockedOnboardingUsersData: Array<MockedUser> = [
|
|||||||
lastName: '',
|
lastName: '',
|
||||||
avatarUrl: null,
|
avatarUrl: null,
|
||||||
canImpersonate: false,
|
canImpersonate: false,
|
||||||
|
supportUserHash: '',
|
||||||
workspaceMember: {
|
workspaceMember: {
|
||||||
__typename: 'WorkspaceMember',
|
__typename: 'WorkspaceMember',
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
||||||
@ -106,6 +109,7 @@ export const mockedOnboardingUsersData: Array<MockedUser> = [
|
|||||||
lastName: '',
|
lastName: '',
|
||||||
avatarUrl: null,
|
avatarUrl: null,
|
||||||
canImpersonate: false,
|
canImpersonate: false,
|
||||||
|
supportUserHash: '',
|
||||||
workspaceMember: {
|
workspaceMember: {
|
||||||
__typename: 'WorkspaceMember',
|
__typename: 'WorkspaceMember',
|
||||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
||||||
|
|||||||
@ -19,5 +19,5 @@ SIGN_IN_PREFILLED=true
|
|||||||
# STORAGE_TYPE=local
|
# STORAGE_TYPE=local
|
||||||
# STORAGE_LOCAL_PATH=.local-storage
|
# STORAGE_LOCAL_PATH=.local-storage
|
||||||
# SUPPORT_DRIVER=front
|
# SUPPORT_DRIVER=front
|
||||||
# SUPPORT_HMAC_KEY=replace_me_with_a_random_string
|
# SUPPORT_FRONT_HMAC_KEY=replace_me_with_front_chat_verification_secret
|
||||||
# SUPPORT_FRONTEND_KEY=replace_me_with_a_random_string
|
# SUPPORT_FRONT_CHAT_ID=replace_me_with_front_chat_id
|
||||||
|
|||||||
@ -22,12 +22,12 @@ class Telemetry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
class SupportChat {
|
class Support {
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
supportDriver: string;
|
supportDriver: string;
|
||||||
|
|
||||||
@Field(() => String, { nullable: true })
|
@Field(() => String, { nullable: true })
|
||||||
supportFrontendKey: string | null;
|
supportFrontChatId: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
@ -44,6 +44,6 @@ export class ClientConfig {
|
|||||||
@Field(() => Boolean)
|
@Field(() => Boolean)
|
||||||
debugMode: boolean;
|
debugMode: boolean;
|
||||||
|
|
||||||
@Field(() => SupportChat)
|
@Field(() => Support)
|
||||||
supportChat: SupportChat;
|
support: Support;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,9 +23,9 @@ export class ClientConfigResolver {
|
|||||||
},
|
},
|
||||||
signInPrefilled: this.environmentService.isSignInPrefilled(),
|
signInPrefilled: this.environmentService.isSignInPrefilled(),
|
||||||
debugMode: this.environmentService.isDebugMode(),
|
debugMode: this.environmentService.isDebugMode(),
|
||||||
supportChat: {
|
support: {
|
||||||
supportDriver: this.environmentService.getSupportDriver(),
|
supportDriver: this.environmentService.getSupportDriver(),
|
||||||
supportFrontendKey: this.environmentService.getSupportFrontendKey(),
|
supportFrontChatId: this.environmentService.getSupportFrontChatId(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
import { Field, ObjectType } from '@nestjs/graphql';
|
|
||||||
|
|
||||||
import { User } from 'src/core/@generated/user/user.model';
|
|
||||||
|
|
||||||
@ObjectType()
|
|
||||||
export class UserWithHMACKey extends User {
|
|
||||||
@Field(() => String, { nullable: true })
|
|
||||||
supportHMACKey: string | null;
|
|
||||||
}
|
|
||||||
@ -43,7 +43,7 @@ import { EnvironmentService } from 'src/integrations/environment/environment.ser
|
|||||||
|
|
||||||
import { UserService } from './user.service';
|
import { UserService } from './user.service';
|
||||||
|
|
||||||
import { UserWithHMACKey } from './dto/user-with-HMAC';
|
import { SupportDriver } from 'src/integrations/environment/interfaces/support.interface';
|
||||||
|
|
||||||
function getHMACKey(email?: string, key?: string | null) {
|
function getHMACKey(email?: string, key?: string | null) {
|
||||||
if (!email || !key) return null;
|
if (!email || !key) return null;
|
||||||
@ -61,26 +61,25 @@ export class UserResolver {
|
|||||||
private environmentService: EnvironmentService,
|
private environmentService: EnvironmentService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Query(() => UserWithHMACKey)
|
@Query(() => User)
|
||||||
async currentUser(
|
async currentUser(
|
||||||
@AuthUser() { id, email }: User,
|
@AuthUser() { id }: User,
|
||||||
@PrismaSelector({ modelName: 'User' })
|
@PrismaSelector({ modelName: 'User' })
|
||||||
prismaSelect: PrismaSelect<'User'>,
|
prismaSelect: PrismaSelect<'User'>,
|
||||||
) {
|
) {
|
||||||
const key = this.environmentService.getSupportHMACKey();
|
|
||||||
|
|
||||||
const select = prismaSelect.value;
|
const select = prismaSelect.value;
|
||||||
delete select['supportHMACKey'];
|
|
||||||
|
|
||||||
const user = await this.userService.findUnique({
|
const user = await this.userService.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id,
|
id,
|
||||||
},
|
},
|
||||||
select,
|
select
|
||||||
});
|
});
|
||||||
assert(user, 'User not found');
|
assert(user, 'User not found');
|
||||||
|
|
||||||
return { ...user, supportHMACKey: getHMACKey(email, key) };
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseFilters(ExceptionFilter)
|
@UseFilters(ExceptionFilter)
|
||||||
@ -141,6 +140,17 @@ export class UserResolver {
|
|||||||
return `${parent.firstName ?? ''} ${parent.lastName ?? ''}`;
|
return `${parent.firstName ?? ''} ${parent.lastName ?? ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => String, {
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
supportUserHash(@Parent() parent: User): string | null {
|
||||||
|
if (this.environmentService.getSupportDriver() !== SupportDriver.Front) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const key = this.environmentService.getSupportFrontHMACKey();
|
||||||
|
return getHMACKey(parent.email, key);
|
||||||
|
}
|
||||||
|
|
||||||
@Mutation(() => String)
|
@Mutation(() => String)
|
||||||
async uploadProfilePicture(
|
async uploadProfilePicture(
|
||||||
@AuthUser() { id }: User,
|
@AuthUser() { id }: User,
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { ConfigService } from '@nestjs/config';
|
|||||||
|
|
||||||
import { AwsRegion } from './interfaces/aws-region.interface';
|
import { AwsRegion } from './interfaces/aws-region.interface';
|
||||||
import { StorageType } from './interfaces/storage.interface';
|
import { StorageType } from './interfaces/storage.interface';
|
||||||
|
import { SupportDriver } from './interfaces/support.interface';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EnvironmentService {
|
export class EnvironmentService {
|
||||||
@ -103,14 +104,14 @@ export class EnvironmentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSupportDriver(): string {
|
getSupportDriver(): string {
|
||||||
return this.configService.get<string>('SUPPORT_DRIVER') ?? 'front';
|
return this.configService.get<string>('SUPPORT_DRIVER') ?? SupportDriver.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSupportFrontendKey(): string | null {
|
getSupportFrontChatId(): string | undefined {
|
||||||
return this.configService.get<string>('SUPPORT_FRONTEND_KEY') ?? null;
|
return this.configService.get<string>('SUPPORT_FRONT_CHAT_ID');
|
||||||
}
|
}
|
||||||
|
|
||||||
getSupportHMACKey(): string | null {
|
getSupportFrontHMACKey(): string | undefined {
|
||||||
return this.configService.get<string>('SUPPORT_HMAC_KEY') ?? null;
|
return this.configService.get<string>('SUPPORT_FRONT_HMAC_KEY');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { StorageType } from './interfaces/storage.interface';
|
|||||||
import { AwsRegion } from './interfaces/aws-region.interface';
|
import { AwsRegion } from './interfaces/aws-region.interface';
|
||||||
import { IsAWSRegion } from './decorators/is-aws-region.decorator';
|
import { IsAWSRegion } from './decorators/is-aws-region.decorator';
|
||||||
import { CastToBoolean } from './decorators/cast-to-boolean.decorator';
|
import { CastToBoolean } from './decorators/cast-to-boolean.decorator';
|
||||||
|
import { SupportDriver } from './interfaces/support.interface';
|
||||||
|
|
||||||
export class EnvironmentVariables {
|
export class EnvironmentVariables {
|
||||||
// Misc
|
// Misc
|
||||||
@ -104,6 +105,19 @@ export class EnvironmentVariables {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@ValidateIf((env) => env.STORAGE_TYPE === StorageType.Local)
|
@ValidateIf((env) => env.STORAGE_TYPE === StorageType.Local)
|
||||||
STORAGE_LOCAL_PATH?: string;
|
STORAGE_LOCAL_PATH?: string;
|
||||||
|
|
||||||
|
// Support
|
||||||
|
@IsEnum(SupportDriver)
|
||||||
|
@IsOptional()
|
||||||
|
SUPPORT_DRIVER?: SupportDriver;
|
||||||
|
|
||||||
|
@ValidateIf((env) => env.SUPPORT_DRIVER === SupportDriver.Front)
|
||||||
|
@IsString()
|
||||||
|
SUPPORT_FRONT_CHAT_ID?: AwsRegion;
|
||||||
|
|
||||||
|
@ValidateIf((env) => env.SUPPORT_DRIVER === SupportDriver.Front)
|
||||||
|
@IsString()
|
||||||
|
SUPPORT_FRONT_HMAC_KEY?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validate(config: Record<string, unknown>) {
|
export function validate(config: Record<string, unknown>) {
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
export enum SupportDriver {
|
||||||
|
None = 'none',
|
||||||
|
Front = 'front',
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user