mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at verify-code 5.6 kB view raw
1import React from 'react' 2import {msg} from '@lingui/macro' 3import {useLingui} from '@lingui/react' 4 5import { 6 ProgressGuideToast, 7 ProgressGuideToastRef, 8} from '#/components/ProgressGuide/Toast' 9import { 10 usePreferencesQuery, 11 useSetActiveProgressGuideMutation, 12} from '../queries/preferences' 13 14export enum ProgressGuideAction { 15 Like = 'like', 16 Follow = 'follow', 17} 18 19type ProgressGuideName = 'like-10-and-follow-7' 20 21interface BaseProgressGuide { 22 guide: string 23 isComplete: boolean 24 [key: string]: any 25} 26 27interface Like10AndFollow7ProgressGuide extends BaseProgressGuide { 28 numLikes: number 29 numFollows: number 30} 31 32type ProgressGuide = Like10AndFollow7ProgressGuide | undefined 33 34const ProgressGuideContext = React.createContext<ProgressGuide>(undefined) 35 36const ProgressGuideControlContext = React.createContext<{ 37 startProgressGuide(guide: ProgressGuideName): void 38 endProgressGuide(): void 39 captureAction(action: ProgressGuideAction, count?: number): void 40}>({ 41 startProgressGuide: (_guide: ProgressGuideName) => {}, 42 endProgressGuide: () => {}, 43 captureAction: (_action: ProgressGuideAction, _count = 1) => {}, 44}) 45 46export function useProgressGuide(guide: ProgressGuideName) { 47 const ctx = React.useContext(ProgressGuideContext) 48 if (ctx?.guide === guide) { 49 return ctx 50 } 51 return undefined 52} 53 54export function useProgressGuideControls() { 55 return React.useContext(ProgressGuideControlContext) 56} 57 58export function Provider({children}: React.PropsWithChildren<{}>) { 59 const {_} = useLingui() 60 const {data: preferences} = usePreferencesQuery() 61 const {mutateAsync, variables, isPending} = 62 useSetActiveProgressGuideMutation() 63 64 const activeProgressGuide = ( 65 isPending ? variables : preferences?.bskyAppState?.activeProgressGuide 66 ) as ProgressGuide 67 68 // ensure the unspecced attributes have the correct types 69 if (activeProgressGuide?.guide === 'like-10-and-follow-7') { 70 activeProgressGuide.numLikes = Number(activeProgressGuide.numLikes) || 0 71 activeProgressGuide.numFollows = Number(activeProgressGuide.numFollows) || 0 72 } 73 74 const [localGuideState, setLocalGuideState] = 75 React.useState<ProgressGuide>(undefined) 76 77 if (activeProgressGuide && !localGuideState) { 78 // hydrate from the server if needed 79 setLocalGuideState(activeProgressGuide) 80 } 81 82 const firstLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null) 83 const fifthLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null) 84 const tenthLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null) 85 const guideCompleteToastRef = React.useRef<ProgressGuideToastRef | null>(null) 86 87 const controls = React.useMemo(() => { 88 return { 89 startProgressGuide(guide: ProgressGuideName) { 90 if (guide === 'like-10-and-follow-7') { 91 const guideObj = { 92 guide: 'like-10-and-follow-7', 93 numLikes: 0, 94 numFollows: 0, 95 isComplete: false, 96 } 97 setLocalGuideState(guideObj) 98 mutateAsync(guideObj) 99 } 100 }, 101 102 endProgressGuide() { 103 setLocalGuideState(undefined) 104 mutateAsync(undefined) 105 }, 106 107 captureAction(action: ProgressGuideAction, count = 1) { 108 let guide = activeProgressGuide 109 if (!guide || guide?.isComplete) { 110 return 111 } 112 if (guide?.guide === 'like-10-and-follow-7') { 113 if (action === ProgressGuideAction.Like) { 114 guide = { 115 ...guide, 116 numLikes: (Number(guide.numLikes) || 0) + count, 117 } 118 if (guide.numLikes === 1) { 119 firstLikeToastRef.current?.open() 120 } 121 if (guide.numLikes === 5) { 122 fifthLikeToastRef.current?.open() 123 } 124 if (guide.numLikes === 10) { 125 tenthLikeToastRef.current?.open() 126 } 127 } 128 if (action === ProgressGuideAction.Follow) { 129 guide = { 130 ...guide, 131 numFollows: (Number(guide.numFollows) || 0) + count, 132 } 133 } 134 if (Number(guide.numLikes) >= 10 && Number(guide.numFollows) >= 7) { 135 guide = { 136 ...guide, 137 isComplete: true, 138 } 139 } 140 } 141 142 setLocalGuideState(guide) 143 mutateAsync(guide?.isComplete ? undefined : guide) 144 }, 145 } 146 }, [activeProgressGuide, mutateAsync, setLocalGuideState]) 147 148 return ( 149 <ProgressGuideContext.Provider value={localGuideState}> 150 <ProgressGuideControlContext.Provider value={controls}> 151 {children} 152 {localGuideState?.guide === 'like-10-and-follow-7' && ( 153 <> 154 <ProgressGuideToast 155 ref={firstLikeToastRef} 156 title={_(msg`Your first like!`)} 157 subtitle={_(msg`Like 10 posts to train the Discover feed`)} 158 /> 159 <ProgressGuideToast 160 ref={fifthLikeToastRef} 161 title={_(msg`Half way there!`)} 162 subtitle={_(msg`Like 10 posts to train the Discover feed`)} 163 /> 164 <ProgressGuideToast 165 ref={tenthLikeToastRef} 166 title={_(msg`Task complete - 10 likes!`)} 167 subtitle={_(msg`The Discover feed now knows what you like`)} 168 /> 169 <ProgressGuideToast 170 ref={guideCompleteToastRef} 171 title={_(msg`Algorithm training complete!`)} 172 subtitle={_(msg`The Discover feed now knows what you like`)} 173 /> 174 </> 175 )} 176 </ProgressGuideControlContext.Provider> 177 </ProgressGuideContext.Provider> 178 ) 179}