-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
280 additions
and
203 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"namespace": "common", | ||
"strings": { | ||
"fallbackMessage":"Please correct all the errors before submission!" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { useMemo } from 'react'; | ||
import { AlertLineIcon } from '@ifrc-go/icons'; | ||
import { useTranslation } from '@ifrc-go/ui/hooks'; | ||
import { | ||
_cs, | ||
isFalsyString, | ||
isNotDefined, | ||
} from '@togglecorp/fujs'; | ||
import { | ||
analyzeErrors, | ||
Error, | ||
getErrorObject, | ||
nonFieldError, | ||
} from '@togglecorp/toggle-form'; | ||
|
||
import i18n from './i18n.json'; | ||
import styles from './styles.module.css'; | ||
|
||
export interface Props<T> { | ||
className?: string; | ||
error?: Error<T>; | ||
withFallbackError?: boolean; | ||
} | ||
|
||
function NonFieldError<T>(props: Props<T>) { | ||
const { | ||
className, | ||
error, | ||
withFallbackError, | ||
} = props; | ||
|
||
const strings = useTranslation(i18n); | ||
const errorObject = useMemo(() => getErrorObject(error), [error]); | ||
|
||
if (isNotDefined(errorObject)) { | ||
return null; | ||
} | ||
|
||
const hasError = analyzeErrors(errorObject); | ||
if (!hasError) { | ||
return null; | ||
} | ||
|
||
const stringError = errorObject?.[nonFieldError] || ( | ||
withFallbackError ? strings.fallbackMessage : undefined); | ||
|
||
if (isFalsyString(stringError)) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div className={_cs( | ||
styles.nonFieldError, | ||
className, | ||
)} | ||
> | ||
<AlertLineIcon className={styles.icon} /> | ||
<div> | ||
{stringError} | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default NonFieldError; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
.non-field-error { | ||
display: inline-flex; | ||
gap: var(--go-ui-spacing-sm); | ||
align-items: baseline; | ||
animation: flash var(--go-ui-duration-animation-fast) ease-in-out; | ||
animation-delay: var(--go-ui-duration-animation-slow); | ||
color: var(--go-ui-color-red); | ||
font-size: var(--go-ui-font-size-lg); | ||
font-weight: var(--go-ui-font-weight-medium); | ||
|
||
.icon { | ||
flex-shrink: 0; | ||
/* font-size: var(--go-ui-height-icon-multiplier); */ | ||
} | ||
} | ||
|
||
@keyframes flash { | ||
0% { opacity: 1; } | ||
50% { opacity: 0.7; } | ||
100% { opacity: 1; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { | ||
isDefined, | ||
isNotDefined, | ||
listToMap, | ||
} from '@togglecorp/fujs'; | ||
import { nonFieldError } from '@togglecorp/toggle-form'; | ||
|
||
export interface Error { | ||
[ nonFieldError]?: string | undefined; | ||
[key: string]: string | Error | undefined; | ||
} | ||
|
||
export interface ObjectError { | ||
// clientId is sent by the server for bulk updates | ||
clientId: string | undefined; | ||
|
||
field: string; | ||
messages?: string; | ||
objectErrors?: ObjectError[]; | ||
arrayErrors?: (ArrayError | null)[]; | ||
} | ||
|
||
interface ArrayError { | ||
clientId: string; | ||
messages?: string; | ||
objectErrors?: ObjectError[]; | ||
} | ||
|
||
function transformObject(errors: ObjectError[] | undefined): Error | undefined { | ||
if (isNotDefined(errors)) { | ||
return undefined; | ||
} | ||
|
||
const topLevelError = errors.find((error) => error.field === 'nonFieldErrors'); | ||
const finalNonFieldErrors = topLevelError?.messages; | ||
|
||
const fieldErrors = errors.filter((error) => error.field !== 'nonFieldErrors'); | ||
const finalFieldErrors: Error = listToMap( | ||
fieldErrors, | ||
(error) => error.field, | ||
(error) => { | ||
if (isDefined(error.messages)) { | ||
return error.messages; | ||
} | ||
const objectErrors = isDefined(error.objectErrors) | ||
? transformObject(error.objectErrors) | ||
: undefined; | ||
|
||
const arrayErrors = isDefined(isDefined(error.arrayErrors)) | ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
? transformArray(error.arrayErrors) | ||
: undefined; | ||
|
||
if (!objectErrors && !arrayErrors) { | ||
return undefined; | ||
} | ||
return { ...objectErrors, ...arrayErrors }; | ||
}, | ||
); | ||
|
||
return { | ||
[nonFieldError]: finalNonFieldErrors, | ||
...finalFieldErrors, | ||
}; | ||
} | ||
|
||
function transformArray(errors: (ArrayError | null)[] | undefined): Error | undefined { | ||
if (isNotDefined(errors)) { | ||
return undefined; | ||
} | ||
const filteredErrors = errors.filter(isDefined); | ||
|
||
const topLevelError = filteredErrors.find((error) => error.clientId === 'nonMemberErrors'); | ||
const memberErrors = filteredErrors.filter((error) => error.clientId !== 'nonMemberErrors'); | ||
|
||
return { | ||
[nonFieldError]: topLevelError?.messages, | ||
...listToMap( | ||
memberErrors, | ||
(error) => error.clientId, | ||
(error) => transformObject(error.objectErrors), | ||
), | ||
}; | ||
} | ||
|
||
export const transformToFormError = transformObject; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.