diff options
| author | Kevin J Hoerr <kjhoerr@protonmail.com> | 2023-05-06 10:50:41 -0400 |
|---|---|---|
| committer | Kevin J Hoerr <kjhoerr@protonmail.com> | 2025-08-18 12:16:07 -0400 |
| commit | 76702103c1a5f6c54a8aa58875ef21ce3316f4df (patch) | |
| tree | 916cc98dc83f54c84ecf895c84c263cbaa43d664 | |
| parent | 20c42e6bf24ac332306b92fa27938410ab6a7431 (diff) | |
| download | pantry-76702103c1a5f6c54a8aa58875ef21ce3316f4df.tar.gz pantry-76702103c1a5f6c54a8aa58875ef21ce3316f4df.tar.bz2 pantry-76702103c1a5f6c54a8aa58875ef21ce3316f4df.zip | |
Add labels reducer and hooks
| -rw-r--r-- | src/main/webui/src/hooks/controllers/index.ts | 1 | ||||
| -rw-r--r-- | src/main/webui/src/hooks/controllers/labels.ts | 80 | ||||
| -rw-r--r-- | src/main/webui/src/hooks/index.ts | 1 | ||||
| -rw-r--r-- | src/main/webui/src/hooks/labels.ts | 21 | ||||
| -rw-r--r-- | src/main/webui/src/model/index.ts | 2 | ||||
| -rw-r--r-- | src/main/webui/src/store/index.ts | 2 | ||||
| -rw-r--r-- | src/main/webui/src/store/reducers/labels.ts | 23 |
7 files changed, 129 insertions, 1 deletions
diff --git a/src/main/webui/src/hooks/controllers/index.ts b/src/main/webui/src/hooks/controllers/index.ts index 780fb80..d1903a6 100644 --- a/src/main/webui/src/hooks/controllers/index.ts +++ b/src/main/webui/src/hooks/controllers/index.ts @@ -1 +1,2 @@ export * from "./items"; +export * from "./labels"; diff --git a/src/main/webui/src/hooks/controllers/labels.ts b/src/main/webui/src/hooks/controllers/labels.ts new file mode 100644 index 0000000..e7ac5e0 --- /dev/null +++ b/src/main/webui/src/hooks/controllers/labels.ts @@ -0,0 +1,80 @@ +import { request } from "graphql-request"; + +import { + PantryItemLabel, + AllLabelsDocument, + SyncLabelsDocument, + SyncLabelsMutationVariables, +} from "../../gql/conf/graphql"; +import { ApiError, errorHandler, GraphQLModelError } from "../../model"; +import nullcheck from "../../util/nullcheck"; +import { useToastAPIError } from "../toast"; +import { GRAPHQL_ENDPOINT } from "../../config"; +import { useSetLabels } from ".."; + +/** + * Hook to issue query for `allLabels` to retrieve list of {@link PantryItemLabel}s. + * + * By default will issue the SET_PANTRY_ITEM_LABELS action with the list of labels. + */ +export const useAllLabelsController = ( + onSuccess?: (items: PantryItemLabel[]) => void, + onError?: (error: ApiError) => void, +) => { + const toastApiError = useToastAPIError(); + const setLabels = useSetLabels(); + + /** Issue query for `allLabels` to retrieve list of {@link PantryItemLabel}s. */ + return () => + request(GRAPHQL_ENDPOINT, AllLabelsDocument) + .then((data) => { + if (nullcheck(data.allLabels)) { + return data.allLabels + .filter(nullcheck) + .map(({ id, title, color }) => { + // ensure object is uncoerced to model type + return { + id: id ?? undefined, + title: title ?? undefined, + color: color ?? undefined, + }; + }); + } else { + return Promise.reject(new GraphQLModelError()); + } + }) + .then(onSuccess ?? setLabels) + .catch(errorHandler(onError ?? toastApiError)); +}; + +/** + * Hook to issue a mutation for `syncLabels` to sync labels to the pantry. + * + * By default will not dispatch any actions. + */ +export const useSyncLabelsController = ( + onSuccess?: (item: PantryItemLabel[]) => void, + onError?: (error: ApiError) => void, +) => { + const toastApiError = useToastAPIError(); + const setLabels = useSetLabels(); + + /** + * Issue mutation for `syncLabels` to sync labels to the pantry. + */ + return (variables: SyncLabelsMutationVariables) => + request(GRAPHQL_ENDPOINT, SyncLabelsDocument, variables) + .then((data) => { + if (nullcheck(data) && nullcheck(data?.syncLabels)) { + return data.syncLabels.map(label => ({ + id: label?.id ?? undefined, + color: label?.color ?? undefined, + title: label?.title ?? undefined, + })); + } else { + return Promise.reject(new GraphQLModelError()); + } + }) + .then(onSuccess ?? setLabels) + .catch(errorHandler(onError ?? toastApiError)); +}; diff --git a/src/main/webui/src/hooks/index.ts b/src/main/webui/src/hooks/index.ts index 15d42ef..4580ec8 100644 --- a/src/main/webui/src/hooks/index.ts +++ b/src/main/webui/src/hooks/index.ts @@ -1,5 +1,6 @@ export * from "./health"; export * from "./items"; +export * from "./labels"; export * from "./toast"; export * from "./controllers"; export { useDispatch, useSelector } from "../store"; diff --git a/src/main/webui/src/hooks/labels.ts b/src/main/webui/src/hooks/labels.ts new file mode 100644 index 0000000..5d4fee3 --- /dev/null +++ b/src/main/webui/src/hooks/labels.ts @@ -0,0 +1,21 @@ +import { PantryItemLabel } from "../model"; +import { useDispatch } from "../store"; +import { addLabel, setLabels } from "../store/reducers/labels"; + +/** + * Hook to dispatch a {@link SetLabelsAction}. + */ +export const useSetLabels = () => { + const dispatch = useDispatch(); + + return (Labels: PantryItemLabel[]) => dispatch(setLabels(Labels)); +}; + +/** + * Hook to dispatch an {@link AddLabelAction}. + */ +export const useAddLabel = () => { + const dispatch = useDispatch(); + + return (Label: PantryItemLabel) => dispatch(addLabel(Label)); +}; diff --git a/src/main/webui/src/model/index.ts b/src/main/webui/src/model/index.ts index 61f1cf0..c75dceb 100644 --- a/src/main/webui/src/model/index.ts +++ b/src/main/webui/src/model/index.ts @@ -1,4 +1,4 @@ export * from "./errors"; export * from "./health"; export * from "./toastMessage"; -export type { PantryItem } from "../gql/conf/graphql"; +export type { PantryItem, PantryItemLabel } from "../gql/conf/graphql"; diff --git a/src/main/webui/src/store/index.ts b/src/main/webui/src/store/index.ts index b0071c4..f4eb1f3 100644 --- a/src/main/webui/src/store/index.ts +++ b/src/main/webui/src/store/index.ts @@ -7,6 +7,7 @@ import { import healthReducer from "./reducers/health"; import itemsReducer from "./reducers/items"; +import labelsReducer from "./reducers/labels"; import toastReducer from "./reducers/toast"; // creating store @@ -14,6 +15,7 @@ export const store = configureStore({ reducer: { health: healthReducer, items: itemsReducer, + labels: labelsReducer, toast: toastReducer, }, }); diff --git a/src/main/webui/src/store/reducers/labels.ts b/src/main/webui/src/store/reducers/labels.ts new file mode 100644 index 0000000..8974af5 --- /dev/null +++ b/src/main/webui/src/store/reducers/labels.ts @@ -0,0 +1,23 @@ +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; + +import { PantryItemLabel } from "../../model"; + +export type LabelState = Array<PantryItemLabel>; + +const initialState: LabelState = []; + +const labelsSlice = createSlice({ + name: "labels", + initialState, + reducers: { + setLabels: (_state, action: PayloadAction<Array<PantryItemLabel>>) => + action.payload, + addLabel: (state, action: PayloadAction<PantryItemLabel>) => { + state.push(action.payload); + }, + }, +}); + +export const { addLabel, setLabels } = labelsSlice.actions; + +export default labelsSlice.reducer; |
