feat: add survey popup for survey monkey (#3116)
* add survey popup for survey monkey * update useEffect and add 24 hour window * upate % logic * update logic to show after duration * update timestamp conditional * small changes
This commit is contained in:
parent
5d97cbf6ad
commit
1b10c88c51
9
src/assets/images/survey-orb.svg
Normal file
9
src/assets/images/survey-orb.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 572 KiB |
106
src/components/Popups/SurveyPopup.tsx
Normal file
106
src/components/Popups/SurveyPopup.tsx
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { Trans } from '@lingui/macro'
|
||||||
|
import { AutoColumn } from 'components/Column'
|
||||||
|
import { RowFixed } from 'components/Row'
|
||||||
|
import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { MessageCircle, X } from 'react-feather'
|
||||||
|
import ReactGA from 'react-ga'
|
||||||
|
import { useShowSurveyPopup } from 'state/user/hooks'
|
||||||
|
import styled from 'styled-components/macro'
|
||||||
|
import { ExternalLink, ThemedText, Z_INDEX } from 'theme'
|
||||||
|
|
||||||
|
import BGImage from '../../assets/images/survey-orb.svg'
|
||||||
|
import useTheme from '../../hooks/useTheme'
|
||||||
|
|
||||||
|
const Wrapper = styled(AutoColumn)`
|
||||||
|
background: #edeef2;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 18px;
|
||||||
|
max-width: 360px;
|
||||||
|
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
color: ${({ theme }) => theme.text1};
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
${({ theme }) => theme.mediaWidth.upToSmall`
|
||||||
|
max-width: 100%;
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
|
||||||
|
const BGOrb = styled.img`
|
||||||
|
position: absolute;
|
||||||
|
right: -64px;
|
||||||
|
top: -64px;
|
||||||
|
width: 180px;
|
||||||
|
z-index: ${Z_INDEX.sticky};
|
||||||
|
`
|
||||||
|
|
||||||
|
const WrappedCloseIcon = styled(X)`
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
stroke: #7c7c80;
|
||||||
|
z-index: ${Z_INDEX.fixed};
|
||||||
|
:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const END_TIMESTAMP = 1642215971 // Jan 15th
|
||||||
|
|
||||||
|
export default function SurveyPopup() {
|
||||||
|
const theme = useTheme()
|
||||||
|
const [showPopup, setShowSurveyPopup] = useShowSurveyPopup()
|
||||||
|
|
||||||
|
// show popup to 1% of users
|
||||||
|
useEffect(() => {
|
||||||
|
// has not visited page during A/B testing if undefined
|
||||||
|
if (showPopup === undefined) {
|
||||||
|
if (Math.random() < 0.01) {
|
||||||
|
setShowSurveyPopup(true)
|
||||||
|
// log a case of succesful view
|
||||||
|
ReactGA.event({
|
||||||
|
category: 'Survey',
|
||||||
|
action: 'Saw Survey',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [setShowSurveyPopup, showPopup])
|
||||||
|
|
||||||
|
// limit survey to 24 hours based on timestamps
|
||||||
|
const timestamp = useCurrentBlockTimestamp()
|
||||||
|
const durationOver = timestamp ? timestamp.toNumber() > END_TIMESTAMP : false
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{!showPopup || durationOver ? null : (
|
||||||
|
<Wrapper gap="10px">
|
||||||
|
<WrappedCloseIcon
|
||||||
|
onClick={() => {
|
||||||
|
ReactGA.event({
|
||||||
|
category: 'Survey',
|
||||||
|
action: 'Clicked Survey Link',
|
||||||
|
})
|
||||||
|
setShowSurveyPopup(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<BGOrb src={BGImage} />
|
||||||
|
<ExternalLink href="https://www.surveymonkey.com/r/YGWV9VD">
|
||||||
|
<RowFixed>
|
||||||
|
<MessageCircle stroke={theme.black} size="20px" strokeWidth="1px" />
|
||||||
|
<ThemedText.White fontWeight={600} color={theme.black} ml="6px">
|
||||||
|
<Trans>Tell us what you think ↗</Trans>
|
||||||
|
</ThemedText.White>
|
||||||
|
</RowFixed>
|
||||||
|
</ExternalLink>
|
||||||
|
<ThemedText.Black style={{ zIndex: Z_INDEX.fixed }} fontWeight={400} fontSize="12px" color={theme.black}>
|
||||||
|
<Trans>Take a 10 minute survey to help us improve your experience in the Uniswap app.</Trans>
|
||||||
|
</ThemedText.Black>
|
||||||
|
</Wrapper>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -4,10 +4,11 @@ import styled from 'styled-components/macro'
|
|||||||
import { MEDIA_WIDTHS } from 'theme'
|
import { MEDIA_WIDTHS } from 'theme'
|
||||||
|
|
||||||
import { useActivePopups } from '../../state/application/hooks'
|
import { useActivePopups } from '../../state/application/hooks'
|
||||||
import { useURLWarningVisible } from '../../state/user/hooks'
|
import { useShowSurveyPopup, useURLWarningVisible } from '../../state/user/hooks'
|
||||||
import { AutoColumn } from '../Column'
|
import { AutoColumn } from '../Column'
|
||||||
import ClaimPopup from './ClaimPopup'
|
import ClaimPopup from './ClaimPopup'
|
||||||
import PopupItem from './PopupItem'
|
import PopupItem from './PopupItem'
|
||||||
|
import SurveyPopup from './SurveyPopup'
|
||||||
|
|
||||||
const MobilePopupWrapper = styled.div<{ height: string | number }>`
|
const MobilePopupWrapper = styled.div<{ height: string | number }>`
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -59,6 +60,9 @@ export default function Popups() {
|
|||||||
// get all popups
|
// get all popups
|
||||||
const activePopups = useActivePopups()
|
const activePopups = useActivePopups()
|
||||||
|
|
||||||
|
// show survey popup if user has not closed
|
||||||
|
const [showSurveyPopup] = useShowSurveyPopup()
|
||||||
|
|
||||||
const urlWarningActive = useURLWarningVisible()
|
const urlWarningActive = useURLWarningVisible()
|
||||||
|
|
||||||
// need extra padding if network is not L1 Ethereum
|
// need extra padding if network is not L1 Ethereum
|
||||||
@ -69,12 +73,14 @@ export default function Popups() {
|
|||||||
<>
|
<>
|
||||||
<FixedPopupColumn gap="20px" extraPadding={urlWarningActive} xlPadding={isNotOnMainnet}>
|
<FixedPopupColumn gap="20px" extraPadding={urlWarningActive} xlPadding={isNotOnMainnet}>
|
||||||
<ClaimPopup />
|
<ClaimPopup />
|
||||||
|
<SurveyPopup />
|
||||||
{activePopups.map((item) => (
|
{activePopups.map((item) => (
|
||||||
<PopupItem key={item.key} content={item.content} popKey={item.key} removeAfterMs={item.removeAfterMs} />
|
<PopupItem key={item.key} content={item.content} popKey={item.key} removeAfterMs={item.removeAfterMs} />
|
||||||
))}
|
))}
|
||||||
</FixedPopupColumn>
|
</FixedPopupColumn>
|
||||||
<MobilePopupWrapper height={activePopups?.length > 0 ? 'fit-content' : 0}>
|
<MobilePopupWrapper height={activePopups?.length > 0 || showSurveyPopup ? 'fit-content' : 0}>
|
||||||
<MobilePopupInner>
|
<MobilePopupInner>
|
||||||
|
<SurveyPopup />
|
||||||
{activePopups // reverse so new items up front
|
{activePopups // reverse so new items up front
|
||||||
.slice(0)
|
.slice(0)
|
||||||
.reverse()
|
.reverse()
|
||||||
|
@ -18,6 +18,7 @@ export const updateMatchesDarkMode = createAction<{ matchesDarkMode: boolean }>(
|
|||||||
export const updateUserDarkMode = createAction<{ userDarkMode: boolean }>('user/updateUserDarkMode')
|
export const updateUserDarkMode = createAction<{ userDarkMode: boolean }>('user/updateUserDarkMode')
|
||||||
export const updateUserExpertMode = createAction<{ userExpertMode: boolean }>('user/updateUserExpertMode')
|
export const updateUserExpertMode = createAction<{ userExpertMode: boolean }>('user/updateUserExpertMode')
|
||||||
export const updateUserLocale = createAction<{ userLocale: SupportedLocale }>('user/updateUserLocale')
|
export const updateUserLocale = createAction<{ userLocale: SupportedLocale }>('user/updateUserLocale')
|
||||||
|
export const updateShowSurveyPopup = createAction<{ showSurveyPopup: boolean }>('user/updateShowSurveyPopup')
|
||||||
export const updateUserClientSideRouter = createAction<{ userClientSideRouter: boolean }>(
|
export const updateUserClientSideRouter = createAction<{ userClientSideRouter: boolean }>(
|
||||||
'user/updateUserClientSideRouter'
|
'user/updateUserClientSideRouter'
|
||||||
)
|
)
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
SerializedPair,
|
SerializedPair,
|
||||||
SerializedToken,
|
SerializedToken,
|
||||||
updateHideClosedPositions,
|
updateHideClosedPositions,
|
||||||
|
updateShowSurveyPopup,
|
||||||
updateUserClientSideRouter,
|
updateUserClientSideRouter,
|
||||||
updateUserDarkMode,
|
updateUserDarkMode,
|
||||||
updateUserDeadline,
|
updateUserDeadline,
|
||||||
@ -104,6 +105,18 @@ export function useExpertModeManager(): [boolean, () => void] {
|
|||||||
return [expertMode, toggleSetExpertMode]
|
return [expertMode, toggleSetExpertMode]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useShowSurveyPopup(): [boolean | undefined, (showPopup: boolean) => void] {
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
const showSurveyPopup = useAppSelector((state) => state.user.showSurveyPopup)
|
||||||
|
const toggleShowSurveyPopup = useCallback(
|
||||||
|
(showPopup: boolean) => {
|
||||||
|
dispatch(updateShowSurveyPopup({ showSurveyPopup: showPopup }))
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
)
|
||||||
|
return [showSurveyPopup, toggleShowSurveyPopup]
|
||||||
|
}
|
||||||
|
|
||||||
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
|
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
SerializedToken,
|
SerializedToken,
|
||||||
updateHideClosedPositions,
|
updateHideClosedPositions,
|
||||||
updateMatchesDarkMode,
|
updateMatchesDarkMode,
|
||||||
|
updateShowSurveyPopup,
|
||||||
updateUserClientSideRouter,
|
updateUserClientSideRouter,
|
||||||
updateUserDarkMode,
|
updateUserDarkMode,
|
||||||
updateUserDeadline,
|
updateUserDeadline,
|
||||||
@ -60,6 +61,9 @@ export interface UserState {
|
|||||||
|
|
||||||
timestamp: number
|
timestamp: number
|
||||||
URLWarningVisible: boolean
|
URLWarningVisible: boolean
|
||||||
|
|
||||||
|
// undefined means has not gone through A/B split yet
|
||||||
|
showSurveyPopup: boolean | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function pairKey(token0Address: string, token1Address: string) {
|
function pairKey(token0Address: string, token1Address: string) {
|
||||||
@ -80,6 +84,7 @@ export const initialState: UserState = {
|
|||||||
pairs: {},
|
pairs: {},
|
||||||
timestamp: currentTimestamp(),
|
timestamp: currentTimestamp(),
|
||||||
URLWarningVisible: true,
|
URLWarningVisible: true,
|
||||||
|
showSurveyPopup: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default createReducer(initialState, (builder) =>
|
export default createReducer(initialState, (builder) =>
|
||||||
@ -147,6 +152,9 @@ export default createReducer(initialState, (builder) =>
|
|||||||
.addCase(updateHideClosedPositions, (state, action) => {
|
.addCase(updateHideClosedPositions, (state, action) => {
|
||||||
state.userHideClosedPositions = action.payload.userHideClosedPositions
|
state.userHideClosedPositions = action.payload.userHideClosedPositions
|
||||||
})
|
})
|
||||||
|
.addCase(updateShowSurveyPopup, (state, action) => {
|
||||||
|
state.showSurveyPopup = action.payload.showSurveyPopup
|
||||||
|
})
|
||||||
.addCase(addSerializedToken, (state, { payload: { serializedToken } }) => {
|
.addCase(addSerializedToken, (state, { payload: { serializedToken } }) => {
|
||||||
if (!state.tokens) {
|
if (!state.tokens) {
|
||||||
state.tokens = {}
|
state.tokens = {}
|
||||||
|
Loading…
Reference in New Issue
Block a user