All files / src/store/slices/student StudentFeatureFlags.js

83.33% Statements 40/48
81.48% Branches 22/27
81.81% Functions 9/11
83.33% Lines 40/48

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108          2x                       2x                       2x                                 2x     2x 2x 2x 2x 2x 2x 2x 2x       1x   1x 1x     8x 8x 8x 8x 8x 8x 8x 8x 8x     1x 1x     1x 1x     3x 3x 3x 3x 1x   3x 1x   3x 1x       2x 2x         2x    
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { StudentFeaturesAPI } from "@/api/student/StudentFeaturesAPI";
import { normalizeFeatureList } from "@/utils/features/featureAccess";
 
// Async thunk to fetch student's district features
export const fetchStudentDistrictFeatures = createAsyncThunk(
    "student/features/fetchDistrictFeatures",
    async (_, { rejectWithValue }) => {
        try {
            const response = await StudentFeaturesAPI.getEffectiveFeatures();
            return response;
        } catch (error) {
            return rejectWithValue(error.response?.data || error);
        }
    }
);
 
export const fetchStudentOrganization = createAsyncThunk(
    "student/features/fetchOrganization",
    async (_, { rejectWithValue }) => {
        try {
            const response = await StudentFeaturesAPI.getOrganization();
            return response;
        } catch (error) {
            return rejectWithValue(error.response?.data || error);
        }
    }
);
 
const StudentFeatureFlags = createSlice({
    name: "StudentFeatureFlags",
    initialState: {
        districtId: null,
        currentPlan: null,
        planName: null,
        districtFeatures: [],
        maintenanceMode: false,
        organization: null,
        organizationLoading: false,
        organizationError: null,
        isLoading: false,
        hasErrors: null,
        lastFetched: null,
    },
    reducers: {
        clearErrors: (state) => {
            state.hasErrors = null;
        },
        resetFeatures: (state) => {
            state.districtId = null;
            state.currentPlan = null;
            state.planName = null;
            state.districtFeatures = [];
            state.maintenanceMode = false;
            state.organization = null;
            state.organizationError = null;
            state.lastFetched = null;
        },
    },
    extraReducers: (builder) => {
        builder
            .addCase(fetchStudentDistrictFeatures.pending, (state) => {
                state.isLoading = true;
                state.hasErrors = null;
            })
            .addCase(fetchStudentDistrictFeatures.fulfilled, (state, action) => {
                const payload = action.payload || {};
                state.isLoading = false;
                state.districtId = payload.district_id ?? null;
                state.currentPlan = payload.current_plan ?? null;
                state.planName = payload.plan_name ?? null;
                state.districtFeatures = normalizeFeatureList(payload.features || payload.results || []);
                state.maintenanceMode = Boolean(payload.maintenance_mode);
                state.lastFetched = new Date().toISOString();
                state.hasErrors = null;
            })
            .addCase(fetchStudentDistrictFeatures.rejected, (state, action) => {
                state.isLoading = false;
                state.hasErrors = action.payload?.detail || action.error.message;
            })
            .addCase(fetchStudentOrganization.pending, (state) => {
                state.organizationLoading = true;
                state.organizationError = null;
            })
            .addCase(fetchStudentOrganization.fulfilled, (state, action) => {
                state.organizationLoading = false;
                state.organization = action.payload || null;
                state.organizationError = null;
                if (action.payload?.district_id) {
                    state.districtId = action.payload.district_id;
                }
                if (action.payload?.current_plan) {
                    state.currentPlan = action.payload.current_plan;
                }
                if (action.payload?.plan_name) {
                    state.planName = action.payload.plan_name;
                }
            })
            .addCase(fetchStudentOrganization.rejected, (state, action) => {
                state.organizationLoading = false;
                state.organizationError = action.payload?.detail || action.error.message;
            });
    },
});
 
export const { clearErrors, resetFeatures } = StudentFeatureFlags.actions;
export default StudentFeatureFlags;