diff --git a/common/categories.ts b/common/categories.ts index 232aa526..672f3200 100644 --- a/common/categories.ts +++ b/common/categories.ts @@ -1,6 +1,7 @@ import { difference } from 'lodash' export const CATEGORIES_GROUP_SLUG_POSTFIX = '-default' + export const CATEGORIES = { politics: 'Politics', technology: 'Technology', @@ -37,3 +38,8 @@ export const EXCLUDED_CATEGORIES: category[] = [ ] export const DEFAULT_CATEGORIES = difference(CATEGORY_LIST, EXCLUDED_CATEGORIES) + +export const DEFAULT_CATEGORY_GROUPS = DEFAULT_CATEGORIES.map((c) => ({ + slug: c.toLowerCase() + CATEGORIES_GROUP_SLUG_POSTFIX, + name: CATEGORIES[c as category], +})) diff --git a/common/numeric-constants.ts b/common/numeric-constants.ts index 46885668..f399aa5a 100644 --- a/common/numeric-constants.ts +++ b/common/numeric-constants.ts @@ -3,4 +3,4 @@ export const NUMERIC_FIXED_VAR = 0.005 export const NUMERIC_GRAPH_COLOR = '#5fa5f9' export const NUMERIC_TEXT_COLOR = 'text-blue-500' -export const UNIQUE_BETTOR_BONUS_AMOUNT = 5 +export const UNIQUE_BETTOR_BONUS_AMOUNT = 10 diff --git a/web/.prettierignore b/web/.prettierignore index b79c5513..6cc1e5c7 100644 --- a/web/.prettierignore +++ b/web/.prettierignore @@ -1,3 +1,4 @@ # Ignore Next artifacts .next/ -out/ \ No newline at end of file +out/ +public/**/*.json \ No newline at end of file diff --git a/web/components/auth-context.tsx b/web/components/auth-context.tsx new file mode 100644 index 00000000..fcc3de39 --- /dev/null +++ b/web/components/auth-context.tsx @@ -0,0 +1,77 @@ +import { createContext, useEffect } from 'react' +import { User } from 'common/user' +import { onIdTokenChanged } from 'firebase/auth' +import { + auth, + listenForUser, + getUser, + setCachedReferralInfoForUser, +} from 'web/lib/firebase/users' +import { deleteAuthCookies, setAuthCookies } from 'web/lib/firebase/auth' +import { createUser } from 'web/lib/firebase/api' +import { randomString } from 'common/util/random' +import { identifyUser, setUserProperty } from 'web/lib/service/analytics' +import { useStateCheckEquality } from 'web/hooks/use-state-check-equality' + +// Either we haven't looked up the logged in user yet (undefined), or we know +// the user is not logged in (null), or we know the user is logged in (User). +type AuthUser = undefined | null | User + +const CACHED_USER_KEY = 'CACHED_USER_KEY' + +const ensureDeviceToken = () => { + let deviceToken = localStorage.getItem('device-token') + if (!deviceToken) { + deviceToken = randomString() + localStorage.setItem('device-token', deviceToken) + } + return deviceToken +} + +export const AuthContext = createContext(null) + +export function AuthProvider({ children }: any) { + const [authUser, setAuthUser] = useStateCheckEquality(undefined) + + useEffect(() => { + const cachedUser = localStorage.getItem(CACHED_USER_KEY) + setAuthUser(cachedUser && JSON.parse(cachedUser)) + }, [setAuthUser]) + + useEffect(() => { + return onIdTokenChanged(auth, async (fbUser) => { + if (fbUser) { + let user = await getUser(fbUser.uid) + if (!user) { + const deviceToken = ensureDeviceToken() + user = (await createUser({ deviceToken })) as User + } + setAuthUser(user) + // Persist to local storage, to reduce login blink next time. + // Note: Cap on localStorage size is ~5mb + localStorage.setItem(CACHED_USER_KEY, JSON.stringify(user)) + setCachedReferralInfoForUser(user) + setAuthCookies(await fbUser.getIdToken(), fbUser.refreshToken) + } else { + // User logged out; reset to null + setAuthUser(null) + localStorage.removeItem(CACHED_USER_KEY) + deleteAuthCookies() + } + }) + }, [setAuthUser]) + + const authUserId = authUser?.id + const authUsername = authUser?.username + useEffect(() => { + if (authUserId && authUsername) { + identifyUser(authUserId) + setUserProperty('username', authUsername) + return listenForUser(authUserId, setAuthUser) + } + }, [authUserId, authUsername, setAuthUser]) + + return ( + {children} + ) +} diff --git a/web/components/bets-list.tsx b/web/components/bets-list.tsx index 2114ec2b..a306a020 100644 --- a/web/components/bets-list.tsx +++ b/web/components/bets-list.tsx @@ -78,10 +78,10 @@ export function BetsList(props: { const getTime = useTimeSinceFirstRender() useEffect(() => { - if (bets && contractsById) { - trackLatency('portfolio', getTime()) + if (bets && contractsById && signedInUser) { + trackLatency(signedInUser.id, 'portfolio', getTime()) } - }, [bets, contractsById, getTime]) + }, [signedInUser, bets, contractsById, getTime]) if (!bets || !contractsById) { return diff --git a/web/components/buttons/pill-button.tsx b/web/components/buttons/pill-button.tsx index 796036d1..5b4962b7 100644 --- a/web/components/buttons/pill-button.tsx +++ b/web/components/buttons/pill-button.tsx @@ -13,7 +13,7 @@ export function PillButton(props: { return ( - - )} - -
- +
- + )} {isFreeResponseContractPage && (