Skip to content

Commit

Permalink
refactor(web): [FE]Improvement: display error msg with translations o…
Browse files Browse the repository at this point in the history
…n FE
  • Loading branch information
soneda-yuya committed Jan 9, 2025
1 parent 25d2613 commit 313b0a5
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 64 deletions.
71 changes: 35 additions & 36 deletions web/src/beta/features/Notification/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { useT, useLang } from "@reearth/services/i18n";
import {
useError,
useNotification,
Notification
} from "@reearth/services/state";
import { useNotification, Notification } from "@reearth/services/state";
import { useErrors } from "@reearth/services/state/gqlErrorHandling";
import { useState, useEffect, useCallback, useMemo } from "react";

export type PolicyItems =
Expand All @@ -26,7 +23,7 @@ const policyItems: PolicyItems[] = [
export default () => {
const t = useT();
const currentLanguage = useLang();
const [error, setError] = useError();
const [errors, setErrors] = useErrors();
const [notification, setNotification] = useNotification();
const [visible, changeVisibility] = useState(false);

Expand Down Expand Up @@ -54,42 +51,44 @@ export default () => {
}, []);

useEffect(() => {
if (!error) return;
if (error.message?.includes("policy violation") && error.message) {
const limitedItem = policyItems.find((i) => error.message?.includes(i));
const policyItem =
limitedItem && policyLimitNotifications
? policyLimitNotifications[limitedItem]
: undefined;
const message = policyItem
? typeof policyItem === "string"
? policyItem
: policyItem[currentLanguage]
: t(
"You have reached a policy limit. Please contact an administrator of your Re:Earth system."
);
if (errors.length === 0) return;
errors.forEach((error) => {
if (error.message?.includes("policy violation") && error.message) {
const limitedItem = policyItems.find((i) => error.message?.includes(i));
const policyItem =
limitedItem && policyLimitNotifications
? policyLimitNotifications[limitedItem]
: undefined;
const message = policyItem
? typeof policyItem === "string"
? policyItem
: policyItem[currentLanguage]
: t(
"You have reached a policy limit. Please contact an administrator of your Re:Earth system."
);

setNotification({
type: "info",
heading: noticeHeading,
text: message,
duration: "persistent"
});
} else {
setNotification({
type: "error",
heading: errorHeading,
text: t("Something went wrong. Please try again later.")
});
}
setError(undefined);
setNotification({
type: "info",
heading: noticeHeading,
text: message,
duration: "persistent"
});
} else {
setNotification({
type: "error",
heading: errorHeading,
text: error.description || error.message || ""
});
}
});
setErrors([]);
}, [
error,
errors,
currentLanguage,
policyLimitNotifications,
errorHeading,
noticeHeading,
setError,
setErrors,
setNotification,
t
]);
Expand Down
22 changes: 12 additions & 10 deletions web/src/sentry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ export const initialize = () => {
}
};

export const reportError = (error: ReportError) => {
if (error instanceof Error) {
Sentry.captureException(error);
} else {
Sentry.captureException(
new Error(
`${error.type || "Unknown"}: ${error.message || "No message provided"}`
)
);
}
export const reportError = (errors: ReportError[]) => {
errors.forEach((error) => {
if (error instanceof Error) {
Sentry.captureException(error);
} else {
Sentry.captureException(
new Error(
`${error.type || "Unknown"}: ${error.message || "No message provided"}`
)
);
}
});
};
2 changes: 2 additions & 0 deletions web/src/services/gql/provider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useCallback, type ReactNode } from "react";
import fragmentMatcher from "../__gen__/fragmentMatcher.json";

import { authLink, sentryLink, errorLink, uploadLink, taskLink } from "./links";
import langLink from "./links/langLink";
import { paginationMerge } from "./pagination";

const Provider: React.FC<{ children?: ReactNode }> = ({ children }) => {
Expand Down Expand Up @@ -90,6 +91,7 @@ const Provider: React.FC<{ children?: ReactNode }> = ({ children }) => {
errorLink(),
sentryLink(endpoint),
authLink(),
langLink(),
// https://github.com/apollographql/apollo-client/issues/6011#issuecomment-619468320
uploadLink(endpoint) as unknown as ApolloLink
]),
Expand Down
30 changes: 19 additions & 11 deletions web/src/services/gql/provider/links/errorLink.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
import { onError } from "@apollo/client/link/error";
import { reportError } from "@reearth/sentry";
import { useSetError } from "@reearth/services/state";
import { GQLError } from "@reearth/services/state/gqlErrorHandling";

export default () => {
const { setError } = useSetError();
const { setErrors } = useSetError();

return onError(({ graphQLErrors, networkError }) => {
if (!networkError && !graphQLErrors) return;
let error: { type?: string; message?: string } | undefined;

let errors: GQLError[] = [];
console.log(graphQLErrors);
if (networkError?.message) {
error = { message: networkError?.message };
errors = [
{ message: networkError?.message, description: networkError.message }
];
} else {
error = {
type: graphQLErrors?.[0].path?.[0].toString(),
message: graphQLErrors?.[0].message
};
errors =
graphQLErrors?.map((gqlError) => {
return {
type: gqlError.path?.[0].toString(),
message: gqlError.message,
code: gqlError.extensions?.code as string,
description: gqlError.extensions?.description as string
};
}) ?? [];
}
if (error) {
setError(error);
reportError(error);
if (errors.length > 0) {
setErrors(errors);
reportError(errors);
}
});
};
14 changes: 14 additions & 0 deletions web/src/services/gql/provider/links/langLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { setContext } from "@apollo/client/link/context";
import i18n from "@reearth/services/i18n/i18n";

export default () => {
return setContext(async (_, { headers }) => {
const local = i18n.language.split("-")[0];
return {
headers: {
...headers,
lang: local
}
};
});
};
16 changes: 10 additions & 6 deletions web/src/services/state/gqlErrorHandling.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { atom, useAtom, useSetAtom } from "jotai";

// useError is needed for Apollo provider error only. Handle other errors with useNotification directly.
type GQLError = { type?: string; message?: string };
const error = atom<GQLError | undefined>(undefined);

export const useError = () => useAtom(error);
export type GQLError = {
type?: string;
message?: string;
code?: string;
description?: string;
};
const errors = atom<GQLError[]>([]);
export const useErrors = () => useAtom(errors);

export default () => {
const setError = useSetAtom(error);
return { setError };
const setErrors = useSetAtom(errors);
return { setErrors };
};
2 changes: 1 addition & 1 deletion web/src/services/state/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { TeamMember } from "../gql";

export * from "./devPlugins";

export { default as useSetError, useError } from "./gqlErrorHandling";
export { default as useSetError } from "./gqlErrorHandling";

export type WidgetAreaState = {
zone: "inner" | "outer";
Expand Down

0 comments on commit 313b0a5

Please sign in to comment.