all repos — caroster @ 535c63f081f0a6a98429277c875b9f475802e4af

[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 = ''} = process.env;
 10
 11// https://github.com/vercel/next.js/tree/canary/examples/with-apollo
 12// https://github.com/vercel/next.js/tree/canary/examples/layout-component
 13// https://www.apollographql.com/docs/react/networking/authentication/
 14// https://www.apollographql.com/docs/react/data/error-handling/
 15// https://www.apollographql.com/docs/react/caching/cache-field-behavior/#the-merge-function
 16
 17export const APOLLO_STATE_PROP_NAME = '__APOLLO_STATE__';
 18let apolloClient;
 19
 20const authLink = setContext((_, {headers}) => {
 21  // get the authentication token from local storage if it exists
 22  const {token} = useAuthStore.getState();
 23  // return the headers to the context so httpLink can read them
 24  return {
 25    headers: {
 26      ...headers,
 27      authorization: token ? `Bearer ${token}` : '',
 28    },
 29  };
 30});
 31
 32const errorLink = onError(({graphQLErrors = []}) => {
 33  const [error] = graphQLErrors;
 34  console.error({graphQLErrors});
 35
 36  if (
 37    error?.message === 'Invalid token.' ||
 38    error?.message === 'User Not Found' ||
 39    error?.message === 'Your account has been blocked by the administrator.'
 40  ) {
 41    useAuthStore.getState().setToken();
 42    useAuthStore.getState().setUser();
 43    localStorage.removeItem('token');
 44    localStorage.removeItem('user');
 45  }
 46});
 47
 48const httpLink = uri =>
 49  new HttpLink({
 50    uri,
 51    credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
 52  });
 53
 54const createApolloClient = () => {
 55  return new ApolloClient({
 56    ssrMode: typeof window === 'undefined',
 57    link: from([authLink, errorLink, httpLink(`${STRAPI_URL}/graphql`)]),
 58    cache: new InMemoryCache({
 59      typePolicies: {
 60        Event: {
 61          fields: {
 62            waitingList: {
 63              merge(_, incoming) {
 64                return incoming;
 65              },
 66            },
 67          },
 68        },
 69        Car: {
 70          fields: {
 71            passengers: {
 72              merge(_, incoming) {
 73                return incoming;
 74              },
 75            },
 76          },
 77        },
 78      },
 79    }),
 80  });
 81};
 82
 83export const initializeApollo = (initialState = null) => {
 84  const _apolloClient = apolloClient ?? createApolloClient();
 85
 86  // If your page has Next.js data fetching methods that use Apollo Client, the initial state gets hydrated here
 87  if (initialState) {
 88    // Get existing cache, loaded during client side data fetching
 89    const existingCache = _apolloClient.extract();
 90    // Merge the existing cache into data passed from getStaticProps/getServerSideProps
 91    const data = merge(initialState, existingCache, {
 92      // Combine arrays using object equality (like in sets)
 93      arrayMerge: (destinationArray, sourceArray) => [
 94        ...sourceArray,
 95        ...destinationArray.filter(d => sourceArray.every(s => !isEqual(d, s))),
 96      ],
 97    });
 98    // Restore the cache with the merged data
 99    _apolloClient.cache.restore(data);
100  }
101
102  // For SSG and SSR always create a new Apollo Client
103  if (typeof window === 'undefined') return _apolloClient;
104
105  // Create the Apollo Client once in the client
106  if (!apolloClient) apolloClient = _apolloClient;
107  return _apolloClient;
108};
109
110export const addApolloState = (client, pageProps) => {
111  if (pageProps?.props) {
112    pageProps.props[APOLLO_STATE_PROP_NAME] = client.cache.extract();
113  }
114  return pageProps;
115};
116
117export const useApollo = pageProps => {
118  const state = pageProps[APOLLO_STATE_PROP_NAME];
119
120  return useMemo(() => initializeApollo(state), [state]);
121};