Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(fe): fetch default error handling #923

Merged
merged 8 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"start": "vite --host --port 3000",
"build": "vue-tsc --noEmit && vite build",
"preview": "cross-env VITE_NODE_ENV=test start-server-and-test stub http://127.0.0.1:8080/ 'vite --host --port 3000'",
"preview:app": "cross-env VITE_NODE_ENV=test vite --host --port 3000",
"typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint . --fix --ignore-path .gitignore",
"stub": "wiremock --enable-stub-cors --port 8080 --https-port 8081 --preserve-host-header --root-dir ./stub --verbose --global-response-templating",
Expand Down
4 changes: 0 additions & 4 deletions frontend/src/components/grouping/AddressGroupComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ const emit = defineEmits<{
(e: "remove", value: number): void;
}>();

const generalErrorBus = useEventBus<string>("general-error-notification");

const noValidation = (value: string) => "";

//We set it as a separated ref due to props not being updatable
Expand Down Expand Up @@ -211,8 +209,6 @@ watch([autoCompleteResult], () => {
);

watch([error], () => {
// @ts-ignore
generalErrorBus.emit(error.response?.data.message);
postalCodeShowHint.value = true;
});

Expand Down
76 changes: 45 additions & 31 deletions frontend/src/composables/useFetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,25 @@ export const useFetch = (url: string | Ref, config: any = {}) => {
const data: any = ref(config.initialData || {});
const info = useFetchTo(url, data, config);

return { ...info, data };
return info;
};

const handleErrorDefault = (error: any) => {
if (
error.code === "ERR_BAD_RESPONSE" ||
error.code === "ERR_NETWORK"
) {
notificationBus.emit({
fieldId: "internal.server.error",
errorMsg: "",
});
}
else if (error.code === "ERR_BAD_REQUEST") {
notificationBus.emit({
fieldId: "bad.request.error",
errorMsg: "",
});
}
};

/**
Expand Down Expand Up @@ -61,29 +79,27 @@ export const useFetchTo = (
data.value = result.data;
} catch (ex) {
error.value = ex;
if (
error.value.code === "ERR_BAD_RESPONSE" ||
error.value.code === "ERR_NETWORK"
) {
notificationBus.emit({
fieldId: "internal.server.error",
errorMsg: "",
});
}
else if (error.value.code === "ERR_BAD_REQUEST") {
notificationBus.emit({
fieldId: "bad.request.error",
errorMsg: "",
});
if (config.skipDefaultErrorHandling) {
return;
}
apiDataHandler.handleErrorDefault();
} finally {
loading.value = false;
}
};

!config.skip && fetch();

return { response, error, data, loading, fetch };
const apiDataHandler = {
response,
error,
data,
loading,
fetch,
handleErrorDefault: () => handleErrorDefault(error.value),
};

return apiDataHandler;
};

/**
Expand Down Expand Up @@ -123,26 +139,24 @@ export const usePost = (url: string, body: any, config: any = {}) => {
responseBody.value = result.data;
} catch (ex: any) {
error.value = ex;
if (
error.value.code === "ERR_BAD_RESPONSE" ||
error.value.code === "ERR_NETWORK"
) {
notificationBus.emit({
fieldId: "internal.server.error",
errorMsg: "",
});
}
else if (error.value.code === "ERR_BAD_REQUEST") {
notificationBus.emit({
fieldId: "bad.request.error",
errorMsg: "",
});
if (config.skipDefaultErrorHandling) {
return;
}
apiDataHandler.handleErrorDefault();
} finally {
loading.value = false;
}
};
!config.skip && fetch();

return { response, error, responseBody, loading, fetch };
const apiDataHandler = {
response,
error,
responseBody,
loading,
fetch,
handleErrorDefault: () => handleErrorDefault(error.value),
};

return apiDataHandler;
};
37 changes: 25 additions & 12 deletions frontend/src/pages/FormBCSCPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ const {
response,
error,
fetch: fetchSubmit,
handleErrorDefault,
} = usePost("/api/clients/submissions", toRef(formData).value, {
skip: true,
});
Expand Down Expand Up @@ -364,29 +365,41 @@ watch([error], () => {
// reset the button to allow a new submission attempt
submitBtnDisabled.value = !validInd.value;

const validationErrors: ValidationMessageType[] =
error.value.response?.data ?? ([] as ValidationMessageType[]);
if (Array.isArray(error.value.response?.data)) {
const validationErrors: ValidationMessageType[] = error.value.response?.data;

validationErrors.forEach((errorItem: ValidationMessageType) =>
notificationBus.emit({
fieldId: "server.validation.error",
fieldName: convertFieldNameToSentence(errorItem.fieldId),
errorMsg: errorItem.errorMsg,
}),
);
} else {
handleErrorDefault();
}

validationErrors.forEach((errorItem: ValidationMessageType) =>
notificationBus.emit({
fieldId: "server.validation.error",
fieldName: convertFieldNameToSentence(errorItem.fieldId),
errorMsg: errorItem.errorMsg,
})
);
setScrollPoint("top-notification");
});

const { error:validationError } = useFetch(`/api/clients/individual/${ForestClientUserSession.user?.userId.split('\\').pop()}?lastName=${ForestClientUserSession.user?.lastName}`);
const { error: validationError, handleErrorDefault: handleValidationError } = useFetch(
`/api/clients/individual/${ForestClientUserSession.user?.userId
.split("\\")
.pop()}?lastName=${ForestClientUserSession.user?.lastName}`,
{ skipDefaultErrorHandling: true },
);
watch([validationError], () => {
if (validationError.value.response?.status === 409) {
updateValidState(-1, false); //-1 to define the error as global
notificationBus.emit({
fieldId: "server.validation.error",
fieldName: '',
errorMsg: validationError.value.response?.data ?? "",
})
}
});
} else if (validationError.value.response?.status !== 404) {
updateValidState(-1, false); //-1 to define the error as global
handleValidationError();
}
});

const districtsList = ref([]);
Expand Down
38 changes: 22 additions & 16 deletions frontend/src/pages/FormBCeIDPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,15 @@ const associatedLocations = computed(() =>
)
);

const { response, error, fetch: post } = usePost(
"/api/clients/submissions",
toRef(formData).value,
{
skip: true,
}
);
const {
response,
error,
fetch: post,
handleErrorDefault,
} = usePost("/api/clients/submissions", toRef(formData).value, {
skip: true,
skipDefaultErrorHandling: true,
});

watch([response], () => {
if (response.value.status === 201) {
Expand All @@ -125,16 +127,20 @@ watch([error], () => {
// reset the button to allow a new submission attempt
submitBtnDisabled.value = false;

const validationErrors: ValidationMessageType[] = error.value.response?.data ??
[] as ValidationMessageType[];
if (Array.isArray(error.value.response?.data)) {
const validationErrors: ValidationMessageType[] = error.value.response?.data;

validationErrors.forEach((errorItem: ValidationMessageType) =>
notificationBus.emit({
fieldId: "server.validation.error",
fieldName: convertFieldNameToSentence(errorItem.fieldId),
errorMsg: errorItem.errorMsg,
}),
);
} else {
handleErrorDefault();
}

validationErrors.forEach((errorItem: ValidationMessageType) =>
notificationBus.emit({
fieldId: "server.validation.error",
fieldName: convertFieldNameToSentence(errorItem.fieldId),
errorMsg: errorItem.errorMsg,
})
);
setScrollPoint("top-notification");
});

Expand Down
33 changes: 19 additions & 14 deletions frontend/src/pages/bceidform/BusinessInformationWizardStep.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ const ForestClientUserSession = instance.appContext.config.globalProperties.$ses
const progressIndicatorBus = useEventBus<ProgressNotification>(
"progress-indicator-bus"
);
const exitBus =
useEventBus<Record<string, boolean | null>>("exit-notification");
const generalErrorBus = useEventBus<string>("general-error-notification");
const exitBus = useEventBus<Record<string, boolean | null>>("exit-notification");

//Set the prop as a ref, and then emit when it changes
const formData = ref<FormDataDto>(props.data);
Expand Down Expand Up @@ -176,11 +174,13 @@ watch([autoCompleteResult], () => {
emit("update:data", formData.value);

//Also, we will load the backend data to fill all the other information as well
const { error, loading: detailsLoading } = useFetchTo(
`/api/clients/${autoCompleteResult.value.code}`,
detailsData,
{}
);
const {
error,
loading: detailsLoading,
handleErrorDefault,
} = useFetchTo(`/api/clients/${autoCompleteResult.value.code}`, detailsData, {
skipDefaultErrorHandling: true,
});

showDetailsLoading.value = true;
watch(error, () => {
Expand All @@ -207,8 +207,7 @@ watch([autoCompleteResult], () => {
emit("update:data", formData.value);
return;
}
// @ts-ignore
generalErrorBus.emit(error.value.response?.data.message);
handleErrorDefault();
});

watch(
Expand All @@ -227,10 +226,15 @@ watch([autoCompleteResult], () => {
* @param {string} lastName - The last name to check.
*/
const checkForIndividualValid = (lastName: string) => {
const { error: validationError, response: individualResponse } = useFetch(
const {
error: validationError,
response: individualResponse,
handleErrorDefault,
} = useFetch(
`/api/clients/individual/${ForestClientUserSession.user?.userId
.split("\\")
.pop()}?lastName=${lastName}`
.pop()}?lastName=${lastName}`,
{ skipDefaultErrorHandling: true },
);

// reset validation
Expand All @@ -240,13 +244,14 @@ const checkForIndividualValid = (lastName: string) => {
if (watchValue.response?.status === 409) {
validation.business = false;
toggleErrorMessages(null, true, null);
generalErrorBus.emit(watchValue.response?.data ?? "");
} else if (watchValue.response?.status === 404) {
validation.individual = true;
} else {
handleErrorDefault();
}
});
watch(individualResponse, (watchValue) => {
if(watchValue.status === 200){
if (watchValue.status === 200) {
validation.individual = true;
}
});
Expand Down
Loading
Loading