WIP
This commit is contained in:
@@ -0,0 +1,88 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {msg} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {
|
||||||
|
ProgressGuideToast,
|
||||||
|
ProgressGuideToastRef,
|
||||||
|
} from '#/components/ProgressGuide/Toast'
|
||||||
|
import {useNudges, NudgeType} from '#/components/nudges'
|
||||||
|
|
||||||
|
export type Action = {
|
||||||
|
type: 'activate'
|
||||||
|
} | {
|
||||||
|
type: 'like'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useProgressGuide() {
|
||||||
|
const {nudges, activateNudges, updateNudges, dismissNudges} = useNudges()
|
||||||
|
const firstLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null)
|
||||||
|
const fifthLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null)
|
||||||
|
const tenthLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null)
|
||||||
|
const isActive = Boolean(nudges.find(n => n.type === NudgeType.progressGuide_like10Follow7))
|
||||||
|
|
||||||
|
const dispatch = (action: Action) => {
|
||||||
|
const prevState = nudges.find(n => n.type === NudgeType.progressGuide_like10Follow7)
|
||||||
|
|
||||||
|
if (!prevState || prevState.type !== NudgeType.progressGuide_like10Follow7) return
|
||||||
|
|
||||||
|
let next = prevState
|
||||||
|
|
||||||
|
switch (action.type) {
|
||||||
|
case 'activate': {
|
||||||
|
activateNudges([
|
||||||
|
{
|
||||||
|
type: NudgeType.progressGuide_like10Follow7,
|
||||||
|
numLikes: 0,
|
||||||
|
numFollows: 0,
|
||||||
|
complete: false,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'like': {
|
||||||
|
next = {
|
||||||
|
...next,
|
||||||
|
numLikes: prevState.numLikes + 1,
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isActive,
|
||||||
|
dispatch,
|
||||||
|
refs: {
|
||||||
|
firstLikeToastRef,
|
||||||
|
fifthLikeToastRef,
|
||||||
|
tenthLikeToastRef,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Toasts() {
|
||||||
|
const {_} = useLingui()
|
||||||
|
const {isActive, refs} = useProgressGuide()
|
||||||
|
|
||||||
|
return isActive ? (
|
||||||
|
<>
|
||||||
|
<ProgressGuideToast
|
||||||
|
ref={refs.firstLikeToastRef}
|
||||||
|
title={_(msg`Your first like!`)}
|
||||||
|
subtitle={_(msg`Like 10 posts to train the Discover feed`)}
|
||||||
|
/>
|
||||||
|
<ProgressGuideToast
|
||||||
|
ref={refs.fifthLikeToastRef}
|
||||||
|
title={_(msg`Half way there!`)}
|
||||||
|
subtitle={_(msg`Like 10 posts to train the Discover feed`)}
|
||||||
|
/>
|
||||||
|
<ProgressGuideToast
|
||||||
|
ref={refs.tenthLikeToastRef}
|
||||||
|
title={_(msg`Task complete - 10 likes!`)}
|
||||||
|
subtitle={_(msg`The Discover feed now knows what you like`)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import {Nudge} from '#/components/nudges/types'
|
||||||
|
|
||||||
|
export * from '#/components/nudges/types'
|
||||||
|
|
||||||
|
export type Context = {
|
||||||
|
nudges: Nudge[]
|
||||||
|
activateNudges: (nudges: Nudge[]) => Promise<void>
|
||||||
|
updateNudges: (nudges: Nudge[]) => Promise<void>
|
||||||
|
dismissNudges: (nudges: Nudge[]) => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
const Context = React.createContext<Context>({
|
||||||
|
nudges: [],
|
||||||
|
activateNudges: async () => {},
|
||||||
|
updateNudges: async () => {},
|
||||||
|
dismissNudges: async () => {},
|
||||||
|
})
|
||||||
|
|
||||||
|
export function useNudges() {
|
||||||
|
return React.useContext(Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NudgeProvider({children}: {children: React.ReactNode}) {
|
||||||
|
// TODO hydrate from remote storage
|
||||||
|
const [nudges, setNudges] = React.useState<Nudge[]>([])
|
||||||
|
|
||||||
|
const activateNudges = async (nudges: Nudge[]) => {
|
||||||
|
setNudges(s => Array.from(new Set([...s, ...nudges])))
|
||||||
|
// TODO write to remote storage
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateNudges = async (nudges: Nudge[]) => {
|
||||||
|
setNudges(s => [
|
||||||
|
...s.filter(n => !nudges.some(nudge => nudge.type === n.type)),
|
||||||
|
...nudges,
|
||||||
|
])
|
||||||
|
// TODO write to remote storage
|
||||||
|
}
|
||||||
|
|
||||||
|
const dismissNudges = async (nudges: Nudge[]) => {
|
||||||
|
setNudges(s => s.filter(n => !nudges.some(nudge => nudge.type === n.type)))
|
||||||
|
// TODO write to remote storage
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = React.useMemo<Context>(
|
||||||
|
() => ({nudges, activateNudges, updateNudges, dismissNudges}),
|
||||||
|
[nudges],
|
||||||
|
)
|
||||||
|
|
||||||
|
return <Context.Provider value={ctx}>{children}</Context.Provider>
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
export enum NudgeType {
|
||||||
|
/*
|
||||||
|
* Feed interstitials
|
||||||
|
*/
|
||||||
|
interstitialPopularFeeds = 'interstitialPopularFeeds',
|
||||||
|
interstitialSuggestedFollows = 'interstitialSuggestedFollows',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Progress guides
|
||||||
|
*/
|
||||||
|
progressGuide_like10Follow7 = 'progressGuide_like10Follow7',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Interstitials = {
|
||||||
|
type: NudgeType.interstitialPopularFeeds
|
||||||
|
hidden: boolean
|
||||||
|
} | {
|
||||||
|
type: NudgeType.interstitialSuggestedFollows
|
||||||
|
hidden: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProgressGuides = {
|
||||||
|
type: NudgeType.progressGuide_like10Follow7
|
||||||
|
numLikes: number
|
||||||
|
numFollows: number
|
||||||
|
complete: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Nudge = Interstitials | ProgressGuides
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
// import {useQueueNudgesMutation, useDismissNudgesMutation} from '#/state/queries/preferences'
|
||||||
|
|
||||||
|
export enum NudgeType {
|
||||||
|
/*
|
||||||
|
* Feed interstitials
|
||||||
|
*/
|
||||||
|
interstitialPopularFeeds = 'interstitialPopularFeeds',
|
||||||
|
interstitialSuggestedFollows = 'interstitialSuggestedFollows',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Progress guides
|
||||||
|
*/
|
||||||
|
progressGuide_like10Follow7 = 'progressGuide_like10Follow7',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Interstitials = {
|
||||||
|
type: NudgeType.interstitialPopularFeeds
|
||||||
|
} | {
|
||||||
|
type: NudgeType.interstitialSuggestedFollows
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProgressGuides = {
|
||||||
|
type: NudgeType.progressGuide_like10Follow7
|
||||||
|
numLikes: number
|
||||||
|
numFollows: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Nudge = Interstitials | ProgressGuides
|
||||||
|
|
||||||
|
let __temp_storage: Nudge[] = []
|
||||||
|
|
||||||
|
export function useQueueNudges() {
|
||||||
|
const queueNudges = async (nudges: Nudge[]) => {
|
||||||
|
__temp_storage.push(...nudges)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { queueNudges }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDismissNudges() {
|
||||||
|
const dismissNudges = async (nudges: Nudge[]) => {
|
||||||
|
__temp_storage = __temp_storage.filter(n => {
|
||||||
|
return !nudges.some(nudge => nudge.type === n.type)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { dismissNudges }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user