From dc214725259fa7ca5b5b669dbb385b7889dcec2a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 3 Jul 2024 14:02:28 -0500 Subject: [PATCH] WIP --- .../nudges/ProgressGuides/Like10Follow7.tsx | 88 +++++++++++++++++++ src/components/nudges/index.tsx | 53 +++++++++++ src/components/nudges/types.ts | 29 ++++++ src/state/queries/nudges.ts | 48 ++++++++++ 4 files changed, 218 insertions(+) create mode 100644 src/components/nudges/ProgressGuides/Like10Follow7.tsx create mode 100644 src/components/nudges/index.tsx create mode 100644 src/components/nudges/types.ts create mode 100644 src/state/queries/nudges.ts diff --git a/src/components/nudges/ProgressGuides/Like10Follow7.tsx b/src/components/nudges/ProgressGuides/Like10Follow7.tsx new file mode 100644 index 0000000000..97f4d91824 --- /dev/null +++ b/src/components/nudges/ProgressGuides/Like10Follow7.tsx @@ -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(null) + const fifthLikeToastRef = React.useRef(null) + const tenthLikeToastRef = React.useRef(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 ? ( + <> + + + + + ) : null +} diff --git a/src/components/nudges/index.tsx b/src/components/nudges/index.tsx new file mode 100644 index 0000000000..5d58d5988e --- /dev/null +++ b/src/components/nudges/index.tsx @@ -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 + updateNudges: (nudges: Nudge[]) => Promise + dismissNudges: (nudges: Nudge[]) => Promise +} + +const Context = React.createContext({ + 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([]) + + 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( + () => ({nudges, activateNudges, updateNudges, dismissNudges}), + [nudges], + ) + + return {children} +} diff --git a/src/components/nudges/types.ts b/src/components/nudges/types.ts new file mode 100644 index 0000000000..392a99854b --- /dev/null +++ b/src/components/nudges/types.ts @@ -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 diff --git a/src/state/queries/nudges.ts b/src/state/queries/nudges.ts new file mode 100644 index 0000000000..6531ce37ff --- /dev/null +++ b/src/state/queries/nudges.ts @@ -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 } +}