reactjstypescriptrestnext.jshigher-order-components

Next.js | HOC from REST API with Typescript not being read when wrapping a child component to access it's data


I have this HOC line of code from withUser.tsx. When a user is authenticated, the authenticated pages will then be wrapped by it so that the specified user-role will be the one to only have access to pages intended.

import axios, { AxiosError } from "axios";
import { API } from "../config";
import { getCookie } from "../helpers/auth";

const withUser = (Page: any) => {
  const WithAuthUser = (props: any): JSX.Element => <Page {...props} />;
  WithAuthUser.getInitialProps = async (context: any): Promise<any> => {
    const token = getCookie("token", context.req);
    let user = null;
    let userLinks = [];

    if (token) {
      try {
        const response = await axios.get(`${API}/user`, {
          headers: {
            authorization: `Bearer ${token}`,
            contentType: "application/json",
          },
        });

        console.log("Response in withUser: ", response);
        user = response.data.user;
        userLinks = response.data.links;
      } catch (err: unknown) {
        const error = err as AxiosError;
        if (error.response?.status === 401) {
          user = null;
        }
      }
    }

    if (user === null) {
      // redirect
      context.res.writeHead(302, {
        Location: "/",
      });
      context.res.end();
    } else {
      return {
        ...(Page.getInitialProps ? await Page.getInitialProps(context) : {}),
        user,
        token,
        userLinks,
      };
    }
  };

  return WithAuthUser;
};

export default withUser;

Now, the above code is not my final writing of TypeScript, I could be wrong but this is how I converted it from JS, please feel free to give me a refactored TSX codes here, here is the JS version:

import axios from "axios";
import { API } from "../config";
import { getCookie } from "../helpers/auth";

const withUser = (Page) => {
  const WithAuthUser = (props) => <Page {...props} />;
  WithAuthUser.getInitialProps = async (context) => {
    const token = getCookie("token", context.req);
    let user = null;
    let userLinks = [];

    if (token) {
      try {
        const response = await axios.get(`${API}/user`, {
          headers: {
            authorization: `Bearer ${token}`,
            contentType: "application/json",
          },
        });

        console.log("Response in withUser: ", response);
        user = response.data.user;
        userLinks = response.data.links;
      } catch (error) {
        if (error.response.status === 401) {
          user = null;
        }
      }
    }

    if (user === null) {
      // redirect
      context.res.writeHead(302, {
        Location: "/",
      });
      context.res.end();
    } else {
      return {
        ...(Page.getInitialProps ? await Page.getInitialProps(context) : {}),
        user,
        token,
        userLinks,
      };
    }
  };

  return WithAuthUser;
};

export default withUser;

But now, when using it when an Authenticated /user page, I could not get any data from the user. It will give me an undefined and for example, user.first_name will not be shown:

import withUser from "../withUser";

const User = ({ user }: any): JSX.Element => (
  <div className="flex min-h-screen flex-col items-center justify-center">
   {user.first_name}
  </div>
);

export default withUser(User);

Any correct ways of implementing this would be very much appreciated. Thanks!


Solution

  • Okay, sorry this was just a bug and I figure out that I did not have any userLinks from the REST API that I was passing in. So I can already consider this question as resolved as I have already fixed it.

    Here is the code of my fix:

    import axios, { AxiosError } from "axios";
    import { API } from "../config";
    import { getCookie } from "../helpers/auth";
    
    const withUser = (Page: any) => {
        const WithAuthUser = (props: any): JSX.Element => <Page {...props} />;
        WithAuthUser.getInitialProps = async (context: any): Promise<any> => {
            const token = getCookie("token", context.req);
            console.log("token: ", token);
    
            let user = null;
    
            if (token) {
                try {
                    const response = await axios.get(`${API}/user`, {
                        headers: {
                            authorization: `Bearer ${token}`,
                            contentType: "application/json",
                        },
                    });
    
                    console.log("response: ", response);
                    user = response.data;
                } catch (err: unknown) {
                    const error = err as AxiosError;
                    if (error.response?.status === 401) {
                        user = null;
                    }
                }
            }
    
            if (user === null) {
                // redirect
                context.res.writeHead(302, {
                    Location: "/",
                });
                context.res.end();
            } else {
                return {
                    ...(Page.getInitialProps ? await Page.getInitialProps(context) : {}),
                    user,
                    token,
                };
            }
        }
    
        return WithAuthUser;
    }
    export default withUser;