Skip to content

Commit

Permalink
fix: better state management of unstarted steps
Browse files Browse the repository at this point in the history
  • Loading branch information
christianmat committed Feb 16, 2023
1 parent 9832f17 commit b8c97fa
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 32 deletions.
4 changes: 3 additions & 1 deletion src/DataFetcher/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const GUEST_PREFIX = 'guest_'
export const DataFetcher: FC<DataFetcherProps> = ({}) => {
const { getUserFlowState, setFlowResponses } = useFlowResponses()
const { userId, setUserId } = useUser()
const { flows, userProperties, setIsLoading } = useContext(FrigadeContext)
const { flows, userProperties, setIsLoading, setIsLoadingUserState } = useContext(FrigadeContext)
const [automaticFlowIdsToTrigger, setAutomaticFlowIdsToTrigger] = useState<string[]>([])
const [isNewGuestUser, setIsNewGuestUser] = useState(false)

Expand All @@ -34,12 +34,14 @@ export const DataFetcher: FC<DataFetcherProps> = ({}) => {
prefetchPromises.push(getUserFlowState(flow.slug, userId))
})
}
setIsLoadingUserState(true)
const flowStates = await Promise.all(prefetchPromises)
for (let i = 0; i < flowStates.length; i++) {
if (flowStates[i]) {
syncFlowStates(flowStates[i])
}
}
setIsLoadingUserState(false)
setIsLoading(false)
} else {
console.error('Failed to prefetch flows')
Expand Down
3 changes: 2 additions & 1 deletion src/FrigadeChecklist/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useFlows } from '../api/flows'
import { HeroChecklist, HeroChecklistProps } from '../Checklists/HeroChecklist'
import { StepData } from '../types'
import { ModalChecklist } from '../Checklists/ModalChecklist'
import { COMPLETED_STEP } from '../api/common'

