all repos — caroster @ a781a5fafbf60b3c6587213cf3c9bfb735bdf933

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

frontend/lib/apolloClient.tsx (view raw)

 1import {useMemo} from 'react';
 2import {ApolloClient, HttpLink, InMemoryCache} 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
 9export const APOLLO_STATE_PROP_NAME = '__APOLLO_STATE__';
10
11export let apolloClient;
12
13const httpLink = new HttpLink({
14  uri: '/graphql', // Server URL (must be absolute)
15  credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
16});
17
18const handleError = onError(({graphQLErrors = []}) => {
19  const [error] = graphQLErrors;
20  console.error({graphQLErrors, error});
21
22  if (error?.message === 'Invalid token.') {
23    useAuthStore.getState().logout();
24  } else if (error?.message == 'Forbidden') {
25    window.location.href = '/auth/login';
26  }
27});
28
29const createApolloClient = token => {
30  return new ApolloClient({
31    ssrMode: typeof window === 'undefined',
32    link: setContext((_, {headers}) => {
33      // return the headers to the context so httpLink can read them
34      return {
35        headers: {
36          ...headers,
37          authorization: token ? `Bearer ${token}` : '',
38        },
39      };
40    })
41      .concat(handleError)
42      .concat(httpLink),
43    cache: new InMemoryCache(),
44  });
45};
46
47export const initializeApollo = (initialState: object, token: string) => {
48  const _apolloClient = createApolloClient(token);
49
50  // If your page has Next.js data fetching methods that use Apollo Client, the initial state gets hydrated here
51  if (initialState) {
52    // Get existing cache, loaded during client side data fetching
53    const existingCache = _apolloClient.extract();
54
55    // Merge the existing cache into data passed from getStaticProps/getServerSideProps
56    const data = merge(initialState, existingCache, {
57      // combine arrays using object equality (like in sets)
58      arrayMerge: (destinationArray, sourceArray) => [
59        ...sourceArray,
60        ...destinationArray.filter(d => sourceArray.every(s => !isEqual(d, s))),
61      ],
62    });
63
64    // Restore the cache with the merged data
65    _apolloClient.cache.restore(data);
66  }
67  // For SSG and SSR always create a new Apollo Client
68  if (typeof window === 'undefined') return _apolloClient;
69  // Create the Apollo Client once in the client
70  if (!apolloClient) apolloClient = _apolloClient;
71
72  return _apolloClient;
73};
74
75export const addApolloState = (client, pageProps) => {
76  if (pageProps?.props) {
77    pageProps.props[APOLLO_STATE_PROP_NAME] = client.cache.extract();
78  }
79
80  return pageProps;
81};
82
83export const useApollo = pageProps => {
84  const state = pageProps[APOLLO_STATE_PROP_NAME];
85  const token = useAuthStore(s => s.token);
86  return useMemo(() => {
87    const newClient = initializeApollo(state, token);
88    apolloClient = newClient;
89    return newClient;
90  }, [state, token]);
91};