diff --git a/web/components/info-box.tsx b/web/components/info-box.tsx
new file mode 100644
index 00000000..34f65089
--- /dev/null
+++ b/web/components/info-box.tsx
@@ -0,0 +1,30 @@
+import clsx from 'clsx'
+import { InformationCircleIcon } from '@heroicons/react/solid'
+
+import { Linkify } from './linkify'
+
+export function InfoBox(props: {
+ title: string
+ text: string
+ className?: string
+}) {
+ const { title, text, className } = props
+ return (
+
+ )
+}
diff --git a/web/components/nav/sidebar.tsx b/web/components/nav/sidebar.tsx
index 9486a97b..b7117a20 100644
--- a/web/components/nav/sidebar.tsx
+++ b/web/components/nav/sidebar.tsx
@@ -63,6 +63,7 @@ function getMoreNavigation(user?: User | null) {
return [
{ name: 'Leaderboards', href: '/leaderboards' },
+ { name: 'Referrals', href: '/referrals' },
{ name: 'Charity', href: '/charity' },
{ name: 'Send M$', href: '/links' },
{ name: 'Discord', href: 'https://discord.gg/eHQBNBqXuh' },
@@ -114,6 +115,7 @@ function getMoreMobileNav() {
...(IS_PRIVATE_MANIFOLD
? []
: [
+ { name: 'Referrals', href: '/referrals' },
{ name: 'Charity', href: '/charity' },
{ name: 'Send M$', href: '/links' },
{ name: 'Discord', href: 'https://discord.gg/eHQBNBqXuh' },
diff --git a/web/hooks/use-save-referral.ts b/web/hooks/use-save-referral.ts
new file mode 100644
index 00000000..788268b0
--- /dev/null
+++ b/web/hooks/use-save-referral.ts
@@ -0,0 +1,27 @@
+import { useRouter } from 'next/router'
+import { useEffect } from 'react'
+
+import { User, writeReferralInfo } from 'web/lib/firebase/users'
+
+export const useSaveReferral = (
+ user?: User | null,
+ options?: {
+ defaultReferrer?: string
+ contractId?: string
+ groupId?: string
+ }
+) => {
+ const router = useRouter()
+
+ useEffect(() => {
+ const { referrer } = router.query as {
+ referrer?: string
+ }
+
+ const actualReferrer = referrer || options?.defaultReferrer
+
+ if (!user && router.isReady && actualReferrer) {
+ writeReferralInfo(actualReferrer, options?.contractId, options?.groupId)
+ }
+ }, [user, router, options])
+}
diff --git a/web/pages/[username]/[contractSlug].tsx b/web/pages/[username]/[contractSlug].tsx
index 17453770..11d9af9c 100644
--- a/web/pages/[username]/[contractSlug].tsx
+++ b/web/pages/[username]/[contractSlug].tsx
@@ -10,7 +10,7 @@ import { useUser } from 'web/hooks/use-user'
import { ResolutionPanel } from 'web/components/resolution-panel'
import { Title } from 'web/components/title'
import { Spacer } from 'web/components/layout/spacer'
-import { listUsers, User, writeReferralInfo } from 'web/lib/firebase/users'
+import { listUsers, User } from 'web/lib/firebase/users'
import {
Contract,
getContractFromSlug,
@@ -43,9 +43,9 @@ import { CPMMBinaryContract } from 'common/contract'
import { AlertBox } from 'web/components/alert-box'
import { useTracking } from 'web/hooks/use-tracking'
import { CommentTipMap, useTipTxns } from 'web/hooks/use-tip-txns'
-import { useRouter } from 'next/router'
import { useLiquidity } from 'web/hooks/use-liquidity'
import { richTextToString } from 'common/util/parse'
+import { useSaveReferral } from 'web/hooks/use-save-referral'
export const getStaticProps = fromPropz(getStaticPropz)
export async function getStaticPropz(props: {
@@ -157,15 +157,10 @@ export function ContractPageContent(
const ogCardProps = getOpenGraphProps(contract)
- const router = useRouter()
-
- useEffect(() => {
- const { referrer } = router.query as {
- referrer?: string
- }
- if (!user && router.isReady)
- writeReferralInfo(contract.creatorUsername, contract.id, referrer)
- }, [user, contract, router])
+ useSaveReferral(user, {
+ defaultReferrer: contract.creatorUsername,
+ contractId: contract.id,
+ })
const rightSidebar = hasSidePanel ? (
diff --git a/web/pages/group/[...slugs]/index.tsx b/web/pages/group/[...slugs]/index.tsx
index 0d38580c..90f39e83 100644
--- a/web/pages/group/[...slugs]/index.tsx
+++ b/web/pages/group/[...slugs]/index.tsx
@@ -14,12 +14,7 @@ import {
} from 'web/lib/firebase/groups'
import { Row } from 'web/components/layout/row'
import { UserLink } from 'web/components/user-page'
-import {
- firebaseLogin,
- getUser,
- User,
- writeReferralInfo,
-} from 'web/lib/firebase/users'
+import { firebaseLogin, getUser, User } from 'web/lib/firebase/users'
import { Col } from 'web/components/layout/col'
import { useUser } from 'web/hooks/use-user'
import { listMembers, useGroup, useMembers } from 'web/hooks/use-group'
@@ -34,7 +29,7 @@ import { Linkify } from 'web/components/linkify'
import { fromPropz, usePropz } from 'web/hooks/use-propz'
import { Tabs } from 'web/components/layout/tabs'
import { CreateQuestionButton } from 'web/components/create-question-button'
-import React, { useEffect, useState } from 'react'
+import React, { useState } from 'react'
import { GroupChat } from 'web/components/groups/group-chat'
import { LoadingIndicator } from 'web/components/loading-indicator'
import { Modal } from 'web/components/layout/modal'
@@ -53,6 +48,7 @@ import { searchInAny } from 'common/util/parse'
import { useWindowSize } from 'web/hooks/use-window-size'
import { CopyLinkButton } from 'web/components/copy-link-button'
import { ENV_CONFIG } from 'common/envs/constants'
+import { useSaveReferral } from 'web/hooks/use-save-referral'
export const getStaticProps = fromPropz(getStaticPropz)
export async function getStaticPropz(props: { params: { slugs: string[] } }) {
@@ -155,13 +151,11 @@ export default function GroupPage(props: {
const messages = useCommentsOnGroup(group?.id)
const user = useUser()
- useEffect(() => {
- const { referrer } = router.query as {
- referrer?: string
- }
- if (!user && router.isReady)
- writeReferralInfo(creator.username, undefined, referrer, group?.id)
- }, [user, creator, group, router])
+
+ useSaveReferral(user, {
+ defaultReferrer: creator.username,
+ groupId: group?.id,
+ })
const { width } = useWindowSize()
const chatDisabled = !group || group.chatDisabled
diff --git a/web/pages/home.tsx b/web/pages/home.tsx
index 53bb6ec9..61003895 100644
--- a/web/pages/home.tsx
+++ b/web/pages/home.tsx
@@ -12,6 +12,7 @@ import { getContractFromSlug } from 'web/lib/firebase/contracts'
import { useTracking } from 'web/hooks/use-tracking'
import { track } from 'web/lib/service/analytics'
import { redirectIfLoggedOut } from 'web/lib/firebase/server-auth'
+import { useSaveReferral } from 'web/hooks/use-save-referral'
export const getServerSideProps = redirectIfLoggedOut('/')
@@ -21,6 +22,8 @@ const Home = () => {
const router = useRouter()
useTracking('view home')
+ useSaveReferral()
+
return (
<>
diff --git a/web/pages/index.tsx b/web/pages/index.tsx
index d9ff7f51..fd5cf382 100644
--- a/web/pages/index.tsx
+++ b/web/pages/index.tsx
@@ -7,6 +7,7 @@ import { LandingPagePanel } from 'web/components/landing-page-panel'
import { Col } from 'web/components/layout/col'
import { ManifoldLogo } from 'web/components/nav/manifold-logo'
import { redirectIfLoggedIn } from 'web/lib/firebase/server-auth'
+import { useSaveReferral } from 'web/hooks/use-save-referral'
export const getServerSideProps = redirectIfLoggedIn('/home', async (_) => {
// These hardcoded markets will be shown in the frontpage for signed-out users:
@@ -32,6 +33,9 @@ export default function Home(props: { hotContracts: Contract[] }) {
// on this page and they log in -- in the future we will make some cleaner way
const user = useUser()
const router = useRouter()
+
+ useSaveReferral()
+
useEffect(() => {
if (user != null) {
router.replace('/home')
diff --git a/web/pages/referrals.tsx b/web/pages/referrals.tsx
new file mode 100644
index 00000000..c879afaa
--- /dev/null
+++ b/web/pages/referrals.tsx
@@ -0,0 +1,57 @@
+import { Col } from 'web/components/layout/col'
+import { SEO } from 'web/components/SEO'
+import { Title } from 'web/components/title'
+import { useUser } from 'web/hooks/use-user'
+import { Page } from 'web/components/page'
+import { useTracking } from 'web/hooks/use-tracking'
+import { redirectIfLoggedOut } from 'web/lib/firebase/server-auth'
+import { REFERRAL_AMOUNT } from 'common/user'
+import { CopyLinkButton } from 'web/components/copy-link-button'
+import { ENV_CONFIG } from 'common/envs/constants'
+import { InfoBox } from 'web/components/info-box'
+
+export const getServerSideProps = redirectIfLoggedOut('/')
+
+export default function ReferralsPage() {
+ const user = useUser()
+
+ useTracking('view referrals')
+
+ const url = `https://${ENV_CONFIG.domain}?referrer=${user?.username}`
+
+ return (
+
+
+
+
+
+
+
+
+
+ Invite new users to Manifold and get M${REFERRAL_AMOUNT} if they
+ sign up!
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/web/public/logo-flapping-with-money.gif b/web/public/logo-flapping-with-money.gif
new file mode 100644
index 00000000..0ef936a4
Binary files /dev/null and b/web/public/logo-flapping-with-money.gif differ