export interface FrigadeHeroChecklistProps extends HeroChecklistProps {
flowId: string
Expand Down Expand Up @@ -66,7 +67,7 @@ export const FrigadeChecklist: React.FC<FrigadeHeroChecklistProps> = ({
return steps.map((step) => {
return {
...step,
complete: getStepStatus(flowId, step.id) === 'COMPLETED_STEP',
complete: getStepStatus(flowId, step.id) === COMPLETED_STEP,
handleCTAClick: () => {
if (step.autoMarkCompleted || step.autoMarkCompleted === undefined) {
markStepCompleted(flowId, step.id)
Expand Down
9 changes: 8 additions & 1 deletion src/FrigadeProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export interface IFrigadeContext {
setFlowResponses?: React.Dispatch<React.SetStateAction<FlowResponse[]>>
children?: React.ReactNode
isLoading: boolean
setIsLoading: (hasLoadedData: boolean) => void
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>
isLoadingUserState: boolean
setIsLoadingUserState: React.Dispatch<React.SetStateAction<boolean>>
userProperties?: { [key: string]: string | boolean | number | null }
setUserProperties?: React.Dispatch<
React.SetStateAction<{ [key: string]: string | boolean | number | null }>
Expand All @@ -39,6 +41,8 @@ export const FrigadeContext = createContext<IFrigadeContext>({
setFlowResponses: () => {},
isLoading: false,
setIsLoading: () => {},
isLoadingUserState: false,
setIsLoadingUserState: () => {},
userProperties: {},
setUserProperties: () => {},
})
Expand All @@ -49,6 +53,7 @@ export const FrigadeProvider: FC<FrigadeProviderProps> = ({ publicApiKey, userId
const [failedFlowResponses, setFailedFlowResponses] = useState<FlowResponse[]>([])
const [flowResponses, setFlowResponses] = useState<FlowResponse[]>([])
const [isLoading, setIsLoading] = useState(true)
const [isLoadingUserState, setIsLoadingUserState] = useState(true)
const [userProperties, setUserProperties] = useState<{
[key: string]: string | boolean | number | null
}>({})
Expand All @@ -71,6 +76,8 @@ export const FrigadeProvider: FC<FrigadeProviderProps> = ({ publicApiKey, userId
setFailedFlowResponses,
isLoading: isLoading,
setIsLoading: setIsLoading,
isLoadingUserState,
setIsLoadingUserState,
flowResponses,
setFlowResponses,
userProperties,
Expand Down
27 changes: 16 additions & 11 deletions src/api/common.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
import React, {useMemo} from "react";
import {FrigadeContext} from "../FrigadeProvider";
import React, { useMemo } from 'react'
import { FrigadeContext } from '../FrigadeProvider'

export const API_PREFIX = 'https://api.frigade.com/v1/public/';
export const API_PREFIX = 'https://api.frigade.com/v1/public/'

export const NOT_STARTED_STEP = 'NOT_STARTED_STEP'
export const COMPLETED_FLOW = 'COMPLETED_FLOW'
export const STARTED_FLOW = 'STARTED_FLOW'
export const COMPLETED_STEP = 'COMPLETED_STEP'
export const STARTED_STEP = 'STARTED_STEP'

export function useConfig() {
const {publicApiKey, userId} = React.useContext(FrigadeContext);
const { publicApiKey, userId } = React.useContext(FrigadeContext)

return {
config: useMemo(
() => ({
headers: {
Authorization: `Bearer ${publicApiKey}`,
'Content-Type': 'application/json'
}
'Content-Type': 'application/json',
},
}),
[publicApiKey, userId]
)
};
),
}
}

export interface PaginatedResult<T> {
data: T[];
offset: number;
limit: number;
data: T[]
offset: number
limit: number
}
21 changes: 14 additions & 7 deletions src/api/flow-responses.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React, { useContext, useState } from 'react'
import { API_PREFIX, useConfig } from './common'
import {
API_PREFIX,
COMPLETED_FLOW,
COMPLETED_STEP,
STARTED_FLOW,
STARTED_STEP,
useConfig,
} from './common'
import { FrigadeContext } from '../FrigadeProvider'

export interface FlowResponse {
Expand Down Expand Up @@ -94,16 +101,16 @@ export function useFlowResponses() {
if (!flowResponse.foreignUserId) {
return
}
if (flowResponse.actionType === 'STARTED_FLOW') {
if (flowResponse.actionType === STARTED_FLOW) {
recordResponse(flowResponse)
await sendDataToBackend() // Send previous step data to backend
} else if (flowResponse.actionType === 'COMPLETED_FLOW') {
} else if (flowResponse.actionType === COMPLETED_FLOW) {
recordResponse(flowResponse)
await sendDataToBackend() // Send previous step data to backend
} else if (flowResponse.actionType === 'STARTED_STEP') {
} else if (flowResponse.actionType === STARTED_STEP) {
setCurrentStep(flowResponse.stepId)
recordResponse(flowResponse)
} else if (flowResponse.actionType === 'COMPLETED_STEP') {
} else if (flowResponse.actionType === COMPLETED_STEP) {
await sendDataToBackend() // Send previous step data to backend
setFlowResponseMap(new Map()) // Clear existing data
recordResponse(flowResponse)
Expand Down Expand Up @@ -137,7 +144,7 @@ export function useFlowResponses() {
foreignUserId: userId,
flowSlug: flowSlug,
stepId: 'startFlow',
actionType: 'STARTED_FLOW',
actionType: STARTED_FLOW,
data: {},
createdAt: new Date(),
}
Expand All @@ -150,7 +157,7 @@ export function useFlowResponses() {
foreignUserId: userId,
flowSlug: flowSlug,
stepId: 'endFlow',
actionType: 'COMPLETED_FLOW',
actionType: COMPLETED_FLOW,
data: { flowResponses: Array.from(successfulFlowResponses) },
createdAt: new Date(),
}
Expand Down
36 changes: 25 additions & 11 deletions src/api/flows.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React, { useContext, useEffect } from 'react'
import { API_PREFIX, PaginatedResult, useConfig } from './common'
import {
API_PREFIX,
COMPLETED_FLOW,
COMPLETED_STEP,
NOT_STARTED_STEP,
STARTED_FLOW,
useConfig,
} from './common'
import { FrigadeContext } from '../FrigadeProvider'
import { useFlowResponses } from './flow-responses'
import useSWR from 'swr'
Expand Down Expand Up @@ -28,7 +35,8 @@ export enum TriggerType {

export function useFlows() {
const { config } = useConfig()
const { flows, setFlows, isLoading, userId, publicApiKey } = useContext(FrigadeContext)
const { flows, setFlows, isLoading, userId, publicApiKey, isLoadingUserState } =
useContext(FrigadeContext)
const { addResponse, flowResponses } = useFlowResponses()
const fetcher = (url) => fetch(url, config).then((r) => r.json())

Expand Down Expand Up @@ -64,24 +72,31 @@ export function useFlows() {
foreignUserId: userId,
flowSlug,
stepId,
actionType: 'COMPLETED_STEP',
actionType: COMPLETED_STEP,
data: data ?? {},
createdAt: new Date(),
})
}

function getStepStatus(flowSlug: string, stepId: string) {
return flowResponses ? flowResponses.find((r) => r.stepId === stepId)?.actionType : null
if (isLoadingUserState) {
return undefined
}
if (flowResponses === null || flowResponses === undefined) {
return NOT_STARTED_STEP
}

return flowResponses.find((r) => r.stepId === stepId)?.actionType ?? NOT_STARTED_STEP
}

function getFlowStatus(flowSlug: string) {
if (getNumberOfStepsCompleted(flowSlug) === getNumberOfSteps(flowSlug)) {
return 'COMPLETED_FLOW'
return COMPLETED_FLOW
}

const startedFlow = flowResponses?.find((r) => r.flowSlug === flowSlug)
if (startedFlow) {
return 'STARTED_FLOW'
return STARTED_FLOW
}
return null
}
Expand All @@ -92,7 +107,7 @@ export function useFlows() {
if (flowResponses) {
// Add all unique flowResponses by stepId to flowResponsesFound
flowResponses.forEach((r) => {
if (r.flowSlug === flowSlug && r.actionType === 'COMPLETED_STEP') {
if (r.flowSlug === flowSlug && r.actionType === COMPLETED_STEP) {
const found = flowResponsesFound.find((fr) => fr.stepId === r.stepId)
if (!found) {
flowResponsesFound.push(r)
Expand All @@ -102,9 +117,8 @@ export function useFlows() {
}

return (
flowResponsesFound?.filter(
(r) => r.flowSlug === flowSlug && r.actionType === 'COMPLETED_STEP'
).length ?? 0
flowResponsesFound?.filter((r) => r.flowSlug === flowSlug && r.actionType === COMPLETED_STEP)
.length ?? 0
)
}

Expand All @@ -119,7 +133,7 @@ export function useFlows() {
return {
getFlow,
getFlowData,
isLoading,
isLoading: isLoadingUserState || isLoading,
getStepStatus,
getFlowSteps,
markStepStarted,
Expand Down

0 comments on commit b8c97fa

Please sign in to comment.