MOON
Server: Apache
System: Linux nserver.cafsindia.com 4.18.0-553.123.2.lve.el8.x86_64 #1 SMP Thu May 7 23:17:13 UTC 2026 x86_64
User: cafsindia (1002)
PHP: 8.2.30
Disabled: NONE
Upload Files
File: /home/cafsindia/www/wp-content/plugins/redux-framework/extendify-sdk/src/Assist/state/Tours.js
import { useEffect, useState } from '@wordpress/element'
import create from 'zustand'
import { devtools, persist } from 'zustand/middleware'
import { getTourData, saveTourData } from '../api/Data'

const state = (set, get) => ({
    currentTour: null,
    currentStep: 0,
    progress: [],
    startTour(tourData) {
        set({ currentTour: tourData })
        // See if the tour already was opened
        const tour = get().trackTourProgress(tourData.id)
        // Increment the opened count
        get().updateProgress(tour.id, {
            openedCount: tour.openedCount + 1,
            lastAction: 'started',
        })
    },
    completeCurrentTour() {
        if (!get().currentTour) return
        const tour = get().findTourProgress(get().currentTour.id)
        // if already completed, dont update the completedAt
        if (!get().isCompleted(tour.id)) {
            get().updateProgress(tour.id, {
                completedAt: new Date().toISOString(),
                lastAction: 'completed',
            })
        }
        // Track how many times it was completed
        get().updateProgress(tour.id, {
            completedCount: tour.completedCount + 1,
            lastAction: 'completed',
        })
        set({ currentTour: null, currentStep: 0 })
    },
    closeForRedirect() {
        if (!get().currentTour) return
        const tour = get().findTourProgress(get().currentTour.id)
        // update last action
        get().updateProgress(tour?.id ?? get().currentTour, {
            lastAction: 'redirected',
        })
        set({ currentTour: null, currentStep: 0 })
    },
    closeCurrentTourManually() {
        const tour = get().findTourProgress(get().currentTour.id)
        // Track how many times it was closed early
        get().updateProgress(tour.id, {
            closedManuallyCount: tour.closedManuallyCount + 1,
            lastAction: 'closed-manually',
        })
        set({ currentTour: null, currentStep: 0 })
    },
    closeCurrentTourFromError() {
        if (!get().currentTour) return console.error('No tour found')
        const tour = get().findTourProgress(get().currentTour.id)
        if (!tour) return console.error('No tour found')
        get().updateProgress(tour.id, {
            errored: true,
            lastAction: 'closed-by-caught-error',
        })
        set({ currentTour: null, currentStep: 0 })
    },
    findTourProgress(tourId) {
        return get().progress.find((tour) => tour.id === tourId)
    },
    isCompleted(tourId) {
        return get().findTourProgress(tourId)?.completedAt
    },
    isSeen(tourId) {
        return get().findTourProgress(tourId)?.firstSeenAt
    },
    trackTourProgress(tourId) {
        // If we are already tracking it, return that
        if (get().findTourProgress(tourId)) {
            return get().findTourProgress(tourId)
        }
        set((state) => ({
            progress: [
                ...state.progress,
                {
                    id: tourId,
                    firstSeenAt: new Date().toISOString(),
                    updatedAt: new Date().toISOString(),
                    completedAt: null,
                    lastAction: 'init',
                    currentStep: 0,
                    openedCount: 0,
                    closedManuallyCount: 0,
                    completedCount: 0,
                    errored: false,
                },
            ],
        }))
        return get().findTourProgress(tourId)
    },
    updateProgress(tourId, update) {
        const lastAction = update?.lastAction ?? 'unknown'
        set((state) => {
            const progress = state.progress.map((tour) => {
                if (tour.id === tourId) {
                    return {
                        ...tour,
                        ...update,
                        lastAction,
                        updatedAt: new Date().toISOString(),
                    }
                }
                return tour
            })
            return { progress }
        })
    },
    hasNextStep() {
        if (!get().currentTour) return false
        return get().currentStep < get().currentTour.steps.length - 1
    },
    nextStep() {
        if (!get().hasNextStep()) {
            get().closeCurrentTourFromError()
            return
        }
        const tour = get().currentTour
        const next = get().currentStep + 1
        set(() => ({ currentStep: next }))
        get().updateProgress(tour.id, {
            currentStep: next,
            lastAction: 'next',
        })
    },
    hasPreviousStep() {
        if (!get().currentTour) return false
        return get().currentStep > 0
    },
    prevStep() {
        if (!get().hasPreviousStep()) {
            get().closeCurrentTourFromError()
            return
        }
        const tour = get().currentTour
        const prev = get().currentStep - 1
        set(() => ({ currentStep: prev }))
        get().updateProgress(tour.id, {
            currentStep: prev,
            lastAction: 'prev',
        })
    },
    goToStep(step) {
        const tour = get().currentTour
        // Check that the step is valid
        if (step < 0 || step > tour.steps.length - 1) return
        get().updateProgress(tour.id, {
            currentStep: step,
            lastAction: `go-to-step-${step}`,
        })
        set(() => ({ currentStep: step }))
    },
})

const storage = {
    getItem: async () => JSON.stringify(await getTourData()),
    setItem: async (_, value) => await saveTourData(value),
    removeItem: () => undefined,
}

export const useTourStore = create(
    persist(devtools(state, { name: 'Extendify Assist Tour Progress' }), {
        name: 'extendify-assist-tour-progress',
        getStorage: () => storage,
        partialize: (state) => {
            // return without currentTour or currentStep
            // eslint-disable-next-line no-unused-vars
            const { currentTour, currentStep, ...newState } = state
            return newState
        },
    }),
    state,
)

/* Hook useful for when you need to wait on the async state to hydrate */
export const useTourStoreReady = () => {
    const [hydrated, setHydrated] = useState(useTourStore.persist.hasHydrated)
    useEffect(() => {
        const unsubFinishHydration = useTourStore.persist.onFinishHydration(
            () => setHydrated(true),
        )
        return () => {
            unsubFinishHydration()
        }
    }, [])
    return hydrated
}