mirror of
				https://gitlab.nic.cz/turris/reforis/foris-js.git
				synced 2025-11-03 23:00:31 +01:00 
			
		
		
		
	Loading and errors HOCs
This commit is contained in:
		
							
								
								
									
										16
									
								
								src/utils/ErrorMessage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/utils/ErrorMessage.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/)
 | 
			
		||||
 *
 | 
			
		||||
 * This is free software, licensed under the GNU General Public License v3.
 | 
			
		||||
 * See /LICENSE for more information.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import React from "react";
 | 
			
		||||
 | 
			
		||||
export function ErrorMessage() {
 | 
			
		||||
    return (
 | 
			
		||||
        <p className="text-center text-danger">
 | 
			
		||||
            {_("An error occurred while fetching data.")}
 | 
			
		||||
        </p>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
 | 
			
		||||
 | 
			
		||||
exports[`conditional HOCs withError should render error message 1`] = `
 | 
			
		||||
<div>
 | 
			
		||||
  <p
 | 
			
		||||
    class="text-center text-danger"
 | 
			
		||||
  >
 | 
			
		||||
    An error occurred while fetching data.
 | 
			
		||||
  </p>
 | 
			
		||||
</div>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
exports[`conditional HOCs withErrorMessage should render error message 1`] = `
 | 
			
		||||
<div>
 | 
			
		||||
  <p
 | 
			
		||||
    class="text-center text-danger"
 | 
			
		||||
  >
 | 
			
		||||
    An error occurred while fetching data.
 | 
			
		||||
  </p>
 | 
			
		||||
</div>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
exports[`conditional HOCs withSpinner should render spinner 1`] = `
 | 
			
		||||
<div>
 | 
			
		||||
  <div
 | 
			
		||||
    class="spinner-wrapper my-3 text-center"
 | 
			
		||||
  >
 | 
			
		||||
    <div
 | 
			
		||||
      class="spinner-border "
 | 
			
		||||
      role="status"
 | 
			
		||||
    >
 | 
			
		||||
      <span
 | 
			
		||||
        class="sr-only"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div
 | 
			
		||||
      class="spinner-text"
 | 
			
		||||
    />
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
exports[`conditional HOCs withSpinnerOnSending should render spinner 1`] = `
 | 
			
		||||
<div>
 | 
			
		||||
  <div
 | 
			
		||||
    class="spinner-wrapper my-3 text-center"
 | 
			
		||||
  >
 | 
			
		||||
    <div
 | 
			
		||||
      class="spinner-border "
 | 
			
		||||
      role="status"
 | 
			
		||||
    >
 | 
			
		||||
      <span
 | 
			
		||||
        class="sr-only"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div
 | 
			
		||||
      class="spinner-text"
 | 
			
		||||
    />
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
`;
 | 
			
		||||
							
								
								
									
										110
									
								
								src/utils/__tests__/conditionalHOCs.test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/utils/__tests__/conditionalHOCs.test.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/)
 | 
			
		||||
 *
 | 
			
		||||
 * This is free software, licensed under the GNU General Public License v3.
 | 
			
		||||
 * See /LICENSE for more information.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import React from "react";
 | 
			
		||||
import { render } from "customTestRender";
 | 
			
		||||
import {
 | 
			
		||||
    withEither, withSpinner, withSending, withSpinnerOnSending, withError, withErrorMessage,
 | 
			
		||||
} from "../conditionalHOCs";
 | 
			
		||||
import { API_STATE } from "api/utils";
 | 
			
		||||
 | 
			
		||||
describe("conditional HOCs", () => {
 | 
			
		||||
    const First = () => <p>First</p>;
 | 
			
		||||
    const Alternative = () => <p>Alternative</p>;
 | 
			
		||||
 | 
			
		||||
    describe("withEither", () => {
 | 
			
		||||
        it("should render First component", () => {
 | 
			
		||||
            const withAlternative = withEither(() => false, Alternative);
 | 
			
		||||
            const FirstWithConditional = withAlternative(First);
 | 
			
		||||
            const { getByText } = render(<FirstWithConditional />);
 | 
			
		||||
            expect(getByText("First")).toBeDefined();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it("should render Alternative component", () => {
 | 
			
		||||
            const withAlternative = withEither(() => true, Alternative);
 | 
			
		||||
            const FirstWithConditional = withAlternative(First);
 | 
			
		||||
            const { getByText } = render(<FirstWithConditional />);
 | 
			
		||||
            expect(getByText("Alternative")).toBeDefined();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe("withSpinner", () => {
 | 
			
		||||
        it("should render First component", () => {
 | 
			
		||||
            const withSpinnerHidden = withSpinner(() => false);
 | 
			
		||||
            const FirstWithConditional = withSpinnerHidden(First);
 | 
			
		||||
            const { getByText } = render(<FirstWithConditional />);
 | 
			
		||||
            expect(getByText("First")).toBeDefined();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it("should render spinner", () => {
 | 
			
		||||
            const withSpinnerVisible = withSpinner(() => true);
 | 
			
		||||
            const FirstWithConditional = withSpinnerVisible(First);
 | 
			
		||||
            const { container } = render(<FirstWithConditional />);
 | 
			
		||||
            expect(container).toMatchSnapshot();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe("withSending", () => {
 | 
			
		||||
        it("should render First component", () => {
 | 
			
		||||
            const withAlternative = withSending(Alternative);
 | 
			
		||||
            const FirstWithConditional = withAlternative(First);
 | 
			
		||||
            const { getByText } = render(<FirstWithConditional apiState={API_STATE.SUCCESS} />);
 | 
			
		||||
            expect(getByText("First")).toBeDefined();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it("should render Alternative component", () => {
 | 
			
		||||
            const withAlternative = withSending(Alternative);
 | 
			
		||||
            const FirstWithConditional = withAlternative(First);
 | 
			
		||||
            const { getByText } = render(<FirstWithConditional apiState={API_STATE.SENDING} />);
 | 
			
		||||
            expect(getByText("Alternative")).toBeDefined();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe("withSpinnerOnSending", () => {
 | 
			
		||||
        it("should render First component", () => {
 | 
			
		||||
            const FirstWithConditional = withSpinnerOnSending(First);
 | 
			
		||||
            const { getByText } = render(<FirstWithConditional apiState={API_STATE.SUCCESS} />);
 | 
			
		||||
            expect(getByText("First")).toBeDefined();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it("should render spinner", () => {
 | 
			
		||||
            const FirstWithConditional = withSpinnerOnSending(First);
 | 
			
		||||
            const { container } = render(<FirstWithConditional apiState={API_STATE.SENDING} />);
 | 
			
		||||
            expect(container).toMatchSnapshot();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe("withError", () => {
 | 
			
		||||
        it("should render First component", () => {
 | 
			
		||||
            const withErrorHidden = withError(() => false);
 | 
			
		||||
            const FirstWithConditional = withErrorHidden(First);
 | 
			
		||||
            const { getByText } = render(<FirstWithConditional />);
 | 
			
		||||
            expect(getByText("First")).toBeDefined();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it("should render error message", () => {
 | 
			
		||||
            const withErrorVisible = withError(() => true);
 | 
			
		||||
            const FirstWithConditional = withErrorVisible(First);
 | 
			
		||||
            const { container } = render(<FirstWithConditional />);
 | 
			
		||||
            expect(container).toMatchSnapshot();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe("withErrorMessage", () => {
 | 
			
		||||
        it("should render First component", () => {
 | 
			
		||||
            const FirstWithConditional = withErrorMessage(First);
 | 
			
		||||
            const { getByText } = render(<FirstWithConditional apiState={API_STATE.SUCCESS} />);
 | 
			
		||||
            expect(getByText("First")).toBeDefined();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it("should render error message", () => {
 | 
			
		||||
            const FirstWithConditional = withErrorMessage(First);
 | 
			
		||||
            const { container } = render(<FirstWithConditional apiState={API_STATE.ERROR} />);
 | 
			
		||||
            expect(container).toMatchSnapshot();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										52
									
								
								src/utils/conditionalHOCs.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/utils/conditionalHOCs.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/)
 | 
			
		||||
 *
 | 
			
		||||
 * This is free software, licensed under the GNU General Public License v3.
 | 
			
		||||
 * See /LICENSE for more information.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import React from "react";
 | 
			
		||||
 | 
			
		||||
import { Spinner } from "bootstrap/Spinner";
 | 
			
		||||
import { API_STATE } from "api/utils";
 | 
			
		||||
import { ErrorMessage } from "./ErrorMessage";
 | 
			
		||||
 | 
			
		||||
function withEither(conditionalFn, Either) {
 | 
			
		||||
    return (Component) => (props) => {
 | 
			
		||||
        if (conditionalFn(props)) {
 | 
			
		||||
            return <Either />;
 | 
			
		||||
        }
 | 
			
		||||
        return <Component {...props} />;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Loading
 | 
			
		||||
 | 
			
		||||
function isSending(props) {
 | 
			
		||||
    if (Array.isArray(props.apiState)) {
 | 
			
		||||
        return props.apiState.some(
 | 
			
		||||
            (state) => [API_STATE.INIT, API_STATE.SENDING].includes(state),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    return [API_STATE.INIT, API_STATE.SENDING].includes(props.apiState);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const withSpinner = (conditionalFn) => withEither(conditionalFn, Spinner);
 | 
			
		||||
const withSending = (Either) => withEither(isSending, Either);
 | 
			
		||||
const withSpinnerOnSending = withSpinner(isSending);
 | 
			
		||||
 | 
			
		||||
// Error handling
 | 
			
		||||
 | 
			
		||||
const withError = (conditionalFn) => withEither(conditionalFn, ErrorMessage);
 | 
			
		||||
const withErrorMessage = withError(
 | 
			
		||||
    (props) => {
 | 
			
		||||
        if (Array.isArray(props.apiState)) {
 | 
			
		||||
            return props.apiState.includes(API_STATE.ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        return props.apiState === API_STATE.ERROR;
 | 
			
		||||
    },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
    withEither, withSpinner, withSending, withSpinnerOnSending, withError, withErrorMessage,
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user