Skip to content

Instantly share code, notes, and snippets.

@Yasir5247
Created September 2, 2022 14:06
Show Gist options
  • Save Yasir5247/58866e4fc269b124bcf11c8aa3cd4921 to your computer and use it in GitHub Desktop.
Save Yasir5247/58866e4fc269b124bcf11c8aa3cd4921 to your computer and use it in GitHub Desktop.
apolloClient
import {ApolloClient, HttpLink, from, fromPromise} from '@apollo/client';
import {setContext} from '@apollo/client/link/context';
import {RetryLink} from '@apollo/client/link/retry';
import {onError} from '@apollo/client/link/error';
import {refresh} from 'react-native-app-auth';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {getTokenSync, getToken} from '../../utils/getToken';
import {test_config, prod_config} from '../../utils/efaasConfig';
import {cache} from './cache';
getToken();
//httpLink
const httpLink = new HttpLink({
uri: 'https://efaas.mv/graphql',
credentials: 'include',
});
//authLink
const authLink = setContext(async (_, {headers}) => {
const token = await AsyncStorage.getItem('@token');
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : null,
},
};
});
//retryLink
const retryLink = new RetryLink({
attempts: (count, operation, error) => {
const isMutation =
operation &&
operation.query &&
operation.query.definitions &&
Array.isArray(operation.query.definitions) &&
operation.query.definitions.some(def => def.kind === 'OperationDefinition' && def.operation === 'mutation');
if (isMutation) {
return !!error && count < 25;
}
return !!error && count < 6;
},
});
//refresh token
const getRefreshToken = async () => {
try {
const refreshToken = await AsyncStorage.getItem('@refreshToken');
console.log('refreshToken', refreshToken);
if (refreshToken) {
console.log('im here');
const result = await refresh(test_config, {
refreshToken: refreshToken,
});
console.log('result', result);
console.log('new---AccessToken', result.accessToken);
return result.accessToken;
}
} catch (error) {
console.log(error);
}
};
//errorLink
const errorLink = onError(({graphQLErrors, networkError, operation, forward}) => {
// console.log('hellow');
if (graphQLErrors) {
for (let err of graphQLErrors) {
console.log('errorExtentionCode', err.extensions.code);
switch (err.extensions.code) {
case 'INTERNAL_SERVER_ERROR':
return fromPromise(
getRefreshToken().catch(error => {
// console.log('error', error);
// Handle token refresh errors e.g clear stored tokens, redirect to login
return;
}),
)
.filter(value => Boolean(value))
.flatMap(accessToken => {
const oldHeaders = operation.getContext().headers;
// modify the operation context with a new token
operation.setContext({
headers: {
...oldHeaders,
authorization: `Bearer ${accessToken}`,
},
});
//retry the request, returning the new observable
return forward(operation);
});
}
}
}
});
export const client = new ApolloClient({
cache,
link: from([errorLink, authLink, retryLink, httpLink]),
assumeImmutableResults: true,
connectToDevTools: true,
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
errorPolicy: 'none',
},
query: {
fetchPolicy: 'cache-first',
errorPolicy: 'all',
},
},
});
@EhsanHerai
Copy link

import React, { useState , useContext} from "react";
import { ApolloLink, split, fromPromise } from "apollo-link";
import { getMainDefinition } from "apollo-utilities";
import { WebSocketLink } from "apollo-link-ws";
import { onError } from "apollo-link-error";
import { ApolloClient } from "apollo-client";
import { setContext } from "apollo-link-context";
import { InMemoryCache } from "apollo-cache-inmemory";
import { createUploadLink } from "apollo-upload-client";
//@ts-ignore
// import Modal from "react-awesome-modal";
// import ApolloLinkTimeout from 'apollo-link-timeout';
// import AsyncStorage from '@react-native-community/async-storage'
import QueueLink from "apollo-link-queue";
import { ApolloProvider } from "react-apollo";
// import NetInfo from '@react-native-community/netinfo'
import { RetryLink } from "apollo-link-retry";
import {UserContext} from '../../components/Router/userContext'
import { useRouter} from 'next/router'
// import "../../cssFile/newClient_style.scss";
import {
  JSON_WEB_TOKEN_NAME,
  GRAPHQL_ENDPOINT,
  X_ACCESS_TOKEN,
  X_REFRESH_TOKEN,
} from "../constant/index";
// import { useDispatch } from "react-redux";
// import loginAction from "../../redux/actions/loginAction";
//@ts-ignore
// import { browserHistory }  from 'react-router-dom';
import { api } from "../axios/axios";
// const GRAPHQL_ENDPOINT = "https://anarback.xyz/"
// import { ShowMessageBarAction } from '../../redux/actions/showErrorMessageBar'
// import { ShowMessageBarDataType } from '../../redux/actions/showErrorMessageBar'
// import { useHistory } from 'react-router'
// import { companyInfoAction } from "../../redux/actions/companyInfoAction";
const SOCKET_ENDPOINT = "wss://anarback.xyz/graphql";

const ApolloManger = (props: any) => {
  // const dispatch = useDispatch();
  // const history = useHistory()
  const router = useRouter();
  const [isLogin , setIsLogin] = useContext(UserContext)
  const [showModalErrorLogin, setShowModalErrorLogin] = useState({
    show: false,
    text: "برای دسترسی به حساب خود لطفا دوباره لاگن شوید",
  });
  const retryIf = (error: any, operation: any) => {
    const doNotRetryCodes = [500, 400];
    return !!error && !doNotRetryCodes.includes(error.statusCode);
  };

  const queueLink = new QueueLink();
  // if (navigator.onLine) {
  //   // alert('online');
  //   queueLink.open();
  // } else {
  //   // alert('offline');
  //   queueLink.close();
  // }
  // window.addEventListener("online", () => {
  //   queueLink.open();
  // });
  // window.addEventListener("offline", () => {
  //   queueLink.close();
  // });
  const retryLink = new RetryLink({
    delay: {
      initial: 300,
      max: Infinity,
      jitter: true,
    },
    attempts: {
      max: 5,
      retryIf,
    },
  });
  let isRefreshing = false;
  let pendingRequests: any = [];
  const getTokenFunction = async () => {
    const x_refresh_token = localStorage.getItem(X_REFRESH_TOKEN);
    // 
    if (x_refresh_token) {
      // 
      try {
        // let tokenData ;
        let data: any = await api().get("/api/refreshAccessToken")
        // 

        // 
        if (data?.data["x-access-token"]) {
          localStorage?.setItem(X_REFRESH_TOKEN, data?.data["x-refresh-token"]);
          localStorage?.setItem(X_ACCESS_TOKEN, data?.data["x-access-token"]);

          return data?.data["x-access-token"]
          // return {
          //   x_refresh_token: data?.data["x-refresh-token"],
          //   x_access_token: data?.data["x-access-token"],
          // };
        }
        // return data

      } catch (error:any) {
        console.log("eeeeeeeee" , error)
        if (error?.response?.status === 401 || error?.response?.status === 400){
          localStorage?.removeItem(X_REFRESH_TOKEN)
          localStorage.removeItem(X_ACCESS_TOKEN)
          router.push("/loginPage")
          setIsLogin(false)
        }
        if (error.response?.data === "company listed in token not exists") {
          localStorage?.removeItem(X_REFRESH_TOKEN)
          localStorage.removeItem(X_ACCESS_TOKEN)
          setShowModalErrorLogin({
            show: true,
            text: "برای دسترسی به حساب خود لطفا دوباره لاگین شوید",
          });
        }
        if (error?.response?.statusText === "token is black listed"){
          
          localStorage?.removeItem(X_REFRESH_TOKEN)
          localStorage.removeItem(X_ACCESS_TOKEN)
          router.push("/loginPage")
          setIsLogin(false)
        }
        if (error?.response?.data === "refresh token is blacklisted") {
          localStorage?.removeItem(X_REFRESH_TOKEN)
          localStorage.removeItem(X_ACCESS_TOKEN)
          setShowModalErrorLogin({
            show: true,
            text: "برای دسترسی به حساب خود لطفا دوباره لاگین شوید",
          });
        }
        if (error?.response?.statusText === "Unauthorized") {

          pendingRequests = []
          localStorage.removeItem(X_REFRESH_TOKEN)
          localStorage.removeItem(X_ACCESS_TOKEN)
          // localStorage.setItem(JSON_WEB_TOKEN_NAME,'')
          // if (window.location.pathname !== "/") {
          //   window.location.href = "/";
          //   // window.location.reload()
          // }
          if (!showModalErrorLogin.show) {
            setShowModalErrorLogin({
              show: true,
              text: "برای دسترسی به حساب خود لطفا دوباره لاگین شوید",
            });
          }

        }
      }
    }
    // 
    // let newTokenData: any = await fetch(TOKEN_RENEW, {
    //   method: "GET",
    //   headers: new Headers({
    //     "Content-Type": "text/plain",
    //     "X-My-Custom-Header": "value-v",
    //     "x-refresh-token": `${x_refresh_token}`,
    //   }),
    // });
    // newTokenData = newTokenData.json()
    // 
  };

  const resolvePendingRequests = () => {
    //@ts-ignore
    pendingRequests.map(callback => callback());
    pendingRequests = [];
  };
  const errorLink = onError(
    //@ts-ignore
    ({ graphQLErrors, networkError, operation, forward }) => {

      if (graphQLErrors) {
        //  
        for (let err of graphQLErrors) {
          //@ts-ignore
          switch (err.extensions.code) {
            case 'UNAUTHENTICATED':
              // error code is set to UNAUTHENTICATED
              // when AuthenticationError thrown in resolver
              let forward$;
              if (!isRefreshing) {
                isRefreshing = true;
                forward$ = fromPromise(
                  getTokenFunction()
                    .then((data) => {
                      // Store the new tokens for your auth link
                      resolvePendingRequests();
                      isRefreshing = false;
                      return data;
                    })
                    .catch(error => {
                      pendingRequests = [];
                      // Handle token refresh errors e.g clear stored tokens, redirect to login, ...
                      return;
                    })
                    .finally(() => {
                      isRefreshing = false;
                    })
                ).filter((value:any) => Boolean(value));
              } else {
                // Will only emit once the Promise is resolved
                forward$ = fromPromise(
                  new Promise((resolve: any) => {
                    pendingRequests.push(() => resolve());
                  })
                );
              }


              return forward$.flatMap(() => {
                const accessToken = localStorage.getItem(X_ACCESS_TOKEN)
                const oldHeaders = operation.getContext().headers
                operation.setContext({
                  headers: {
                    ...oldHeaders,
                    "x-access-token": accessToken
                  }
                })
                return forward(operation)
              });

            case "UNAUTHORIZED":
              //  
              // dispatch(loginAction(false))
              // history.push("/blacklistPage")
              if (graphQLErrors?.[0]?.message.includes("بلاک")) {

                // dispatch(companyInfoAction({ isBlocked: true }))
              } else {
                // const data: ShowMessageBarDataType = {
                //   showError: true,
                //   textErrorMessage: graphQLErrors?.[0]?.message,
                //   typeMessage: "error"
                // }
                // dispatch(ShowMessageBarAction(data))

              }
              return
            default:
              // const data: ShowMessageBarDataType = {
              //   showError: true,
              //   textErrorMessage: graphQLErrors?.[0]?.message,
              //   typeMessage: "error"
              // }
              // dispatch(ShowMessageBarAction(data))
              return
          }
        }
      }
      if (networkError) {

        const oldHeaders = operation.getContext().headers
        operation.setContext({
          headers: {
            ...oldHeaders
          }
        })
        return forward(operation)

      }
    }
  );
  // const timeoutLink = new ApolloLinkTimeout(30000)
  const loggerLink = new ApolloLink((operation:any, forward:any) => {

    operation.setContext({ start: new Date() });
    return forward(operation).map((response:any) => {
      //@ts-ignore
      const responseTime = new Date() - operation.getContext().start;

      return response;
    });
  });
  const uploadHttpLink: any = createUploadLink({
    uri: GRAPHQL_ENDPOINT,
  });
  // const wsLink = new WebSocketLink({
  //   uri: SOCKET_ENDPOINT,
  //   options: {
  //     reconnect: true,
  //     connectionParams: () => {
  //       // const token = localStorage.getItem(JSON_WEB_TOKEN_NAME);
  //       const x_access_token = localStorage?.getItem(X_ACCESS_TOKEN);
  //       // const x_refresh_token = localStorage?.getItem(X_REFRESH_TOKEN);
  //       // console("token : ========="+token)
  //       // 
  //       // 
  //       return {
  //         // authorization: `Bearer ${await AsyncStorage.getItem(TOKEN_NAME)}`,
  //         // ...(token ? { authorization: `Bearer ${token}` } : {}),
  //         ...(x_access_token ? { "x-access-token": x_access_token } : {}),
  //         // ...(x_refresh_token ? { "x-refresh-token": x_refresh_token } : {}),
  //       };
  //     },
  //   },
  // });
  //@ts-ignore
  const authLink = setContext((_, { headers }) => {
    // 
    // get the authentication token from local storage if it exists
    // return the headers to the context so link can read them
    // const token = localStorage.getItem(JSON_WEB_TOKEN_NAME);
    // 
    const x_access_token = localStorage?.getItem(X_ACCESS_TOKEN);
    // 
    // const x_refresh_token = localStorage?.getItem(X_REFRESH_TOKEN);
    return {
      headers: {
        ...headers,
        // ...(token ? { authorization: `Bearer ${token}` } : {}),
        ...(x_access_token ? { "x-access-token": x_access_token } : {}),
        // ...(x_refresh_token ? { "x-refresh-token": x_refresh_token } : {}),
      },
    };
  });
  // const getTokenLink = useRef(
  //   new ApolloLink((operation, forward) => {
  //     return forward(operation).map((response) => {
  //       const context = operation.getContext();
  //       const accessToken = context.response.headers.get("x-access-token");
  //       const refreshToken = context.response.headers.get("x-refresh-token");

  //       // 
  //       // 

  //       if (accessToken) {
  //         //save new token
  //         localStorage?.setItem(X_ACCESS_TOKEN, accessToken);
  //         localStorage.setItem(X_REFRESH_TOKEN, refreshToken);
  //       }

  //       return response;
  //     });
  //     // return forward(operation);
  //   })
  // ).current;

  const checkTokenLink = new ApolloLink((operation:any, forward:any) => {
    return forward(operation).map((response:any) => {
      const headers = operation.getContext().headers;


      return response
    })
  })
  const wsLinks = ApolloLink.from([
    loggerLink,
    authLink,
    retryLink,
    // queueLink,
    errorLink,
    // getTokenLink,
    // wsLink,
  ]);
  const httpLinks = ApolloLink.from([
    retryLink,
    queueLink,
    // checkTokenLink,
    errorLink,
    authLink,
    // getTokenLink,
    // timeoutLink,
    uploadHttpLink,
  ]);

  const link = split(
    //@ts-ignore
    ({ query }) => {
      //@ts-ignore
      const { kind, operation } = getMainDefinition(query);
      return kind === "OperationDefinition" && operation === "subscription";
    },
    wsLinks,
    httpLinks
  );
  const client = new ApolloClient({
    link,
    cache: new InMemoryCache(),
  });


  const closeModalOrderDetails = () => {


  };


  const handleLogOutFunction = () => {

    // dispatch(loginAction(false));
    localStorage.setItem(JSON_WEB_TOKEN_NAME, "");
    localStorage.setItem(X_ACCESS_TOKEN, "")
    localStorage.setItem(X_REFRESH_TOKEN, '')

    setShowModalErrorLogin({
      show: false,
      text: "",
    });
    if (window.location.pathname !== "/") {
      window.location.href = "/";
      window.location.reload()
    }

  };

  return (
    <>
      {/* <Modal
        visible={showModalErrorLogin.show}
        width="330"
        height="200"
        effect="fadeInDown"
        onClickAway={closeModalOrderDetails}
      >
        <div className="newClient__modal--header">
          {showModalErrorLogin?.text}
        </div>
        <div className="newClient__modal--content">
          <div
            className="newClient__modal--content-button"
            onClick={handleLogOutFunction}
          >
            باشه
          </div>
        </div>
      </Modal> */}
      <ApolloProvider client={client}>{props.children}</ApolloProvider>
    </>
  );
};
export { ApolloManger };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment