-
Notifications
You must be signed in to change notification settings - Fork 461
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: feature flag for targeted survey (#4538)
- Loading branch information
Showing
3 changed files
with
150 additions
and
135 deletions.
There are no files selected for viewing
139 changes: 139 additions & 0 deletions
139
src/features/targetedOutreach/components/OutreachPopup/OutreachPopup.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import { useCreateSubmissionMutation, useGetSubmissionQuery } from '@/store/api/gateway' | ||
import { skipToken } from '@reduxjs/toolkit/query' | ||
import { useEffect, type ReactElement } from 'react' | ||
import { Avatar, Box, Button, Chip, IconButton, Link, Paper, Stack, ThemeProvider, Typography } from '@mui/material' | ||
import { Close } from '@mui/icons-material' | ||
import type { Theme } from '@mui/material/styles' | ||
import { useAppDispatch, useAppSelector } from '@/store' | ||
import css from './styles.module.css' | ||
import { closeOutreachBanner, openOutreachBanner, selectOutreachBanner } from '@/store/popupSlice' | ||
import useLocalStorage, { useSessionStorage } from '@/services/local-storage/useLocalStorage' | ||
import useShowOutreachPopup from '@/features/targetedOutreach/hooks/useShowOutreachPopup' | ||
import { ACTIVE_OUTREACH, OUTREACH_LS_KEY, OUTREACH_SS_KEY } from '@/features/targetedOutreach/constants' | ||
import Track from '@/components/common/Track' | ||
import { OUTREACH_EVENTS } from '@/services/analytics/events/outreach' | ||
import SafeThemeProvider from '@/components/theme/SafeThemeProvider' | ||
import useChainId from '@/hooks/useChainId' | ||
import useSafeAddress from '@/hooks/useSafeAddress' | ||
import useWallet from '@/hooks/wallets/useWallet' | ||
|
||
const OutreachPopup = (): ReactElement | null => { | ||
const dispatch = useAppDispatch() | ||
const outreachPopup = useAppSelector(selectOutreachBanner) | ||
const [isClosed, setIsClosed] = useLocalStorage<boolean>(OUTREACH_LS_KEY) | ||
const currentChainId = useChainId() | ||
const safeAddress = useSafeAddress() | ||
const wallet = useWallet() | ||
const [createSubmission] = useCreateSubmissionMutation() | ||
const { data: submission } = useGetSubmissionQuery( | ||
!wallet || !safeAddress | ||
? skipToken | ||
: { | ||
outreachId: ACTIVE_OUTREACH.id, | ||
chainId: currentChainId, | ||
safeAddress, | ||
signerAddress: wallet?.address, | ||
}, | ||
) | ||
|
||
const [askAgainLaterTimestamp, setAskAgainLaterTimestamp] = useSessionStorage<number>(OUTREACH_SS_KEY) | ||
|
||
const shouldOpen = useShowOutreachPopup(isClosed, askAgainLaterTimestamp, submission) | ||
|
||
const handleClose = () => { | ||
setIsClosed(true) | ||
dispatch(closeOutreachBanner()) | ||
} | ||
|
||
const handleAskAgainLater = () => { | ||
setAskAgainLaterTimestamp(Date.now()) | ||
dispatch(closeOutreachBanner()) | ||
} | ||
|
||
// Decide whether to show the popup. | ||
useEffect(() => { | ||
if (shouldOpen) { | ||
dispatch(openOutreachBanner()) | ||
} else { | ||
dispatch(closeOutreachBanner()) | ||
} | ||
}, [dispatch, shouldOpen]) | ||
|
||
if (!outreachPopup.open) return null | ||
|
||
const handleOpenSurvey = async () => { | ||
if (wallet) { | ||
await createSubmission({ | ||
outreachId: ACTIVE_OUTREACH.id, | ||
chainId: currentChainId, | ||
safeAddress, | ||
signerAddress: wallet.address, | ||
}) | ||
} | ||
dispatch(closeOutreachBanner()) | ||
} | ||
|
||
return ( | ||
// Enforce light theme for the popup | ||
<SafeThemeProvider mode="light"> | ||
{(safeTheme: Theme) => ( | ||
<ThemeProvider theme={safeTheme}> | ||
<Box className={css.popup}> | ||
<Paper className={css.container}> | ||
<Stack gap={2}> | ||
<Box display="flex"> | ||
<Avatar alt="Clem, product lead" src="/images/common/outreach-popup-avatar.png" /> | ||
<Box ml={1}> | ||
<Typography variant="body2">Clem</Typography> | ||
<Typography variant="body2" color="primary.light"> | ||
Product Lead | ||
</Typography> | ||
</Box> | ||
</Box> | ||
<Box> | ||
<Chip | ||
size="small" | ||
sx={{ backgroundColor: 'text.primary', color: 'background.paper', mt: '-2px' }} | ||
label={ | ||
<Typography fontWeight={700} variant="overline"> | ||
EARN REWARDS | ||
</Typography> | ||
} | ||
/> | ||
</Box> | ||
<Typography variant="h4" fontWeight={700}> | ||
You're invited! | ||
</Typography> | ||
<Typography> | ||
As one of our top users, we'd love to hear your feedback on how we can enhance Safe. Share your | ||
contact info, and we'll reach out for a short interview. | ||
</Typography> | ||
<Track {...OUTREACH_EVENTS.OPEN_SURVEY}> | ||
<Link rel="noreferrer noopener" target="_blank" href={ACTIVE_OUTREACH.url}> | ||
<Button fullWidth variant="contained" onClick={handleOpenSurvey}> | ||
Get Involved | ||
</Button> | ||
</Link> | ||
</Track> | ||
<Track {...OUTREACH_EVENTS.ASK_AGAIN_LATER}> | ||
<Button fullWidth variant="text" onClick={handleAskAgainLater}> | ||
Ask me later | ||
</Button> | ||
</Track> | ||
<Typography variant="body2" color="primary.light" mx="auto"> | ||
It'll only take 2 minutes. | ||
</Typography> | ||
<Track {...OUTREACH_EVENTS.CLOSE_POPUP}> | ||
<IconButton className={css.close} aria-label="close" onClick={handleClose}> | ||
<Close /> | ||
</IconButton> | ||
</Track> | ||
</Stack> | ||
</Paper> | ||
</Box> | ||
</ThemeProvider> | ||
)} | ||
</SafeThemeProvider> | ||
) | ||
} | ||
export default OutreachPopup |
145 changes: 10 additions & 135 deletions
145
src/features/targetedOutreach/components/OutreachPopup/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,139 +1,14 @@ | ||
import { useCreateSubmissionMutation, useGetSubmissionQuery } from '@/store/api/gateway' | ||
import { skipToken } from '@reduxjs/toolkit/query' | ||
import { useEffect, type ReactElement } from 'react' | ||
import { Avatar, Box, Button, Chip, IconButton, Link, Paper, Stack, ThemeProvider, Typography } from '@mui/material' | ||
import { Close } from '@mui/icons-material' | ||
import type { Theme } from '@mui/material/styles' | ||
import { useAppDispatch, useAppSelector } from '@/store' | ||
import css from './styles.module.css' | ||
import { closeOutreachBanner, openOutreachBanner, selectOutreachBanner } from '@/store/popupSlice' | ||
import useLocalStorage, { useSessionStorage } from '@/services/local-storage/useLocalStorage' | ||
import useShowOutreachPopup from '@/features/targetedOutreach/hooks/useShowOutreachPopup' | ||
import { ACTIVE_OUTREACH, OUTREACH_LS_KEY, OUTREACH_SS_KEY } from '@/features/targetedOutreach/constants' | ||
import Track from '@/components/common/Track' | ||
import { OUTREACH_EVENTS } from '@/services/analytics/events/outreach' | ||
import SafeThemeProvider from '@/components/theme/SafeThemeProvider' | ||
import useChainId from '@/hooks/useChainId' | ||
import useSafeAddress from '@/hooks/useSafeAddress' | ||
import useWallet from '@/hooks/wallets/useWallet' | ||
import dynamic from 'next/dynamic' | ||
import { useHasFeature } from '@/hooks/useChains' | ||
import { FEATURES } from '@/utils/chains' | ||
|
||
const OutreachPopup = (): ReactElement | null => { | ||
const dispatch = useAppDispatch() | ||
const outreachPopup = useAppSelector(selectOutreachBanner) | ||
const [isClosed, setIsClosed] = useLocalStorage<boolean>(OUTREACH_LS_KEY) | ||
const currentChainId = useChainId() | ||
const safeAddress = useSafeAddress() | ||
const wallet = useWallet() | ||
const [createSubmission] = useCreateSubmissionMutation() | ||
const { data: submission } = useGetSubmissionQuery( | ||
!wallet || !safeAddress | ||
? skipToken | ||
: { | ||
outreachId: ACTIVE_OUTREACH.id, | ||
chainId: currentChainId, | ||
safeAddress, | ||
signerAddress: wallet?.address, | ||
}, | ||
) | ||
const LazyOutreachPopup = dynamic(() => import('./OutreachPopup'), { | ||
ssr: false, | ||
}) | ||
|
||
const [askAgainLaterTimestamp, setAskAgainLaterTimestamp] = useSessionStorage<number>(OUTREACH_SS_KEY) | ||
|
||
const shouldOpen = useShowOutreachPopup(isClosed, askAgainLaterTimestamp, submission) | ||
|
||
const handleClose = () => { | ||
setIsClosed(true) | ||
dispatch(closeOutreachBanner()) | ||
} | ||
|
||
const handleAskAgainLater = () => { | ||
setAskAgainLaterTimestamp(Date.now()) | ||
dispatch(closeOutreachBanner()) | ||
} | ||
|
||
// Decide whether to show the popup. | ||
useEffect(() => { | ||
if (shouldOpen) { | ||
dispatch(openOutreachBanner()) | ||
} else { | ||
dispatch(closeOutreachBanner()) | ||
} | ||
}, [dispatch, shouldOpen]) | ||
|
||
if (!outreachPopup.open) return null | ||
|
||
const handleOpenSurvey = async () => { | ||
if (wallet) { | ||
await createSubmission({ | ||
outreachId: ACTIVE_OUTREACH.id, | ||
chainId: currentChainId, | ||
safeAddress, | ||
signerAddress: wallet.address, | ||
}) | ||
} | ||
dispatch(closeOutreachBanner()) | ||
} | ||
|
||
return ( | ||
// Enforce light theme for the popup | ||
<SafeThemeProvider mode="light"> | ||
{(safeTheme: Theme) => ( | ||
<ThemeProvider theme={safeTheme}> | ||
<Box className={css.popup}> | ||
<Paper className={css.container}> | ||
<Stack gap={2}> | ||
<Box display="flex"> | ||
<Avatar alt="Clem, product lead" src="/images/common/outreach-popup-avatar.png" /> | ||
<Box ml={1}> | ||
<Typography variant="body2">Clem</Typography> | ||
<Typography variant="body2" color="primary.light"> | ||
Product Lead | ||
</Typography> | ||
</Box> | ||
</Box> | ||
<Box> | ||
<Chip | ||
size="small" | ||
sx={{ backgroundColor: 'text.primary', color: 'background.paper', mt: '-2px' }} | ||
label={ | ||
<Typography fontWeight={700} variant="overline"> | ||
EARN REWARDS | ||
</Typography> | ||
} | ||
/> | ||
</Box> | ||
<Typography variant="h4" fontWeight={700}> | ||
You're invited! | ||
</Typography> | ||
<Typography> | ||
As one of our top users, we'd love to hear your feedback on how we can enhance Safe. Share your | ||
contact info, and we'll reach out for a short interview. | ||
</Typography> | ||
<Track {...OUTREACH_EVENTS.OPEN_SURVEY}> | ||
<Link rel="noreferrer noopener" target="_blank" href={ACTIVE_OUTREACH.url}> | ||
<Button fullWidth variant="contained" onClick={handleOpenSurvey}> | ||
Get Involved | ||
</Button> | ||
</Link> | ||
</Track> | ||
<Track {...OUTREACH_EVENTS.ASK_AGAIN_LATER}> | ||
<Button fullWidth variant="text" onClick={handleAskAgainLater}> | ||
Ask me later | ||
</Button> | ||
</Track> | ||
<Typography variant="body2" color="primary.light" mx="auto"> | ||
It'll only take 2 minutes. | ||
</Typography> | ||
<Track {...OUTREACH_EVENTS.CLOSE_POPUP}> | ||
<IconButton className={css.close} aria-label="close" onClick={handleClose}> | ||
<Close /> | ||
</IconButton> | ||
</Track> | ||
</Stack> | ||
</Paper> | ||
</Box> | ||
</ThemeProvider> | ||
)} | ||
</SafeThemeProvider> | ||
) | ||
function OutreachPopup() { | ||
const isEnabled = useHasFeature(FEATURES.TARGETED_SURVEY) | ||
return isEnabled ? <LazyOutreachPopup /> : null | ||
} | ||
|
||
export default OutreachPopup |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters