all repos — caroster @ 79cd68b76c662e9cd5d1940b2feba41767825cd9

[Octree] Group carpool to your event https://caroster.io

frontend/lib/apolloClient.ts (view raw)

  1import {useMemo} from 'react';
  2import {ApolloClient, HttpLink, InMemoryCache, from} from '@apollo/client';
  3import {setContext} from '@apollo/client/link/context';
  4import {onError} from '@apollo/client/link/error';
  5import merge from 'deepmerge';
  6import isEqual from 'lodash/isEqual';
  7import useAuthStore from '../stores/useAuthStore';
  8
  9const {STRAPI_URL = 'http://localhost:1337'} = process?.env;
 10
 11export const APOLLO_STATE_PROP_NAME = '__APOLLO_STATE__';
 12let apolloClient;
 13
 14const authLink = setContext((_, {headers}) => {
 15  // get the authentication token from local storage if it exists
 16  const {token} = useAuthStore.getState();
 17  // return the headers to the context so httpLink can read them
 18  return {
 19    headers: {
 20      ...headers,
 21      authorization: token ? `Bearer ${token}` : '',
 22    },
 23  };
 24});
 25
 26const errorLink = onError(error => {
 27  const {networkError, graphQLErrors} = error;
 28  console.error({networkError, graphQLErrors});
 29  const isUnauthorized = networkError?.response?.status === 401;
 30
 31  if (isUnauthorized) {
 32    console.error('Unauthorized response received from GraphQL. Logout user.');
 33    useAuthStore.getState().setToken();
 34    useAuthStore.getState().setUser();
 35    localStorage.removeItem('token');
 36    localStorage.removeItem('user');
 37  }
 38});
 39
 40const httpLink = uri =>
 41  new HttpLink({
 42    uri,
 43    credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
 44  });
 45
 46const createApolloClient = () => {
 47  return new ApolloClient({
 48    ssrMode: typeof window === 'undefined',
 49    link: from([authLink, errorLink, httpLink(`${STRAPI_URL}/graphql`)]),
 50    cache: new InMemoryCache({
 51      typePolicies: {
 52        Event: {
 53          fields: {
 54            waitingList: {
 55              merge(_, incoming) {
 56                return incoming;
 57              },
 58            },
 59          },
 60        },
 61        Car: {
 62          fields: {
 63            passengers: {
 64              merge(_, incoming) {
 65                return incoming;
 66              },
 67            },
 68          },
 69        },
 70      },
 71    }),
 72  });
 73};
 74
 75export const initializeApollo = (initialState = null) => {
 76  const _apolloClient = apolloClient ?? createApolloClient();
 77
 78  // If your page has Next.js data fetching methods that use Apollo Client, the initial state gets hydrated here
 79  if (initialState) {
 80    // Get existing cache, loaded during client side data fetching
 81    const existingCache = _apolloClient.extract();
 82    // Merge the existing cache into data passed from getStaticProps/getServerSideProps
 83    const data = merge(initialState, existingCache, {
 84      // Combine arrays using object equality (like in sets)
 85      arrayMerge: (destinationArray, sourceArray) => [
 86        ...sourceArray,
 87        ...destinationArray.filter(d => sourceArray.every(s => !isEqual(d, s))),
 88      ],
 89    });
 90    // Restore the cache with the merged data
 91    _apolloClient.cache.restore(data);
 92  }
 93
 94  // For SSG and SSR always create a new Apollo Client
 95  if (typeof window === 'undefined') return _apolloClient;
 96
 97  // Create the Apollo Client once in the client
 98  if (!apolloClient) apolloClient = _apolloClient;
 99  return _apolloClient;
100};
101
102export const addApolloState = (client, pageProps) => {
103  if (pageProps?.props) {
104    pageProps.props[APOLLO_STATE_PROP_NAME] = client.cache.extract();
105  }
106  return pageProps;
107};
108
109export const useApollo = pageProps => {
110  const state = pageProps[APOLLO_STATE_PROP_NAME];
111
112  return useMemo(() => initializeApollo(state), [state]);
113};