• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kiva / ui / 18756510873

23 Oct 2025 05:20PM UTC coverage: 49.67% (-0.5%) from 50.172%
18756510873

Pull #6281

github

web-flow
Merge 6794eb6aa into 1cc04a665
Pull Request #6281: feat: mp-2014 / Display Thank You Page and Prompt for New Achievement After Goal Completion

1815 of 3904 branches covered (46.49%)

Branch coverage included in aggregate %.

0 of 51 new or added lines in 1 file covered. (0.0%)

2699 of 5184 relevant lines covered (52.06%)

260.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/composables/useGoalData.js
1
import {
2
        computed,
3
        inject,
4
        ref,
5
} from 'vue';
6

7
import useGoalDataQuery from '#src/graphql/query/useGoalData.graphql';
8
import useGoalDataProgressQuery from '#src/graphql/query/useGoalDataProgress.graphql';
9
import logFormatter from '#src/util/logFormatter';
10
import { createUserPreferences, updateUserPreferences } from '#src/util/userPreferenceUtils';
11

12
import {
13
        ID_BASIC_NEEDS,
14
        ID_CLIMATE_ACTION,
15
        ID_REFUGEE_EQUALITY,
16
        ID_SUPPORT_ALL,
17
        ID_US_ECONOMIC_EQUALITY,
18
        ID_WOMENS_EQUALITY,
19
} from '#src/composables/useBadgeData';
20

NEW
21
const GOAL_DISPLAY_MAP = {
×
22
        [ID_BASIC_NEEDS]: 'basic needs loans',
23
        [ID_CLIMATE_ACTION]: 'eco-friendly loans',
24
        [ID_REFUGEE_EQUALITY]: 'refugees',
25
        [ID_SUPPORT_ALL]: 'loans',
26
        [ID_US_ECONOMIC_EQUALITY]: 'U.S. entrepreneurs',
27
        [ID_WOMENS_EQUALITY]: 'women',
28
};
29

30
function getGoalDisplayName(category) {
NEW
31
        return GOAL_DISPLAY_MAP[category] || 'loans';
×
32
}
33

34
/**
35
 * Vue composable for loading and managing user goal data
36
 *
37
 * @param {Object} options - Configuration options
38
 * @param {Array} options.loans - List of loans to count toward goals
39
 * @param {Object} options.apollo - Apollo client instance (optional, will use inject if not provided)
40
 * @returns Goal data and utilities
41
 */
42
export default function useGoalData({ loans, apollo: apolloParam }) {
NEW
43
        const apollo = apolloParam || inject('apollo');
×
44

NEW
45
        const allTimeProgress = ref([]);
×
NEW
46
        const loading = ref(true);
×
NEW
47
        const totalLoanCount = ref(null);
×
NEW
48
        const userGoal = ref(null);
×
NEW
49
        const userPreferences = ref(null);
×
50

51
        async function loadPreferences(fetchPolicy = 'cache-first') {
×
NEW
52
                try {
×
NEW
53
                        const response = await apollo.query({ query: useGoalDataQuery, fetchPolicy });
×
NEW
54
                        const prefsData = response.data?.my?.userPreferences || null;
×
NEW
55
                        totalLoanCount.value = response.data?.my?.loans?.totalCount || 0;
×
NEW
56
                        userPreferences.value = prefsData;
×
NEW
57
                        return prefsData ? JSON.parse(prefsData.preferences || '{}') : {};
×
58
                } catch (error) {
NEW
59
                        logFormatter(error, 'Failed to load preferences');
×
NEW
60
                        return null;
×
61
                }
62
        }
63

64
        async function loadProgress(fetchPolicy = 'cache-first') {
×
NEW
65
                try {
×
NEW
66
                        const loanIds = loans.map(loan => loan.id);
×
NEW
67
                        const response = await apollo.query({
×
68
                                query: useGoalDataProgressQuery,
69
                                variables: { loanIds },
70
                                fetchPolicy
71
                        });
NEW
72
                        allTimeProgress.value = response?.data?.postCheckoutAchievements?.allTimeProgress || [];
×
NEW
73
                        return true;
×
74
                } catch (error) {
NEW
75
                        logFormatter(error, 'Failed to load progress');
×
NEW
76
                        return null;
×
77
                }
78
        }
79

80
        function setGoalState(parsedPrefs) {
NEW
81
                if (!parsedPrefs) return;
×
NEW
82
                const goals = parsedPrefs.goals || [];
×
NEW
83
                userGoal.value = { ...goals[0] };
×
84
        }
85

86
        async function storeGoalPreferences(updates) {
NEW
87
                if (!userPreferences.value) {
×
NEW
88
                        await createUserPreferences(apollo, { goals: [] });
×
NEW
89
                        await loadPreferences('network-only'); // Reload after create
×
90
                }
NEW
91
                const parsedPrefs = JSON.parse(userPreferences.value?.preferences || '{}');
×
NEW
92
                const goals = parsedPrefs.goals || [];
×
NEW
93
                const goalIndex = goals.findIndex(g => g.goalName === updates.goalName);
×
NEW
94
                if (goalIndex !== -1) goals[goalIndex] = { ...goals[goalIndex], ...updates };
×
NEW
95
                else goals.push(updates);
×
NEW
96
                await updateUserPreferences(apollo, userPreferences.value, parsedPrefs, { goals });
×
NEW
97
                setGoalState({ goals }); // Refresh local state after update
×
98
        }
99

NEW
100
        const goalProgress = computed(() => {
×
NEW
101
                if (userGoal.value?.category === ID_SUPPORT_ALL) return totalLoanCount.value || 0;
×
NEW
102
                const totalProgress = allTimeProgress.value.find(
×
NEW
103
                        entry => entry.achievementId === userGoal.value?.category
×
104
                )?.totalProgress || 0;
NEW
105
                const adjustedProgress = totalProgress - (userGoal.value?.loanTotalAtStart || 0);
×
NEW
106
                return Math.max(adjustedProgress, 0);
×
107
        });
108

NEW
109
        const userGoalAchieved = computed(() => goalProgress.value >= userGoal.value?.target);
×
110

111
        async function runComposable() {
NEW
112
                loading.value = true;
×
NEW
113
                const parsedPrefs = await loadPreferences();
×
NEW
114
                await loadProgress();
×
NEW
115
                setGoalState(parsedPrefs);
×
116
                // Auto-update if active goal achieved
NEW
117
                if (userGoal.value && userGoalAchieved.value) {
×
NEW
118
                        await storeGoalPreferences({
×
119
                                goalName: userGoal.value.goalName,
120
                                dateStarted: userGoal.value.dateStarted,
121
                                target: userGoal.value.target,
122
                                count: userGoal.value.count,
123
                                status: 'completed',
124
                        });
125
                }
NEW
126
                loading.value = false;
×
127
        }
128

NEW
129
        return {
×
130
                getGoalDisplayName,
131
                goalProgress,
132
                loading,
133
                runComposable,
134
                storeGoalPreferences,
135
                userGoal,
136
                userGoalAchieved,
137
        };
138
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc