all repos — caroster @ 5ecddb30cd1351970186d1d7939cad57554ce781

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

frontend/lib/apolloClient.tsx (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
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
16export const APOLLO_STATE_PROP_NAME = '__APOLLO_STATE__';
17let apolloClient;
18
19const authLink = setContext((_, {headers}) => {
20  // get the authentication token from local storage if it exists
21  const {token} = useAuthStore.getState();
22  // return the headers to the context so httpLink can read them
23  return {
24    headers: {
25      ...headers,
26      authorization: token ? `Bearer ${token}` : '',
27    },
28  };
29});
30
31const errorLink = onError(({graphQLErrors = []}) => {
32  const [error] = graphQLErrors;
33  console.error({graphQLErrors});
34
35  if (
36    error?.message === 'Invalid token.' ||
37    error?.message === 'User Not Found' ||
38    error?.message === 'Your account has been blocked by the administrator.'
39  ) {
40    useAuthStore.getState().setToken();
41    useAuthStore.getState().setUser();
42    localStorage.removeItem('token');
43    localStorage.removeItem('user');
44  }
45});
46
47const httpLink = uri =>
48  new HttpLink({
49    uri, // Server URL (must be absolute)
50    credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
51  });
52
53const createApolloClient = () => {
54  return new ApolloClient({
55    ssrMode: typeof window === 'undefined',
56    link: from([authLink, errorLink, httpLink(`${STRAPI_URL}/graphql`)]),
57    cache: new InMemoryCache(),
58  });
59};
60
61export const initializeApollo = (initialState = null) => {
62  const _apolloClient = apolloClient ?? createApolloClient();
63
64  // If your page has Next.js data fetching methods that use Apollo Client, the initial state gets hydrated here
65  if (initialState) {
66    // Get existing cache, loaded during client side data fetching
67    const existingCache = _apolloClient.extract();
68    // Merge the existing cache into data passed from getStaticProps/getServerSideProps
69    const data = merge(initialState, existingCache, {
70      // Combine arrays using object equality (like in sets)
71      arrayMerge: (destinationArray, sourceArray) => [
72        ...sourceArray,
73        ...destinationArray.filter(d => sourceArray.every(s => !isEqual(d, s))),
74      ],
75    });
76    // Restore the cache with the merged data
77    _apolloClient.cache.restore(data);
78  }
79
80  // For SSG and SSR always create a new Apollo Client
81  if (typeof window === 'undefined') return _apolloClient;
82
83  // Create the Apollo Client once in the client
84  if (!apolloClient) apolloClient = _apolloClient;
85  return _apolloClient;
86};
87
88export const addApolloState = (client, pageProps) => {
89  if (pageProps?.props) {
90    pageProps.props[APOLLO_STATE_PROP_NAME] = client.cache.extract();
91  }
92  return pageProps;
93};
94
95export const useApollo = pageProps => {
96  const state = pageProps[APOLLO_STATE_PROP_NAME];
97
98  return useMemo(() => initializeApollo(state), [state]);
99};