diff --git a/audiences-react/docs/CHANGELOG.md b/audiences-react/docs/CHANGELOG.md
index 72c5397b..a5a3fd92 100644
--- a/audiences-react/docs/CHANGELOG.md
+++ b/audiences-react/docs/CHANGELOG.md
@@ -1,5 +1,19 @@
# Unreleased
+# Version 1.2.1 (2024-08-06)
+
+- Add error handling to audiences form [#372](https://github.com/powerhome/audiences/pull/372)
+
+# Version 1.2.0 (2024-07-18)
+
+- Fix involuntary form reset by [#355](https://github.com/powerhome/audiences/pull/355)
+- Update dependency @types/node to v20.14.5 [#343](https://github.com/powerhome/audiences/pull/343)
+- Update dependency vite to v5.3.1 by [#340](https://github.com/powerhome/audiences/pull/340)
+- Update typescript-eslint monorepo to v7.13.1 [#339](https://github.com/powerhome/audiences/pull/339)
+- Update dependency prettier to v3.3.2 by [#334](https://github.com/powerhome/audiences/pull/334)
+- Update dependency @types/lodash to v4.17.5 [#335](https://github.com/powerhome/audiences/pull/335)
+- Update dependency @vitejs/plugin-react to v4.3 [#337](https://github.com/powerhome/audiences/pull/337)
+
# Version 1.1.0 (2024-06-10)
- Update UX [#329](https://github.com/powerhome/audiences/pull/329)
diff --git a/audiences-react/package.json b/audiences-react/package.json
index 92ec45b9..20b24e6e 100644
--- a/audiences-react/package.json
+++ b/audiences-react/package.json
@@ -1,6 +1,6 @@
{
"name": "audiences",
- "version": "1.2.0",
+ "version": "1.2.1",
"description": "Audiences SCIM client",
"files": [
"dist/*.*",
diff --git a/audiences-react/src/AudienceForm/index.tsx b/audiences-react/src/AudienceForm/index.tsx
index 3663c6b8..bd1740fe 100644
--- a/audiences-react/src/AudienceForm/index.tsx
+++ b/audiences-react/src/AudienceForm/index.tsx
@@ -1,5 +1,5 @@
import { useState } from "react"
-import { Button, Flex } from "playbook-ui"
+import { FixedConfirmationToast, Button, Flex } from "playbook-ui"
import { GroupCriterion, ScimObject } from "../types"
import { toSentence } from "./toSentence"
@@ -29,6 +29,7 @@ export const AudienceForm = ({
saving,
fetchUsers,
save,
+ error,
value: context,
isDirty,
change,
@@ -75,6 +76,9 @@ export const AudienceForm = ({
isDirty={isDirty()}
onToggle={(all: boolean) => change("match_all", all)}
>
+ {error && (
+
+ )}
{allowIndividuals && !context.match_all && (
(data, {
@@ -74,7 +75,11 @@ export function useAudiences(uri: string): UseAudienceContext {
async function save() {
const updatedContext = await put(criteriaForm.value)
- criteriaForm.reset(updatedContext)
+ if (response.ok) {
+ criteriaForm.reset(updatedContext)
+ } else {
+ criteriaForm.setError("Unhandled server error")
+ }
}
return {
diff --git a/audiences-react/src/useFormReducer.ts b/audiences-react/src/useFormReducer.ts
index 9099eb7b..c1f9500c 100644
--- a/audiences-react/src/useFormReducer.ts
+++ b/audiences-react/src/useFormReducer.ts
@@ -5,17 +5,30 @@ import { useState, useReducer, useCallback } from "react"
export interface RegistryAction {
type: string
}
-type ResetAction = RegistryAction & { value: T }
+type ErrorAction = RegistryAction & { message: string }
+type ResetAction = RegistryAction & { state: FormState }
type ChangeAction = RegistryAction & { name: string; value: any } // eslint-disable-line @typescript-eslint/no-explicit-any
-type ReducerAction = (value: T, action: RegistryAction) => T
-type ReducerRegistry = Record>
+type ReducerAction = (
+ value: FormState,
+ action: RegistryAction,
+) => FormState
+type NestedReducerAction = (value: T, action: RegistryAction) => T
+type NestedReducerRegistry = Record>
+export type FormState = {
+ error?: string | undefined
+ value: T
+}
const DefaultFormReducers = {
- change(value: T, action: ChangeAction): T {
- return set(action.name, action.value, value as object) as T
+ change(state: FormState, action: ChangeAction): FormState {
+ const value = set(action.name, action.value, state.value as object) as T
+ return { ...state, value }
},
- reset(_: T, action: ResetAction) {
- return action.value
+ reset(_: FormState, action: ResetAction): FormState {
+ return action.state
+ },
+ error(state: FormState, action: ErrorAction): FormState {
+ return { ...state, error: action.message }
},
}
@@ -24,63 +37,70 @@ const form = {
change(name: string, value: any): ChangeAction {
return { type: "change", name, value }
},
- reset(value: T): ResetAction {
- return { type: "reset", value }
+ reset(state: FormState): ResetAction {
+ return { type: "reset", state }
},
- reducer(nestedReducers?: ReducerRegistry): ReducerAction {
- return (value: T, action: RegistryAction) => {
- const reducer =
- get(DefaultFormReducers, action.type) ||
- get(nestedReducers, action.type)
-
- if (reducer) {
- return reducer(value, action)
+ error(message: string): ErrorAction {
+ return { type: "error", message }
+ },
+ reducer(nestedReducers?: NestedReducerRegistry): ReducerAction {
+ return (state: FormState, action: RegistryAction) => {
+ if (action.type in DefaultFormReducers) {
+ return get(DefaultFormReducers, action.type)(state, action)
+ } else if (nestedReducers && action.type in nestedReducers) {
+ const value = get(nestedReducers, action.type)(state.value, action)
+ return { ...state, value }
}
}
},
}
-export type UseFormReducer = {
+export type UseFormReducer = FormState & {
isDirty: (attribute?: string) => boolean
- value: T
dispatch: ReturnType[1]
reset: (newInitial?: T) => void
+ setError: (message: string) => void
change: (name: string, value: any) => void // eslint-disable-line @typescript-eslint/no-explicit-any
}
export default function useFormReducer(
initial: T,
- nestedReducer?: ReducerRegistry,
+ nestedReducer?: NestedReducerRegistry,
): UseFormReducer {
const [initialValue, setInitialValue] = useState(initial)
- const [value, dispatch] = useReducer(
- form.reducer(nestedReducer),
- initialValue,
- )
+ const [state, dispatch] = useReducer(form.reducer(nestedReducer), {
+ value: initialValue,
+ })
const isDirty = useCallback(
(attribute?: string) => {
if (attribute) {
- return !isEqual(get(initialValue, attribute), get(value, attribute))
+ return !isEqual(
+ get(initialValue, attribute),
+ get(state.value, attribute),
+ )
} else {
- return !isEqual(initialValue, value)
+ return !isEqual(initialValue, state.value)
}
},
- [initialValue, value],
+ [initialValue, state.value],
)
const reset = (newInitial?: T) => {
if (newInitial) {
setInitialValue(newInitial)
- dispatch(form.reset(newInitial))
+ dispatch(form.reset({ value: newInitial }))
} else {
- dispatch(form.reset(initialValue))
+ dispatch(form.reset({ value: initialValue }))
}
}
return {
+ ...state,
isDirty,
- value,
dispatch,
reset,
+ setError(message: string) {
+ dispatch(form.error(message))
+ },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
change(name: string, value: any) {
dispatch(form.change(name, value))
diff --git a/audiences/Gemfile.lock b/audiences/Gemfile.lock
index 963005d1..8c22269c 100644
--- a/audiences/Gemfile.lock
+++ b/audiences/Gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- audiences (1.2.0)
+ audiences (1.2.1)
rails (>= 6.0)
GEM
diff --git a/audiences/config/routes.rb b/audiences/config/routes.rb
index 42b7a5e9..8c19daa6 100644
--- a/audiences/config/routes.rb
+++ b/audiences/config/routes.rb
@@ -10,10 +10,10 @@
Rails.application.routes.draw do
direct :audience_context do |owner, relation = nil|
context = Audiences::Context.for(owner, relation: relation)
- Audiences::Engine.routes.url_helpers.route_for(:signed_context, key: context.signed_key, **url_options)
+ audiences.route_for(:signed_context, key: context.signed_key, **url_options)
end
direct :audience_scim_proxy do |options|
- Audiences::Engine.routes.url_helpers.route_for(:scim_proxy, **url_options, **options)
+ audiences.route_for(:scim_proxy, **url_options, **options)
end
end
diff --git a/audiences/docs/CHANGELOG.md b/audiences/docs/CHANGELOG.md
index 549f2481..13561c60 100644
--- a/audiences/docs/CHANGELOG.md
+++ b/audiences/docs/CHANGELOG.md
@@ -1,5 +1,9 @@
# Unreleased
+# Version 1.2.1 (2024-08-06)
+
+- Fix audiences URL helpers [#372](https://github.com/powerhome/audiences/pull/372)
+
# Version 1.2.0 (2024-07-24)
- Add `has_audience` and the ability to attach multiple audiences to the same owner [#363](https://github.com/powerhome/audiences/pull/363)
diff --git a/audiences/gemfiles/rails_6_1.gemfile.lock b/audiences/gemfiles/rails_6_1.gemfile.lock
index 6c39b9ac..88d7b4c4 100644
--- a/audiences/gemfiles/rails_6_1.gemfile.lock
+++ b/audiences/gemfiles/rails_6_1.gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: ..
specs:
- audiences (1.2.0)
+ audiences (1.2.1)
rails (>= 6.0)
GEM
diff --git a/audiences/gemfiles/rails_7_0.gemfile.lock b/audiences/gemfiles/rails_7_0.gemfile.lock
index a5921c1a..0aa4a8f0 100644
--- a/audiences/gemfiles/rails_7_0.gemfile.lock
+++ b/audiences/gemfiles/rails_7_0.gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: ..
specs:
- audiences (1.2.0)
+ audiences (1.2.1)
rails (>= 6.0)
GEM
diff --git a/audiences/gemfiles/rails_7_1.gemfile.lock b/audiences/gemfiles/rails_7_1.gemfile.lock
index 5fc1e116..c9a49706 100644
--- a/audiences/gemfiles/rails_7_1.gemfile.lock
+++ b/audiences/gemfiles/rails_7_1.gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: ..
specs:
- audiences (1.2.0)
+ audiences (1.2.1)
rails (>= 6.0)
GEM
diff --git a/audiences/lib/audiences/version.rb b/audiences/lib/audiences/version.rb
index 969a6403..c31dbd16 100644
--- a/audiences/lib/audiences/version.rb
+++ b/audiences/lib/audiences/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Audiences
- VERSION = "1.2.0"
+ VERSION = "1.2.1"
end