diff --git a/packages/webapp/src/components/Animals/RemoveAnimalsModal/index.tsx b/packages/webapp/src/components/Animals/RemoveAnimalsModal/index.tsx index 471107a2a5..049e28d07d 100644 --- a/packages/webapp/src/components/Animals/RemoveAnimalsModal/index.tsx +++ b/packages/webapp/src/components/Animals/RemoveAnimalsModal/index.tsx @@ -25,7 +25,7 @@ import { ReactComponent as WarningIcon } from '../../../assets/images/warning.sv import { ReactComponent as CheckIcon } from '../../../assets/images/check-circle.svg'; import { useTranslation } from 'react-i18next'; import { getLocalDateInYYYYDDMM } from '../../../util/date'; -import { useGetAnimalRemovalReasonsQuery } from '../../../store/api/apiSlice'; +import { useGetAnimalRemovalReasonsQuery } from '../../../store/api/libraryApiSlice'; import type { AnimalRemovalReasonKeys } from '../../../store/api/types'; const REASON = 'reason'; diff --git a/packages/webapp/src/components/Task/MovementTask/index.tsx b/packages/webapp/src/components/Task/MovementTask/index.tsx index b3c00b837f..2392bf6f88 100644 --- a/packages/webapp/src/components/Task/MovementTask/index.tsx +++ b/packages/webapp/src/components/Task/MovementTask/index.tsx @@ -21,7 +21,7 @@ import ReactSelect from '../../Form/ReactSelect'; import Input, { getInputErrors } from '../../Form/Input'; import { hookFormMaxCharsValidation } from '../../Form/hookformValidationUtils'; import styles from './styles.module.scss'; -import { useGetAnimalMovementPurposesQuery } from '../../../store/api/apiSlice'; +import { useGetAnimalMovementPurposesQuery } from '../../../store/api/libraryApiSlice'; import { AnimalMovementPurpose } from '../../../store/api/types'; type PureMovementTaskProps = UseFormReturn & { diff --git a/packages/webapp/src/components/Task/SoilAmendmentTask/index.tsx b/packages/webapp/src/components/Task/SoilAmendmentTask/index.tsx index 5fd642ed01..0ebdc7e2f8 100644 --- a/packages/webapp/src/components/Task/SoilAmendmentTask/index.tsx +++ b/packages/webapp/src/components/Task/SoilAmendmentTask/index.tsx @@ -20,7 +20,7 @@ import { useGetSoilAmendmentMethodsQuery, useGetSoilAmendmentPurposesQuery, useGetSoilAmendmentFertiliserTypesQuery, -} from '../../../store/api/apiSlice'; +} from '../../../store/api/libraryApiSlice'; import ReactSelect from '../../Form/ReactSelect'; import Input, { getInputErrors } from '../../Form/Input'; import { hookFormMaxCharsValidation } from '../../Form/hookformValidationUtils'; diff --git a/packages/webapp/src/containers/AddFarm/saga.js b/packages/webapp/src/containers/AddFarm/saga.js index e5c640169d..d140659652 100644 --- a/packages/webapp/src/containers/AddFarm/saga.js +++ b/packages/webapp/src/containers/AddFarm/saga.js @@ -29,8 +29,7 @@ import { axios, getHeader } from '../saga'; import { createAction } from '@reduxjs/toolkit'; import i18n from '../../locales/i18n'; import { enqueueErrorSnackbar } from '../Snackbar/snackbarSlice'; -import { invalidateTags } from '../../store/api/apiSlice'; -import { FarmLibraryTags, FarmTags } from '../../store/api/apiTags'; +import { resetApiState } from '../../store/api/apiSlice'; const patchRoleUrl = (farm_id, user_id) => `${userFarmUrl}/role/farm/${farm_id}/user/${user_id}`; const patchFarmUrl = (farm_id) => `${farmUrl}/owner_operated/${farm_id}`; @@ -62,7 +61,7 @@ export function* postFarmSaga({ payload: { showFarmNameCharacterLimitExceededErr yield call(axios.patch, patchStepUrl(farm_id, user_id), step, getHeader(user_id, farm_id)); // Clear old farm RTK Query data - yield put(invalidateTags([...FarmTags, ...FarmLibraryTags])); + yield put(resetApiState()); const user = getUserResult?.data; yield put( diff --git a/packages/webapp/src/containers/Animals/AddAnimals/AddAnimalDetails/usePopulateDetails.ts b/packages/webapp/src/containers/Animals/AddAnimals/AddAnimalDetails/usePopulateDetails.ts index 0f9022bc28..4f15980170 100644 --- a/packages/webapp/src/containers/Animals/AddAnimals/AddAnimalDetails/usePopulateDetails.ts +++ b/packages/webapp/src/containers/Animals/AddAnimals/AddAnimalDetails/usePopulateDetails.ts @@ -24,7 +24,7 @@ import { DetailsFields, } from '../types'; import { AnimalOrBatchKeys } from '../../types'; -import { useGetAnimalUsesQuery } from '../../../../store/api/apiSlice'; +import { useGetAnimalUsesQuery } from '../../../../store/api/libraryApiSlice'; import { parseUniqueDefaultId } from '../../../../util/animal'; export const usePopulateDetails = ( diff --git a/packages/webapp/src/containers/Animals/AddAnimals/AddAnimalSummary/index.tsx b/packages/webapp/src/containers/Animals/AddAnimals/AddAnimalSummary/index.tsx index 99627c8a86..8449542bc2 100644 --- a/packages/webapp/src/containers/Animals/AddAnimals/AddAnimalSummary/index.tsx +++ b/packages/webapp/src/containers/Animals/AddAnimals/AddAnimalSummary/index.tsx @@ -17,12 +17,14 @@ import { useHistory } from 'react-router-dom'; import { AddAnimalsSummaryCard } from '../../../../components/Animals/AddAnimalsSummaryCard'; import { ANIMALS_INVENTORY_URL } from '../../../../util/siteMapConstants'; import { - useGetAnimalSexesQuery, useGetCustomAnimalBreedsQuery, useGetCustomAnimalTypesQuery, - useGetDefaultAnimalBreedsQuery, useGetDefaultAnimalTypesQuery, } from '../../../../store/api/apiSlice'; +import { + useGetAnimalSexesQuery, + useGetDefaultAnimalBreedsQuery, +} from '../../../../store/api/libraryApiSlice'; import useQueries from '../../../../hooks/api/useQueries'; import { formatDBAnimalsToSummary, formatDBBatchesToSummary } from '../../AddAnimals/utils'; import { Animal, AnimalBatch } from '../../../../store/api/types'; diff --git a/packages/webapp/src/containers/Animals/AddAnimals/index.tsx b/packages/webapp/src/containers/Animals/AddAnimals/index.tsx index 1ca167006f..7d4b76b876 100644 --- a/packages/webapp/src/containers/Animals/AddAnimals/index.tsx +++ b/packages/webapp/src/containers/Animals/AddAnimals/index.tsx @@ -22,11 +22,8 @@ import { ContextForm, Variant } from '../../../components/Form/ContextForm/'; import AddAnimalBasics, { animalBasicsDefaultValues } from './AddAnimalBasics'; import AddAnimalDetails from './AddAnimalDetails'; import AddAnimalSummary from './AddAnimalSummary'; -import { - useAddAnimalBatchesMutation, - useAddAnimalsMutation, - useGetAnimalOriginsQuery, -} from '../../../store/api/apiSlice'; +import { useAddAnimalBatchesMutation, useAddAnimalsMutation } from '../../../store/api/apiSlice'; +import { useGetAnimalOriginsQuery } from '../../../store/api/libraryApiSlice'; import { Animal, AnimalBatch } from '../../../store/api/types'; import { enqueueErrorSnackbar, enqueueSuccessSnackbar } from '../../Snackbar/snackbarSlice'; import { formatAnimalDetailsToDBStructure, formatBatchDetailsToDBStructure } from './utils'; diff --git a/packages/webapp/src/containers/Animals/AddAnimals/useAnimalOptions.ts b/packages/webapp/src/containers/Animals/AddAnimals/useAnimalOptions.ts index f55be5c53c..daaad08bcc 100644 --- a/packages/webapp/src/containers/Animals/AddAnimals/useAnimalOptions.ts +++ b/packages/webapp/src/containers/Animals/AddAnimals/useAnimalOptions.ts @@ -16,14 +16,16 @@ import { useGetDefaultAnimalTypesQuery, useGetCustomAnimalTypesQuery, - useGetDefaultAnimalBreedsQuery, useGetCustomAnimalBreedsQuery, +} from '../../../store/api/apiSlice'; +import { + useGetDefaultAnimalBreedsQuery, useGetAnimalSexesQuery, useGetAnimalIdentifierTypesQuery, useGetAnimalIdentifierColorsQuery, useGetAnimalOriginsQuery, useGetAnimalUsesQuery, -} from '../../../store/api/apiSlice'; +} from '../../../store/api/libraryApiSlice'; import { useTranslation } from 'react-i18next'; import { generateUniqueAnimalId } from '../../../util/animal'; import { ANIMAL_ID_PREFIX } from '../types'; diff --git a/packages/webapp/src/containers/Animals/Inventory/useAnimalInventory.tsx b/packages/webapp/src/containers/Animals/Inventory/useAnimalInventory.tsx index eed4bcaed3..19198cdd2f 100644 --- a/packages/webapp/src/containers/Animals/Inventory/useAnimalInventory.tsx +++ b/packages/webapp/src/containers/Animals/Inventory/useAnimalInventory.tsx @@ -19,10 +19,12 @@ import { useGetAnimalBatchesQuery, useGetCustomAnimalBreedsQuery, useGetCustomAnimalTypesQuery, - useGetDefaultAnimalBreedsQuery, useGetDefaultAnimalTypesQuery, - useGetAnimalSexesQuery, } from '../../../store/api/apiSlice'; +import { + useGetDefaultAnimalBreedsQuery, + useGetAnimalSexesQuery, +} from '../../../store/api/libraryApiSlice'; import useQueries from '../../../hooks/api/useQueries'; import { Animal, diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 387d5fbd58..98f3edc8b1 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -27,14 +27,16 @@ import FixedHeaderContainer from '../../../components/Animals/FixedHeaderContain import { addNullstoMissingFields } from './utils'; import { useInitialAnimalData } from './useInitialAnimalData'; import { - useGetAnimalOriginsQuery, useUpdateAnimalsMutation, useUpdateAnimalBatchesMutation, useGetCustomAnimalBreedsQuery, useGetCustomAnimalTypesQuery, - useGetDefaultAnimalBreedsQuery, useGetDefaultAnimalTypesQuery, } from '../../../store/api/apiSlice'; +import { + useGetAnimalOriginsQuery, + useGetDefaultAnimalBreedsQuery, +} from '../../../store/api/libraryApiSlice'; import { locationsSelector } from '../../locationSlice'; import { formatAnimalDetailsToDBStructure, diff --git a/packages/webapp/src/containers/Filter/Animals/index.tsx b/packages/webapp/src/containers/Filter/Animals/index.tsx index cd55655963..832f2c8626 100644 --- a/packages/webapp/src/containers/Filter/Animals/index.tsx +++ b/packages/webapp/src/containers/Filter/Animals/index.tsx @@ -23,10 +23,12 @@ import { FilterType, type ComponentFilter } from '../../../components/Filter/typ import { useGetDefaultAnimalTypesQuery, useGetCustomAnimalTypesQuery, - useGetDefaultAnimalBreedsQuery, useGetCustomAnimalBreedsQuery, - useGetAnimalSexesQuery, } from '../../../store/api/apiSlice'; +import { + useGetDefaultAnimalBreedsQuery, + useGetAnimalSexesQuery, +} from '../../../store/api/libraryApiSlice'; import { generateUniqueAnimalId } from '../../../util/animal'; import { useVisibleBreeds } from './useVisibleBreeds'; import { locationsSelector } from '../../locationSlice'; diff --git a/packages/webapp/src/containers/Filter/ProductInventory/index.tsx b/packages/webapp/src/containers/Filter/ProductInventory/index.tsx index 001b7132f8..07de8c9df7 100644 --- a/packages/webapp/src/containers/Filter/ProductInventory/index.tsx +++ b/packages/webapp/src/containers/Filter/ProductInventory/index.tsx @@ -17,7 +17,7 @@ import { useTranslation } from 'react-i18next'; import FilterGroup from '../../../components/Filter/FilterGroup'; import type { ReduxFilterEntity, ContainerOnChangeCallback, FilterState } from '../types'; import { FilterType, type ComponentFilter } from '../../../components/Filter/types'; -import { useGetSoilAmendmentFertiliserTypesQuery } from '../../../store/api/apiSlice'; +import { useGetSoilAmendmentFertiliserTypesQuery } from '../../../store/api/libraryApiSlice'; import { InventoryFilterKeys } from './types'; import { sortFilterOptions } from '../../../components/Filter/utils'; diff --git a/packages/webapp/src/containers/ProductInventory/ProductForm/SoilAmendmentProductForm.tsx b/packages/webapp/src/containers/ProductInventory/ProductForm/SoilAmendmentProductForm.tsx index d0bea09e90..c10536677c 100644 --- a/packages/webapp/src/containers/ProductInventory/ProductForm/SoilAmendmentProductForm.tsx +++ b/packages/webapp/src/containers/ProductInventory/ProductForm/SoilAmendmentProductForm.tsx @@ -14,7 +14,7 @@ */ import { shallowEqual, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; -import { useGetSoilAmendmentFertiliserTypesQuery } from '../../../store/api/apiSlice'; +import { useGetSoilAmendmentFertiliserTypesQuery } from '../../../store/api/libraryApiSlice'; import PureSoilAmendmentProductForm from '../../../components/ProductInventory/ProductForm/PureSoilAmendmentProductForm'; import { userFarmSelector } from '../../userFarmSlice'; import { certifierSurveySelector } from '../../OrganicCertifierSurvey/slice'; diff --git a/packages/webapp/src/containers/Task/saga.js b/packages/webapp/src/containers/Task/saga.js index ad6fd54934..6131774420 100644 --- a/packages/webapp/src/containers/Task/saga.js +++ b/packages/webapp/src/containers/Task/saga.js @@ -112,7 +112,7 @@ import { getMovementTaskBody, getSoilSampleTaskBody, } from './sagaUtils'; -import { api } from '../../store/api/apiSlice'; +import { invalidateTags } from '../../store/api/apiSlice'; const taskTypeEndpoint = [ 'cleaning_task', @@ -692,7 +692,7 @@ export function* createTaskSaga({ payload }) { task_translation_key === 'HARVEST_TASK' ? result.data[0] : result.data; yield call(getTasksSuccessSaga, { payload: isHarvest ? result.data : [result.data] }); if (task_translation_key === 'IRRIGATION_TASK') { - yield put(api.util.invalidateTags(['IrrigationPrescriptions'])); + yield put(invalidateTags(['IrrigationPrescriptions'])); } if (alreadyCompleted) { if (['CLEANING_TASK', 'PEST_CONTROL_TASK'].includes(task_translation_key)) { @@ -905,7 +905,7 @@ export function* completeTaskSaga({ payload: { task_id, data, returnPath } }) { }); if (task_translation_key === 'MOVEMENT_TASK') { - yield put(api.util.invalidateTags(['Animals', 'AnimalBatches'])); + yield put(invalidateTags(['Animals', 'AnimalBatches'])); } } } catch (e) { @@ -1096,7 +1096,7 @@ export function* deleteTaskSaga({ payload: data }) { } yield put(deleteTaskSuccess(result.data)); if (task_type.task_translation_key === 'IRRIGATION_TASK') { - yield put(api.util.invalidateTags(['IrrigationPrescriptions'])); + yield put(invalidateTags(['IrrigationPrescriptions'])); } yield put(enqueueSuccessSnackbar(i18n.t('TASK.DELETE.SUCCESS'))); } diff --git a/packages/webapp/src/containers/saga.js b/packages/webapp/src/containers/saga.js index 3e49cdd967..09ad6b58ac 100644 --- a/packages/webapp/src/containers/saga.js +++ b/packages/webapp/src/containers/saga.js @@ -151,14 +151,14 @@ import { onLoadingWatercourseFail, onLoadingWatercourseStart, } from './watercourseSlice'; -import { api, invalidateTags } from '../store/api/apiSlice'; -import { FarmLibraryTags, FarmTags } from '../store/api/apiTags'; +import { api, resetApiState } from '../store/api/apiSlice'; import { getSoilSampleLocationsSuccess, onLoadingSoilSampleLocationFail, } from './soilSampleLocationSlice'; import { getFieldWorkTypes } from './Task/FieldWorkTask/saga'; import { getIrrigationTaskTypes } from './Task/IrrigationTaskTypes/saga'; +import { libraryApi } from '../store/api/libraryApiSlice'; const logUserInfoUrl = () => `${url}/userLog`; const getCropsByFarmIdUrl = (farm_id) => `${url}/crop/farm/${farm_id}`; @@ -617,10 +617,10 @@ export function* fetchAllSaga() { call(getAllUserFarmsByFarmIDSaga), put(getFieldWorkTypes()), put(getIrrigationTaskTypes()), - put(api.endpoints.getSoilAmendmentMethods.initiate()), - put(api.endpoints.getSoilAmendmentPurposes.initiate()), - put(api.endpoints.getSoilAmendmentFertiliserTypes.initiate()), - put(api.endpoints.getAnimalMovementPurposes.initiate()), + put(libraryApi.endpoints.getSoilAmendmentMethods.initiate()), + put(libraryApi.endpoints.getSoilAmendmentPurposes.initiate()), + put(libraryApi.endpoints.getSoilAmendmentFertiliserTypes.initiate()), + put(libraryApi.endpoints.getAnimalMovementPurposes.initiate()), ]; yield all(isAdmin ? [...tasks, ...adminTasks] : tasks); @@ -632,15 +632,15 @@ export function* fetchAllSaga() { put(api.endpoints.getAnimals.initiate()), put(api.endpoints.getAnimalBatches.initiate()), put(api.endpoints.getDefaultAnimalTypes.initiate()), - put(api.endpoints.getDefaultAnimalBreeds.initiate()), + put(libraryApi.endpoints.getDefaultAnimalBreeds.initiate()), put(api.endpoints.getCustomAnimalTypes.initiate()), put(api.endpoints.getCustomAnimalBreeds.initiate()), - put(api.endpoints.getAnimalSexes.initiate()), - put(api.endpoints.getAnimalIdentifierTypes.initiate()), - put(api.endpoints.getAnimalIdentifierColors.initiate()), - put(api.endpoints.getAnimalMovementPurposes.initiate()), - put(api.endpoints.getAnimalOrigins.initiate()), - put(api.endpoints.getAnimalUses.initiate()), + put(libraryApi.endpoints.getAnimalSexes.initiate()), + put(libraryApi.endpoints.getAnimalIdentifierTypes.initiate()), + put(libraryApi.endpoints.getAnimalIdentifierColors.initiate()), + put(libraryApi.endpoints.getAnimalMovementPurposes.initiate()), + put(libraryApi.endpoints.getAnimalOrigins.initiate()), + put(libraryApi.endpoints.getAnimalUses.initiate()), ]); const { @@ -658,7 +658,7 @@ export function* fetchAllSaga() { export function* clearOldFarmStateSaga() { yield put(resetTasks()); yield put(resetDateRange()); - yield put(invalidateTags([...FarmTags, ...FarmLibraryTags])); + yield put(resetApiState()); // Reset finance loading state yield put(setIsFetchingData(true)); diff --git a/packages/webapp/src/store/api/apiSlice.ts b/packages/webapp/src/store/api/apiSlice.ts index 61b39fc107..a57ff432fa 100644 --- a/packages/webapp/src/store/api/apiSlice.ts +++ b/packages/webapp/src/store/api/apiSlice.ts @@ -13,27 +13,14 @@ * GNU General Public License for more details, see . */ -import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; -import { RootState } from '../store'; +import { createApi } from '@reduxjs/toolkit/query/react'; import { animalsUrl, animalBatchesUrl, customAnimalBreedsUrl, customAnimalTypesUrl, - defaultAnimalBreedsUrl, defaultAnimalTypesUrl, - animalSexesUrl, - animalIdentifierTypesUrl, - animalIdentifierColorsUrl, - animalOriginsUrl, - animalUsesUrl, - animalRemovalReasonsUrl, - soilAmendmentMethodsUrl, - soilAmendmentPurposesUrl, - soilAmendmentFertiliserTypesUrl, productUrl, - url, - animalMovementPurposesUrl, sensorUrl, farmAddonUrl, irrigationPrescriptionUrl, @@ -43,19 +30,8 @@ import type { AnimalBatch, CustomAnimalBreed, CustomAnimalType, - DefaultAnimalBreed, DefaultAnimalType, - AnimalSex, - AnimalRemovalReason, - SoilAmendmentMethod, - SoilAmendmentPurpose, - SoilAmendmentFertiliserType, SoilAmendmentProduct, - AnimalIdentifierType, - AnimalIdentifierColor, - AnimalOrigin, - AnimalUse, - AnimalMovementPurpose, SensorData, FarmAddon, SensorReadings, @@ -65,6 +41,7 @@ import type { import { addDaysToDate } from '../../util/date'; import { API_TAGS, ApiTag } from './apiTags'; +import { BASE_QUERY } from './constants'; /** * Invalidates one or more RTK Query cache tags. @@ -77,28 +54,10 @@ import { API_TAGS, ApiTag } from './apiTags'; * which can be dispatched directly or used inside a saga (e.g., `yield put(...)`). */ export const invalidateTags = (tags: ApiTag[]) => api.util.invalidateTags(tags); - -const NON_JSON_ENDPOINT_KEYS = new Set(['addSupportTicket']); +export const resetApiState = () => api.util.resetApiState(); export const api = createApi({ - baseQuery: fetchBaseQuery({ - baseUrl: url, - prepareHeaders: (headers, { getState, endpoint }) => { - const state = getState() as RootState; - - headers.set('Authorization', `Bearer ${localStorage.getItem('id_token')}`); - headers.set('user_id', state.entitiesReducer.userFarmReducer.user_id || ''); - headers.set('farm_id', state.entitiesReducer.userFarmReducer.farm_id || ''); - - // Only set the content-type to json if appropriate. - if (!NON_JSON_ENDPOINT_KEYS.has(endpoint) && !headers.has('Content-Type')) { - headers.set('content-type', 'application/json'); - } - - return headers; - }, - responseHandler: 'content-type', - }), + baseQuery: BASE_QUERY, tagTypes: API_TAGS, keepUnusedDataFor: 60 * 60 * 24 * 7, // 7 days refetchOnMountOrArgChange: 60, @@ -125,38 +84,6 @@ export const api = createApi({ query: () => `${customAnimalBreedsUrl}`, providesTags: ['CustomAnimalBreeds'], }), - getDefaultAnimalBreeds: build.query({ - query: () => `${defaultAnimalBreedsUrl}`, - providesTags: ['DefaultAnimalBreeds'], - }), - getAnimalSexes: build.query({ - query: () => `${animalSexesUrl}`, - providesTags: ['AnimalSexes'], - }), - getAnimalIdentifierTypes: build.query({ - query: () => `${animalIdentifierTypesUrl}`, - providesTags: ['AnimalIdentifierTypes'], - }), - getAnimalIdentifierColors: build.query({ - query: () => `${animalIdentifierColorsUrl}`, - providesTags: ['AnimalIdentifierColors'], - }), - getAnimalMovementPurposes: build.query({ - query: () => `${animalMovementPurposesUrl}`, - providesTags: ['AnimalMovementPurposes'], - }), - getAnimalOrigins: build.query({ - query: () => `${animalOriginsUrl}`, - providesTags: ['AnimalOrigins'], - }), - getAnimalUses: build.query({ - query: () => `${animalUsesUrl}`, - providesTags: ['AnimalUses'], - }), - getAnimalRemovalReasons: build.query({ - query: () => `${animalRemovalReasonsUrl}`, - providesTags: ['AnimalRemovalReasons'], - }), removeAnimals: build.mutation[]>({ query: (patch) => ({ url: `${animalsUrl}/remove`, @@ -323,18 +250,6 @@ export const api = createApi({ 'CustomAnimalBreeds', ], }), - getSoilAmendmentMethods: build.query({ - query: () => `${soilAmendmentMethodsUrl}`, - providesTags: ['SoilAmendmentMethods'], - }), - getSoilAmendmentPurposes: build.query({ - query: () => `${soilAmendmentPurposesUrl}`, - providesTags: ['SoilAmendmentPurposes'], - }), - getSoilAmendmentFertiliserTypes: build.query({ - query: () => `${soilAmendmentFertiliserTypesUrl}`, - providesTags: ['SoilAmendmentFertiliserTypes'], - }), addSoilAmendmentProduct: build.mutation>({ query: (body) => ({ url: `${productUrl}`, @@ -434,15 +349,7 @@ export const { useGetAnimalBatchesQuery, useGetCustomAnimalBreedsQuery, useGetCustomAnimalTypesQuery, - useGetDefaultAnimalBreedsQuery, useGetDefaultAnimalTypesQuery, - useGetAnimalSexesQuery, - useGetAnimalIdentifierTypesQuery, - useGetAnimalIdentifierColorsQuery, - useGetAnimalMovementPurposesQuery, - useGetAnimalOriginsQuery, - useGetAnimalUsesQuery, - useGetAnimalRemovalReasonsQuery, useRemoveAnimalsMutation, useRemoveAnimalBatchesMutation, useDeleteAnimalsMutation, @@ -451,9 +358,6 @@ export const { useAddAnimalBatchesMutation, useUpdateAnimalsMutation, useUpdateAnimalBatchesMutation, - useGetSoilAmendmentMethodsQuery, - useGetSoilAmendmentPurposesQuery, - useGetSoilAmendmentFertiliserTypesQuery, useAddSoilAmendmentProductMutation, useUpdateSoilAmendmentProductMutation, useDeleteSoilAmendmentProductMutation, diff --git a/packages/webapp/src/store/api/apiTags.ts b/packages/webapp/src/store/api/apiTags.ts index 89952cdbc2..d5752de782 100644 --- a/packages/webapp/src/store/api/apiTags.ts +++ b/packages/webapp/src/store/api/apiTags.ts @@ -70,6 +70,7 @@ export const FarmLibraryTags = [ 'MarketDirectoryPartners', ] as const; -export const API_TAGS = [...LibraryTags, ...FarmTags, ...FarmLibraryTags] as const; +export const LIBRARY_API_TAGS = [...LibraryTags] as const; +export const API_TAGS = [...FarmTags, ...FarmLibraryTags] as const; export type ApiTag = (typeof API_TAGS)[number]; diff --git a/packages/webapp/src/store/api/constants.ts b/packages/webapp/src/store/api/constants.ts new file mode 100644 index 0000000000..ee4f13798f --- /dev/null +++ b/packages/webapp/src/store/api/constants.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2026 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { fetchBaseQuery } from '@reduxjs/toolkit/query'; +import { url } from '../../apiConfig'; +import { RootState } from '../store'; + +export const NON_JSON_ENDPOINT_KEYS = new Set(['addSupportTicket']); + +export const BASE_QUERY = fetchBaseQuery({ + baseUrl: url, + prepareHeaders: (headers, { getState, endpoint }) => { + const state = getState() as RootState; + + headers.set('Authorization', `Bearer ${localStorage.getItem('id_token')}`); + headers.set('user_id', state.entitiesReducer.userFarmReducer.user_id || ''); + headers.set('farm_id', state.entitiesReducer.userFarmReducer.farm_id || ''); + + // Only set the content-type to json if appropriate. + if (!NON_JSON_ENDPOINT_KEYS.has(endpoint) && !headers.has('Content-Type')) { + headers.set('content-type', 'application/json'); + } + + return headers; + }, + responseHandler: 'content-type', +}); diff --git a/packages/webapp/src/store/api/libraryApiSlice.ts b/packages/webapp/src/store/api/libraryApiSlice.ts new file mode 100644 index 0000000000..5914040f3d --- /dev/null +++ b/packages/webapp/src/store/api/libraryApiSlice.ts @@ -0,0 +1,113 @@ +/* + * Copyright 2026 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { createApi } from '@reduxjs/toolkit/query/react'; +import { + defaultAnimalBreedsUrl, + animalSexesUrl, + animalIdentifierTypesUrl, + animalIdentifierColorsUrl, + animalOriginsUrl, + animalUsesUrl, + animalRemovalReasonsUrl, + soilAmendmentMethodsUrl, + soilAmendmentPurposesUrl, + soilAmendmentFertiliserTypesUrl, + animalMovementPurposesUrl, +} from '../../apiConfig'; +import type { + DefaultAnimalBreed, + AnimalSex, + AnimalRemovalReason, + SoilAmendmentMethod, + SoilAmendmentPurpose, + SoilAmendmentFertiliserType, + AnimalIdentifierType, + AnimalIdentifierColor, + AnimalOrigin, + AnimalUse, + AnimalMovementPurpose, +} from './types'; + +import { LIBRARY_API_TAGS } from './apiTags'; +import { BASE_QUERY } from './constants'; + +export const libraryApi = createApi({ + reducerPath: 'libraryApi', + baseQuery: BASE_QUERY, + tagTypes: LIBRARY_API_TAGS, + endpoints: (build) => ({ + // redux-toolkit.js.org/rtk-query/usage-with-typescript#typing-query-and-mutation-endpoints + // + getDefaultAnimalBreeds: build.query({ + query: () => `${defaultAnimalBreedsUrl}`, + providesTags: ['DefaultAnimalBreeds'], + }), + getAnimalSexes: build.query({ + query: () => `${animalSexesUrl}`, + providesTags: ['AnimalSexes'], + }), + getAnimalIdentifierTypes: build.query({ + query: () => `${animalIdentifierTypesUrl}`, + providesTags: ['AnimalIdentifierTypes'], + }), + getAnimalIdentifierColors: build.query({ + query: () => `${animalIdentifierColorsUrl}`, + providesTags: ['AnimalIdentifierColors'], + }), + getAnimalMovementPurposes: build.query({ + query: () => `${animalMovementPurposesUrl}`, + providesTags: ['AnimalMovementPurposes'], + }), + getAnimalOrigins: build.query({ + query: () => `${animalOriginsUrl}`, + providesTags: ['AnimalOrigins'], + }), + getAnimalUses: build.query({ + query: () => `${animalUsesUrl}`, + providesTags: ['AnimalUses'], + }), + getAnimalRemovalReasons: build.query({ + query: () => `${animalRemovalReasonsUrl}`, + providesTags: ['AnimalRemovalReasons'], + }), + getSoilAmendmentMethods: build.query({ + query: () => `${soilAmendmentMethodsUrl}`, + providesTags: ['SoilAmendmentMethods'], + }), + getSoilAmendmentPurposes: build.query({ + query: () => `${soilAmendmentPurposesUrl}`, + providesTags: ['SoilAmendmentPurposes'], + }), + getSoilAmendmentFertiliserTypes: build.query({ + query: () => `${soilAmendmentFertiliserTypesUrl}`, + providesTags: ['SoilAmendmentFertiliserTypes'], + }), + }), +}); + +export const { + useGetDefaultAnimalBreedsQuery, + useGetAnimalSexesQuery, + useGetAnimalIdentifierTypesQuery, + useGetAnimalIdentifierColorsQuery, + useGetAnimalMovementPurposesQuery, + useGetAnimalOriginsQuery, + useGetAnimalUsesQuery, + useGetAnimalRemovalReasonsQuery, + useGetSoilAmendmentMethodsQuery, + useGetSoilAmendmentPurposesQuery, + useGetSoilAmendmentFertiliserTypesQuery, +} = libraryApi; diff --git a/packages/webapp/src/store/api/marketProductCategoryApi.ts b/packages/webapp/src/store/api/marketProductCategoryApi.ts index c2303efbe2..cf59c86b08 100644 --- a/packages/webapp/src/store/api/marketProductCategoryApi.ts +++ b/packages/webapp/src/store/api/marketProductCategoryApi.ts @@ -13,11 +13,11 @@ * GNU General Public License for more details, see . */ -import { api } from './apiSlice'; +import { libraryApi } from './libraryApiSlice'; import { marketProductCategoryUrl } from '../../apiConfig'; import { MarketProductCategory } from './types'; -export const MarketProductCategories = api.injectEndpoints({ +export const MarketProductCategories = libraryApi.injectEndpoints({ endpoints: (build) => ({ getMarketProductCategories: build.query({ query: () => ({ diff --git a/packages/webapp/src/store/reducer.js b/packages/webapp/src/store/reducer.js index 4ecf2a4c24..d8a26f08af 100644 --- a/packages/webapp/src/store/reducer.js +++ b/packages/webapp/src/store/reducer.js @@ -18,6 +18,7 @@ import baseReducer from '../containers/reducer'; import { combineForms } from 'react-redux-form'; import { PURGE } from 'redux-persist'; import { api } from './api/apiSlice'; +import { libraryApi } from './api/libraryApiSlice'; import insightReducer from '../containers/Insights/reducer'; import financeReducer from '../containers/Finances/reducer'; import certifierSurveyReducer from '../containers/OrganicCertifierSurvey/slice'; @@ -239,6 +240,7 @@ const tempStateReducer = combineReducers({ // combine all reducers here and pass it to application const appReducer = combineReducers({ [api.reducerPath]: api.reducer, + [libraryApi.reducerPath]: libraryApi.reducer, profileForms: combineForms( { addInfo: addUserInfo, diff --git a/packages/webapp/src/store/store.ts b/packages/webapp/src/store/store.ts index 4af01b9c9f..89ce673e97 100644 --- a/packages/webapp/src/store/store.ts +++ b/packages/webapp/src/store/store.ts @@ -2,6 +2,7 @@ import { persistReducer, persistStore } from 'redux-persist'; import { AnyAction, Middleware, configureStore } from '@reduxjs/toolkit'; import { sagaMiddleware } from './sagaMiddleware'; import { api } from './api/apiSlice'; +import { libraryApi } from './api/libraryApiSlice'; import rootReducer from './reducer'; import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2'; import storage from 'redux-persist/lib/storage'; @@ -26,6 +27,7 @@ export const store = configureStore({ serializableCheck: false, }) .concat(api.middleware) + .concat(libraryApi.middleware) .concat(sagaMiddleware), ], devTools: import.meta.env.VITE_ENV !== 'production',