mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-08 23:15:24 +02:00
removed intercom references
This commit is contained in:
parent
cfd07abac9
commit
bbe6ec6b75
22 changed files with 69 additions and 378 deletions
|
@ -1,5 +1,4 @@
|
|||
import { useAuth0 } from '@auth0/auth0-react'
|
||||
import { useIntercom } from '@maybe-finance/client/shared'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import * as Sentry from '@sentry/react'
|
||||
|
@ -7,22 +6,6 @@ import * as Sentry from '@sentry/react'
|
|||
export default function APM() {
|
||||
const { user } = useAuth0()
|
||||
const router = useRouter()
|
||||
const intercom = useIntercom()
|
||||
|
||||
// Boot intercom
|
||||
useEffect(() => {
|
||||
const isBooted = intercom.boot()
|
||||
|
||||
const handleRouteChange = () => {
|
||||
if (isBooted) {
|
||||
intercom.update()
|
||||
}
|
||||
}
|
||||
|
||||
router.events.on('routeChangeComplete', handleRouteChange)
|
||||
|
||||
return () => router.events.off('routeChangeComplete', handleRouteChange)
|
||||
}, [intercom, router.events])
|
||||
|
||||
// Identify Sentry user
|
||||
useEffect(() => {
|
||||
|
|
|
@ -48,15 +48,6 @@ export default function Meta() {
|
|||
href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
{/* Intercom */}
|
||||
<script
|
||||
type="text/javascript"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `window.INTERCOM_APP_ID='${env.NEXT_PUBLIC_INTERCOM_APP_ID}';(function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic('reattach_activator');ic('update',w.intercomSettings);}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Intercom=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src='https://widget.intercom.io/widget/' + window.INTERCOM_APP_ID;var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s, x);};if(document.readyState==='complete'){l();}else if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();`,
|
||||
}}
|
||||
/>
|
||||
{/* End Intercom */}
|
||||
</Head>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
const env = {
|
||||
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3333',
|
||||
NEXT_PUBLIC_AUTH0_DOMAIN:
|
||||
process.env.NEXT_PUBLIC_AUTH0_DOMAIN || 'REPLACE_THIS',
|
||||
NEXT_PUBLIC_AUTH0_CLIENT_ID:
|
||||
process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID || 'REPLACE_THIS',
|
||||
NEXT_PUBLIC_AUTH0_DOMAIN: process.env.NEXT_PUBLIC_AUTH0_DOMAIN || 'REPLACE_THIS',
|
||||
NEXT_PUBLIC_AUTH0_CLIENT_ID: process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID || 'REPLACE_THIS',
|
||||
NEXT_PUBLIC_AUTH0_AUDIENCE:
|
||||
process.env.NEXT_PUBLIC_AUTH0_AUDIENCE || 'https://maybe-finance-api/v1',
|
||||
NEXT_PUBLIC_LD_CLIENT_SIDE_ID:
|
||||
process.env.NEXT_PUBLIC_LD_CLIENT_SIDE_ID || 'REPLACE_THIS',
|
||||
NEXT_PUBLIC_LD_CLIENT_SIDE_ID: process.env.NEXT_PUBLIC_LD_CLIENT_SIDE_ID || 'REPLACE_THIS',
|
||||
NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
||||
NEXT_PUBLIC_SENTRY_ENV: process.env.NEXT_PUBLIC_SENTRY_ENV,
|
||||
NEXT_PUBLIC_INTERCOM_APP_ID: process.env.NEXT_PUBLIC_INTERCOM_APP_ID || 'REPLACE_THIS',
|
||||
}
|
||||
|
||||
export default env
|
||||
|
|
|
@ -33,7 +33,7 @@ Sentry.init({
|
|||
})
|
||||
|
||||
// Providers and components only relevant to a logged-in user
|
||||
const WithAuth = withAuthenticationRequired(function ({ children }: PropsWithChildren) {
|
||||
const WithAuth = function ({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<ModalManager>
|
||||
<UserAccountContextProvider>
|
||||
|
@ -46,7 +46,7 @@ const WithAuth = withAuthenticationRequired(function ({ children }: PropsWithChi
|
|||
</UserAccountContextProvider>
|
||||
</ModalManager>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export default function App({
|
||||
Component: Page,
|
||||
|
|
|
@ -11,16 +11,16 @@ export default function OAuth() {
|
|||
// If our backend doesn't return a token to re-initialize with, show user troubleshooting message
|
||||
if (fetchTokenError) {
|
||||
return (
|
||||
<div className="fixed h-full w-full flex flex-col items-center gap-4 mt-48">
|
||||
<div className="fixed flex flex-col items-center w-full h-full gap-4 mt-48">
|
||||
<LoadingSpinner />
|
||||
{fetchTokenError && (
|
||||
<>
|
||||
<h4>Stuck on this page?</h4>
|
||||
<div className="mx-auto w-full max-w-md rounded-2xl bg-gray-800 p-2">
|
||||
<div className="w-full max-w-md p-2 mx-auto bg-gray-800 rounded-2xl">
|
||||
<Disclosure defaultOpen>
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Disclosure.Button className="flex w-full items-center justify-between rounded-lg bg-gray-700 px-4 py-2 text-left text-sm font-medium text-purple-900 hover:bg-purple-200 focus:outline-none focus-visible:ring focus-visible:ring-purple-500 focus-visible:ring-opacity-75">
|
||||
<Disclosure.Button className="flex items-center justify-between w-full px-4 py-2 text-sm font-medium text-left text-purple-900 bg-gray-700 rounded-lg hover:bg-purple-200 focus:outline-none focus-visible:ring focus-visible:ring-purple-500 focus-visible:ring-opacity-75">
|
||||
<span>Why did this happen?</span>
|
||||
<RiArrowUpSFill
|
||||
className={`${
|
||||
|
@ -47,24 +47,14 @@ export default function OAuth() {
|
|||
stuck.
|
||||
</p>
|
||||
|
||||
<ul className="mt-4 list-disc ml-4">
|
||||
<ul className="mt-4 ml-4 list-disc">
|
||||
<li>
|
||||
Try connecting this account on a desktop
|
||||
device. We have a mobile app on our roadmap,
|
||||
but for the time being, desktop browsers
|
||||
will be your most reliable experience.
|
||||
</li>
|
||||
<li>
|
||||
Still not working?{' '}
|
||||
<button
|
||||
onClick={() =>
|
||||
BrowserUtil.showIntercom()
|
||||
}
|
||||
className="underline text-cyan"
|
||||
>
|
||||
Let us know!
|
||||
</button>
|
||||
</li>
|
||||
<li>Still not working? Let us know!</li>
|
||||
</ul>
|
||||
</Disclosure.Panel>
|
||||
</Transition>
|
||||
|
|
|
@ -145,19 +145,6 @@ router.get(
|
|||
})
|
||||
)
|
||||
|
||||
router.get(
|
||||
'/intercom',
|
||||
endpoint.create({
|
||||
resolve: async ({ ctx }) => {
|
||||
if (!ctx.user || !ctx.user.id) {
|
||||
throw new Error('User not found')
|
||||
}
|
||||
|
||||
return ctx.userService.getIntercomMetadata(ctx.user.id, env.NX_INTERCOM_SECRET)
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
router.put(
|
||||
'/',
|
||||
endpoint.create({
|
||||
|
|
|
@ -67,25 +67,13 @@ const envSchema = z.object({
|
|||
.string()
|
||||
.default(process.env.NODE_ENV === 'development' ? 'dev' : 'combined'),
|
||||
|
||||
NX_INTERCOM_SECRET: z.string().optional(),
|
||||
|
||||
NX_STRIPE_SECRET_KEY: z
|
||||
.string()
|
||||
.default(
|
||||
'REPLACE_THIS'
|
||||
),
|
||||
NX_STRIPE_WEBHOOK_SECRET: z
|
||||
.string()
|
||||
.default('whsec_REPLACE_THIS'),
|
||||
NX_STRIPE_SECRET_KEY: z.string().default('REPLACE_THIS'),
|
||||
NX_STRIPE_WEBHOOK_SECRET: z.string().default('whsec_REPLACE_THIS'),
|
||||
NX_STRIPE_PREMIUM_MONTHLY_PRICE_ID: z.string().default('price_REPLACE_THIS'),
|
||||
NX_STRIPE_PREMIUM_YEARLY_PRICE_ID: z.string().default('price_REPLACE_THIS'),
|
||||
|
||||
NX_CDN_PRIVATE_BUCKET: z
|
||||
.string()
|
||||
.default('REPLACE_THIS'),
|
||||
NX_CDN_PUBLIC_BUCKET: z
|
||||
.string()
|
||||
.default('REPLACE_THIS'),
|
||||
NX_CDN_PRIVATE_BUCKET: z.string().default('REPLACE_THIS'),
|
||||
NX_CDN_PUBLIC_BUCKET: z.string().default('REPLACE_THIS'),
|
||||
|
||||
// Key to secrets manager value
|
||||
NX_CDN_SIGNER_SECRET_ID: z.string().default('/apps/maybe-app/CLOUDFRONT_SIGNER1_PRIV'),
|
||||
|
|
|
@ -179,15 +179,6 @@ export class ServerStack extends Stack {
|
|||
}
|
||||
)
|
||||
),
|
||||
NX_INTERCOM_SECRET: ECSSecret.fromSsmParameter(
|
||||
StringParameter.fromSecureStringParameterAttributes(
|
||||
this,
|
||||
'IntercomSecretParam',
|
||||
{
|
||||
parameterName: '/providers/NX_INTERCOM_SECRET',
|
||||
}
|
||||
)
|
||||
),
|
||||
NX_STRIPE_SECRET_KEY: ECSSecret.fromSsmParameter(
|
||||
StringParameter.fromSecureStringParameterAttributes(
|
||||
this,
|
||||
|
|
|
@ -24,11 +24,11 @@ type DescriptionProps = {
|
|||
|
||||
function Description({ summary, examples }: DescriptionProps) {
|
||||
return (
|
||||
<div className="text-gray-50 text-base mt-2">
|
||||
<div className="mt-2 text-base text-gray-50">
|
||||
<p className="mb-4">{summary}</p>
|
||||
<ul>
|
||||
{examples.map((example) => (
|
||||
<li key={example} className="list-disc ml-6">
|
||||
<li key={example} className="ml-6 list-disc">
|
||||
{example}
|
||||
</li>
|
||||
))}
|
||||
|
@ -123,7 +123,7 @@ export function SidebarOnboarding({ onClose, onHide }: Props) {
|
|||
|
||||
if (onboarding.isLoading) {
|
||||
return (
|
||||
<div className="w-full flex justify-center items-center h-full">
|
||||
<div className="flex items-center justify-center w-full h-full">
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
)
|
||||
|
@ -196,7 +196,7 @@ export function SidebarOnboarding({ onClose, onHide }: Props) {
|
|||
initial={{ width: 0 }}
|
||||
animate={{ width: `${syncProgress.progress * 100}%` }}
|
||||
transition={{ ease: 'easeOut', duration: 0.5 }}
|
||||
className="h-full rounded-full bg-gray-100"
|
||||
className="h-full bg-gray-100 rounded-full"
|
||||
></motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
|
@ -225,7 +225,7 @@ export function SidebarOnboarding({ onClose, onHide }: Props) {
|
|||
</div>
|
||||
<div className="relative h-2 bg-gray-600 rounded-sm">
|
||||
<div
|
||||
className="absolute inset-0 bg-cyan h-2 rounded-sm"
|
||||
className="absolute inset-0 h-2 rounded-sm bg-cyan"
|
||||
style={{
|
||||
width: `${percent * 100}%`,
|
||||
}}
|
||||
|
@ -233,7 +233,7 @@ export function SidebarOnboarding({ onClose, onHide }: Props) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-start gap-2 text-base pr-4 -mr-4 custom-gray-scroll">
|
||||
<div className="flex flex-col items-start gap-2 pr-4 -mr-4 text-base custom-gray-scroll">
|
||||
{accountSteps.map((step, idx) => {
|
||||
const description = getDescriptionComponent(step.key)
|
||||
|
||||
|
@ -252,7 +252,7 @@ export function SidebarOnboarding({ onClose, onHide }: Props) {
|
|||
open ? 'text-white' : 'text-gray-100'
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center text-left leading-5 gap-3 mr-auto">
|
||||
<div className="flex items-center gap-3 mr-auto leading-5 text-left">
|
||||
<div
|
||||
className={classNames(
|
||||
'rounded-full w-[28px] h-[28px] flex items-center justify-center shrink-0',
|
||||
|
@ -264,7 +264,7 @@ export function SidebarOnboarding({ onClose, onHide }: Props) {
|
|||
{step.isComplete || step.isMarkedComplete ? (
|
||||
<RiCheckFill size={20} className="text-cyan" />
|
||||
) : (
|
||||
<span className="font-medium text-sm">
|
||||
<span className="text-sm font-medium">
|
||||
{idx + 1}
|
||||
</span>
|
||||
)}
|
||||
|
@ -306,7 +306,7 @@ export function SidebarOnboarding({ onClose, onHide }: Props) {
|
|||
<div className="bg-gray-600 my-4 h-[1px]"></div>
|
||||
|
||||
{step.isComplete ? (
|
||||
<p className="text-gray-50 text-sm">
|
||||
<p className="text-sm text-gray-50">
|
||||
This step has been automatically marked complete
|
||||
since you've added at least 1 of these account
|
||||
types.
|
||||
|
@ -354,7 +354,7 @@ export function SidebarOnboarding({ onClose, onHide }: Props) {
|
|||
<Disclosure defaultOpen>
|
||||
{({ open }) => (
|
||||
<div className={classNames('p-3 rounded-lg bg-grape bg-opacity-10 text-base')}>
|
||||
<Disclosure.Button className="flex items-center gap-2 text-grape w-full font-medium">
|
||||
<Disclosure.Button className="flex items-center w-full gap-2 font-medium text-grape">
|
||||
<HiOutlineSparkles size={24} />
|
||||
<span className="mr-auto">Bonus</span>
|
||||
{open ? <RiArrowUpSFill size={18} /> : <RiArrowDownSFill size={18} />}
|
||||
|
@ -399,13 +399,7 @@ export function SidebarOnboarding({ onClose, onHide }: Props) {
|
|||
</Disclosure>
|
||||
|
||||
<p className="text-sm text-gray-100">
|
||||
If you have any issues with connecting accounts, please let us know{' '}
|
||||
<button
|
||||
onClick={() => BrowserUtil.showIntercom()}
|
||||
className="text-cyan cursor-pointer hover:underline"
|
||||
>
|
||||
via live chat
|
||||
</button>
|
||||
If you have any issues with connecting accounts, please let us know.
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -126,9 +126,9 @@ function PromptStep({
|
|||
<>
|
||||
<BoxIcon icon={RiLink} />
|
||||
|
||||
<h4 className="text-white mt-6 mb-2">Link accounts?</h4>
|
||||
<h4 className="mt-6 mb-2 text-white">Link accounts?</h4>
|
||||
|
||||
<p className="mb-6 text-gray-50 text-base">
|
||||
<p className="mb-6 text-base text-gray-50">
|
||||
We found an {secondaryProvider === 'apple' ? 'Apple ' : ' '} account using the same
|
||||
email address as this one in our system. Do you want to link it?
|
||||
</p>
|
||||
|
@ -140,7 +140,7 @@ function PromptStep({
|
|||
{secondaryProvider === 'apple' ? (
|
||||
<button
|
||||
onClick={onNext}
|
||||
className="w-2/4 flex items-center px-4 py-2 rounded text-base bg-white text-black shadow hover:bg-gray-25 focus:bg-gray-25 focus:ring-gray-600 font-medium"
|
||||
className="flex items-center w-2/4 px-4 py-2 text-base font-medium text-black bg-white rounded shadow hover:bg-gray-25 focus:bg-gray-25 focus:ring-gray-600"
|
||||
>
|
||||
<RiAppleFill className="w-4 h-4 mx-2" /> Link with Apple
|
||||
</button>
|
||||
|
@ -165,7 +165,7 @@ function ConfirmStep({
|
|||
<>
|
||||
<BoxIcon icon={RiLink} />
|
||||
|
||||
<h4 className="text-white my-6 animate-pulse">Authentication in progress...</h4>
|
||||
<h4 className="my-6 text-white animate-pulse">Authentication in progress...</h4>
|
||||
|
||||
<Button fullWidth variant="secondary" onClick={onCancel}>
|
||||
Cancel
|
||||
|
@ -178,7 +178,7 @@ function ConfirmStep({
|
|||
<>
|
||||
<BoxIcon icon={isLoading ? RiLinkUnlink : RiLink} />
|
||||
|
||||
<h4 className="text-white mt-6 mb-2">
|
||||
<h4 className="mt-6 mb-2 text-white">
|
||||
{isLoading ? 'Linking accounts ...' : 'Continue linking accounts?'}
|
||||
</h4>
|
||||
|
||||
|
@ -198,7 +198,7 @@ function ConfirmStep({
|
|||
process by unlinking the account in your settings.{' '}
|
||||
</p>
|
||||
|
||||
<p className="text-white mt-4">No data will be deleted.</p>
|
||||
<p className="mt-4 text-white">No data will be deleted.</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
@ -229,9 +229,9 @@ function LinkComplete({ onClose }: { onClose(): void }) {
|
|||
<>
|
||||
<BoxIcon icon={RiCheckLine} variant="teal" />
|
||||
|
||||
<h4 className="text-white mt-6 mb-2">Accounts linked successfully!</h4>
|
||||
<h4 className="mt-6 mb-2 text-white">Accounts linked successfully!</h4>
|
||||
|
||||
<p className="mb-6 text-gray-50 text-base">
|
||||
<p className="mb-6 text-base text-gray-50">
|
||||
Your accounts have been linked and the data has been merged successfully.
|
||||
</p>
|
||||
|
||||
|
@ -249,16 +249,11 @@ function LinkError({ onClose, error }: { onClose(): void; error: string }) {
|
|||
<>
|
||||
<BoxIcon icon={RiLink} variant="red" />
|
||||
|
||||
<h4 className="text-white mt-6 mb-2">Account linking failed</h4>
|
||||
<h4 className="mt-6 mb-2 text-white">Account linking failed</h4>
|
||||
|
||||
<p className="mb-2 text-gray-50 text-base">{error}</p>
|
||||
<p className="mb-2 text-base text-gray-50">{error}</p>
|
||||
|
||||
<button
|
||||
className="underline text-cyan text-base mb-6"
|
||||
onClick={BrowserUtil.showIntercom}
|
||||
>
|
||||
Please contact us.
|
||||
</button>
|
||||
<button className="mb-6 text-base underline text-cyan">Please contact us.</button>
|
||||
|
||||
<div className="flex w-full gap-4">
|
||||
<Button fullWidth onClick={onClose}>
|
||||
|
|
|
@ -11,7 +11,7 @@ import { useMemo } from 'react'
|
|||
import sumBy from 'lodash/sumBy'
|
||||
import toast from 'react-hot-toast'
|
||||
import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useAxiosWithAuth, useIntercom } from '..'
|
||||
import { useAxiosWithAuth } from '..'
|
||||
import { invalidateAccountQueries } from '../utils'
|
||||
|
||||
const AccountApi = (axios: AxiosInstance) => ({
|
||||
|
@ -135,33 +135,6 @@ export function useAccountApi() {
|
|||
const queryClient = useQueryClient()
|
||||
const { axios } = useAxiosWithAuth()
|
||||
const api = useMemo(() => AccountApi(axios), [axios])
|
||||
const { update: updateIntercom } = useIntercom()
|
||||
|
||||
const useAccounts = (
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
SharedType.AccountsResponse,
|
||||
unknown,
|
||||
SharedType.AccountsResponse,
|
||||
string[]
|
||||
>,
|
||||
'queryKey' | 'queryFn' | 'staleTime'
|
||||
>
|
||||
) =>
|
||||
useQuery(['accounts'], api.getAccounts, {
|
||||
staleTime: staleTimes.accounts,
|
||||
onSuccess: (...args) => {
|
||||
if (options?.onSuccess) options.onSuccess(...args)
|
||||
|
||||
const [{ accounts, connections }] = args
|
||||
updateIntercom({
|
||||
'Manual Accounts': accounts.length,
|
||||
'Connected Accounts': sumBy(connections, (c) => c.accounts.length),
|
||||
Connections: connections.length,
|
||||
})
|
||||
},
|
||||
...options,
|
||||
})
|
||||
|
||||
const useAccount = (
|
||||
id: Account['id'],
|
||||
|
|
|
@ -38,11 +38,6 @@ const UserApi = (
|
|||
return data
|
||||
},
|
||||
|
||||
async getIntercomMetadata() {
|
||||
const { data } = await axios.get<SharedType.UserIntercomMetadata>('/users/intercom')
|
||||
return data
|
||||
},
|
||||
|
||||
async update(userData: SharedType.UpdateUser) {
|
||||
const { data } = await axios.put<SharedType.User>('/users', userData)
|
||||
return data
|
||||
|
@ -254,22 +249,6 @@ export function useUserApi() {
|
|||
staleTime: staleTimes.insights,
|
||||
})
|
||||
|
||||
const useIntercomMetadata = (
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
SharedType.UserIntercomMetadata,
|
||||
unknown,
|
||||
SharedType.UserIntercomMetadata,
|
||||
any[]
|
||||
>,
|
||||
'queryKey' | 'queryFn'
|
||||
>
|
||||
) =>
|
||||
useQuery(['users', 'intercom-metadata'], api.getIntercomMetadata, {
|
||||
refetchOnWindowFocus: false,
|
||||
...options,
|
||||
})
|
||||
|
||||
const useProfile = (
|
||||
options?: Omit<
|
||||
UseQueryOptions<SharedType.User, unknown, SharedType.User, any[]>,
|
||||
|
@ -471,7 +450,6 @@ export function useUserApi() {
|
|||
useNetWorthSeries,
|
||||
useInsights,
|
||||
useCurrentNetWorth,
|
||||
useIntercomMetadata,
|
||||
useProfile,
|
||||
useUpdateProfile,
|
||||
useAuth0Profile,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
export * from './useAxiosWithAuth'
|
||||
export * from './useDebounce'
|
||||
export * from './useFinicity'
|
||||
export * from './useIntercom'
|
||||
export * from './useInterval'
|
||||
export * from './useLastUpdated'
|
||||
export * from './useLocalStorage'
|
||||
|
|
|
@ -35,9 +35,6 @@ export function useFinicity() {
|
|||
FinicityConnect.launch(link, {
|
||||
onDone(evt: ConnectDoneEvent) {
|
||||
logger.debug(`Finicity Connect onDone event`, evt)
|
||||
BrowserUtil.trackIntercomEvent('FINICITY_CONNECT_DONE', {
|
||||
...evt,
|
||||
})
|
||||
setExpectingAccounts(true)
|
||||
},
|
||||
onError(evt: ConnectErrorEvent) {
|
||||
|
@ -50,25 +47,15 @@ export function useFinicity() {
|
|||
'finicity.error.reason': evt.reason,
|
||||
},
|
||||
})
|
||||
BrowserUtil.trackIntercomEvent('FINICITY_CONNECT_ERROR', {
|
||||
...evt,
|
||||
})
|
||||
},
|
||||
onCancel(evt: ConnectCancelEvent) {
|
||||
logger.debug(`Finicity Connect onCancel event`, evt)
|
||||
BrowserUtil.trackIntercomEvent('FINICITY_CONNECT_CANCEL', {
|
||||
...evt,
|
||||
})
|
||||
},
|
||||
onUser(evt: any) {
|
||||
BrowserUtil.trackIntercomEvent('FINICITY_CONNECT_USER_ACTION', {
|
||||
...evt,
|
||||
})
|
||||
//Nothing
|
||||
},
|
||||
onRoute(evt: ConnectRouteEvent) {
|
||||
BrowserUtil.trackIntercomEvent('FINICITY_CONNECT_ROUTE_EVENT', {
|
||||
...evt,
|
||||
})
|
||||
//Nothing
|
||||
},
|
||||
})
|
||||
},
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
import { useCallback } from 'react'
|
||||
import { useAuth0 } from '@auth0/auth0-react'
|
||||
import type { SharedType } from '@maybe-finance/shared'
|
||||
import { useUserApi } from '../api'
|
||||
import { BrowserUtil } from '..'
|
||||
|
||||
export function useIntercom() {
|
||||
const { user, isAuthenticated } = useAuth0<SharedType.Auth0ReactUser>()
|
||||
|
||||
const { useIntercomMetadata } = useUserApi()
|
||||
const { data: intercomMetadata } = useIntercomMetadata({ enabled: isAuthenticated })
|
||||
|
||||
const boot = useCallback(
|
||||
(data?: BrowserUtil.IntercomData) => {
|
||||
if (!user?.sub || !intercomMetadata?.hash) return false
|
||||
|
||||
BrowserUtil.bootIntercom({
|
||||
user_id: user.sub,
|
||||
user_hash: intercomMetadata.hash,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
last_request_at: Math.floor(new Date().getTime() / 1000),
|
||||
...data,
|
||||
})
|
||||
|
||||
return true
|
||||
},
|
||||
[user, intercomMetadata]
|
||||
)
|
||||
|
||||
const update = useCallback(
|
||||
(data?: BrowserUtil.IntercomData, updateLastRequestAt = true) => {
|
||||
if (!user?.sub || !intercomMetadata?.hash) return
|
||||
|
||||
BrowserUtil.updateIntercom({
|
||||
user_id: user.sub,
|
||||
user_hash: intercomMetadata.hash,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
last_request_at: updateLastRequestAt
|
||||
? Math.floor(new Date().getTime() / 1000)
|
||||
: undefined,
|
||||
...data,
|
||||
})
|
||||
},
|
||||
[user, intercomMetadata]
|
||||
)
|
||||
|
||||
return { boot, update }
|
||||
}
|
|
@ -69,21 +69,7 @@ export function usePlaid(mode: 'default' | 'oauth' = 'default') {
|
|||
},
|
||||
// https://plaid.com/docs/link/web/#onexit
|
||||
onExit: (error, metadata) => {
|
||||
if (error) {
|
||||
const { error_code, error_type, error_message, display_message } = error
|
||||
BrowserUtil.trackIntercomEvent(`PLAID_LINK_EXIT_ERROR`, {
|
||||
error_type,
|
||||
error_code,
|
||||
error_message,
|
||||
display_message,
|
||||
reference: 'https://plaid.com/docs/errors/',
|
||||
})
|
||||
}
|
||||
|
||||
BrowserUtil.trackIntercomEvent('PLAID_EXIT_EVENT', {
|
||||
...error,
|
||||
...metadata,
|
||||
})
|
||||
//Nothing
|
||||
},
|
||||
// https://plaid.com/docs/link/web/#onevent
|
||||
onEvent: (event, metadata) => {
|
||||
|
@ -97,9 +83,6 @@ export function usePlaid(mode: 'default' | 'oauth' = 'default') {
|
|||
},
|
||||
})
|
||||
|
||||
// Capture all events to Intercom
|
||||
BrowserUtil.trackIntercomEvent(event, metadata)
|
||||
|
||||
logger.debug(
|
||||
`Plaid link event: ${event} for session ID ${metadata.link_session_id}`,
|
||||
metadata
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export * from './image-loaders'
|
||||
export * from './intercom'
|
||||
export * from './browser-utils'
|
||||
export * from './account-utils'
|
||||
export * from './agreement-utils'
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
export type IntercomData = {
|
||||
user_id?: string
|
||||
user_hash?: string
|
||||
email?: string
|
||||
name?: string
|
||||
|
||||
last_request_at?: number
|
||||
|
||||
'Manual Accounts'?: number
|
||||
'Connected Accounts'?: number
|
||||
Connections?: number
|
||||
}
|
||||
|
||||
export function bootIntercom(data?: IntercomData) {
|
||||
const w = window as any
|
||||
w.Intercom('boot', {
|
||||
app_id: w.INTERCOM_APP_ID,
|
||||
...data,
|
||||
})
|
||||
}
|
||||
|
||||
export function updateIntercom(data?: IntercomData) {
|
||||
;(window as any).Intercom('update', {
|
||||
...data,
|
||||
})
|
||||
}
|
||||
|
||||
export function trackIntercomEvent(name: string, data: Record<string, any>) {
|
||||
;(window as any).Intercom('trackEvent', name, {
|
||||
...data,
|
||||
})
|
||||
}
|
||||
|
||||
export function showIntercom() {
|
||||
;(window as any).Intercom('show')
|
||||
}
|
|
@ -280,22 +280,6 @@ export class UserService implements IUserService {
|
|||
}
|
||||
}
|
||||
|
||||
async getIntercomMetadata(
|
||||
userId: User['id'],
|
||||
secret?: string
|
||||
): Promise<SharedType.UserIntercomMetadata> {
|
||||
const { auth0Id } = await this.prisma.user.findUniqueOrThrow({
|
||||
select: { auth0Id: true },
|
||||
where: { id: userId },
|
||||
})
|
||||
|
||||
return {
|
||||
hash: secret
|
||||
? crypto.createHmac('sha256', secret).update(auth0Id).digest('hex')
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
async getSignedAgreements(userId: User['id']) {
|
||||
return this.prisma.agreement.findMany({
|
||||
distinct: 'type',
|
||||
|
|
|
@ -227,10 +227,6 @@ export type UserSubscription = {
|
|||
currentPeriodEnd: DateTime | null
|
||||
}
|
||||
|
||||
export type UserIntercomMetadata = {
|
||||
hash?: string
|
||||
}
|
||||
|
||||
export type UserMemberCardDetails = {
|
||||
memberNumber: number
|
||||
name: string
|
||||
|
|
25
prisma/migrations/20240111053307_fork/migration.sql
Normal file
25
prisma/migrations/20240111053307_fork/migration.sql
Normal file
|
@ -0,0 +1,25 @@
|
|||
-- DropIndex
|
||||
DROP INDEX "account_balance_date_idx";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "security_pricing_date_idx";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "account" ALTER COLUMN "category" DROP DEFAULT,
|
||||
ALTER COLUMN "classification" DROP DEFAULT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "investment_transaction" ALTER COLUMN "flow" DROP DEFAULT,
|
||||
ALTER COLUMN "category" DROP DEFAULT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "transaction" ALTER COLUMN "flow" DROP DEFAULT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "user" ALTER COLUMN "trial_end" SET DEFAULT NOW() + interval '14 days';
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "account_balance_date_idx" ON "account_balance"("date");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "security_pricing_date_idx" ON "security_pricing"("date");
|
70
yarn.lock
70
yarn.lock
|
@ -7707,7 +7707,7 @@ async@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
|
||||
integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
|
||||
|
||||
async@^3.1.0, async@^3.2.0, async@^3.2.3:
|
||||
async@^3.2.0, async@^3.2.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9"
|
||||
integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==
|
||||
|
@ -8072,7 +8072,7 @@ balanced-match@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1:
|
||||
base64-js@^1.0.2, base64-js@^1.3.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
|
@ -9046,7 +9046,7 @@ clone-response@^1.0.2:
|
|||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
clone@2.x, clone@^2.1.2:
|
||||
clone@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
|
||||
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
|
||||
|
@ -11472,11 +11472,6 @@ extsprintf@^1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
|
||||
integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
|
||||
|
||||
fast-deep-equal@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
|
||||
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
|
@ -14694,51 +14689,6 @@ language-tags@^1.0.5:
|
|||
dependencies:
|
||||
language-subtag-registry "~0.3.2"
|
||||
|
||||
launchdarkly-eventsource@1.4.4:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/launchdarkly-eventsource/-/launchdarkly-eventsource-1.4.4.tgz#fa595af8602e487c61520787170376c6a1104459"
|
||||
integrity sha512-GL+r2Y3WccJlhFyL2buNKel+9VaMnYpbE/FfCkOST5jSNSFodahlxtGyrE8o7R+Qhobyq0Ree4a7iafJDQi9VQ==
|
||||
|
||||
launchdarkly-js-client-sdk@2.20.2:
|
||||
version "2.20.2"
|
||||
resolved "https://registry.yarnpkg.com/launchdarkly-js-client-sdk/-/launchdarkly-js-client-sdk-2.20.2.tgz#4c5a72cc8e2d0b5dbb3d4dd31a30e36b243b9e8f"
|
||||
integrity sha512-KAAb1nnpAiQF4dCohe0d1M7QSxhJfa9v6+5PJUPANAVZ3EwX/y6aL7mK8Mik2IrL5I654mseXxidfSbnHVMBXA==
|
||||
dependencies:
|
||||
escape-string-regexp "^1.0.5"
|
||||
launchdarkly-js-sdk-common "3.5.1"
|
||||
|
||||
launchdarkly-js-sdk-common@3.5.1:
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/launchdarkly-js-sdk-common/-/launchdarkly-js-sdk-common-3.5.1.tgz#25966a5b25311bba4db7c9f3807031166b97545d"
|
||||
integrity sha512-MTIn5XkREKCb87A78QTQXNEPaDaC35PzW1mU8bTf1hdxgm78LiDtXjvtKvVk+oU5tqFrH7dZrLKMCGkt03VaKw==
|
||||
dependencies:
|
||||
base64-js "^1.3.0"
|
||||
fast-deep-equal "^2.0.1"
|
||||
uuid "^3.3.2"
|
||||
|
||||
launchdarkly-node-server-sdk@^6.4.3:
|
||||
version "6.4.3"
|
||||
resolved "https://registry.yarnpkg.com/launchdarkly-node-server-sdk/-/launchdarkly-node-server-sdk-6.4.3.tgz#7a35caee3709d70776173fcd814fa0cd88de1270"
|
||||
integrity sha512-n7L2mAAcKqUUKhCGHRd6soVD3Ws4ME4R+MNShWL0lBBY8yGASIaPAW4rGmkob/hs+grCNRXn8HHlZCufecaX4w==
|
||||
dependencies:
|
||||
async "^3.1.0"
|
||||
launchdarkly-eventsource "1.4.4"
|
||||
lru-cache "^6.0.0"
|
||||
node-cache "^5.1.0"
|
||||
semver "^7.3.0"
|
||||
tunnel "0.0.6"
|
||||
uuid "^8.3.2"
|
||||
|
||||
launchdarkly-react-client-sdk@^2.25.1:
|
||||
version "2.25.1"
|
||||
resolved "https://registry.yarnpkg.com/launchdarkly-react-client-sdk/-/launchdarkly-react-client-sdk-2.25.1.tgz#fdfbb532e239227e1f64efa1dccff42ae0ce5533"
|
||||
integrity sha512-OejNEZs8QvW1q/qn/ey1o6lfdLw3aW8tWfLucUmRTeazp0MtBXARnEZoqHWGmgRkRlxkTul3HqecksnoXC/wBg==
|
||||
dependencies:
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
launchdarkly-js-client-sdk "2.20.2"
|
||||
lodash.camelcase "^4.3.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
lazy-ass@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513"
|
||||
|
@ -15968,13 +15918,6 @@ node-addon-api@^3.2.1:
|
|||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161"
|
||||
integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==
|
||||
|
||||
node-cache@^5.1.0:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d"
|
||||
integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==
|
||||
dependencies:
|
||||
clone "2.x"
|
||||
|
||||
node-dir@^0.1.10:
|
||||
version "0.1.17"
|
||||
resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5"
|
||||
|
@ -18989,7 +18932,7 @@ semver@7.3.4:
|
|||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@7.x, semver@^7.3.0:
|
||||
semver@7.x:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
|
@ -20565,11 +20508,6 @@ tunnel-agent@^0.6.0:
|
|||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tunnel@0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
|
||||
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue