/
root.tsx
165 lines (151 loc) · 4.12 KB
/
root.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import {useNonce} from '@shopify/hydrogen';
import {
defer,
type SerializeFrom,
type LoaderFunctionArgs,
} from '@shopify/remix-oxygen';
import {
Links,
Meta,
Outlet,
Scripts,
LiveReload,
useMatches,
useRouteError,
useLoaderData,
ScrollRestoration,
isRouteErrorResponse,
type ShouldRevalidateFunction,
} from '@remix-run/react';
import favicon from '../public/favicon.svg';
import resetStyles from './styles/reset.css';
import appStyles from './styles/app.css';
// 1. Import the ShopifyCookieBanner component
import {ShopifyCookieBanner} from '~/components/ShopifyCookieBanner';
/**
* This is important to avoid re-fetching root queries on sub-navigations
*/
export const shouldRevalidate: ShouldRevalidateFunction = ({
formMethod,
currentUrl,
nextUrl,
}) => {
// revalidate when a mutation is performed e.g add to cart, login...
if (formMethod && formMethod !== 'GET') {
return true;
}
// revalidate when manually revalidating via useRevalidator
if (currentUrl.toString() === nextUrl.toString()) {
return true;
}
return false;
};
export function links() {
return [
{rel: 'stylesheet', href: resetStyles},
{rel: 'stylesheet', href: appStyles},
{
rel: 'preconnect',
href: 'https://cdn.shopify.com',
},
{
rel: 'preconnect',
href: 'https://shop.app',
},
{rel: 'icon', type: 'image/svg+xml', href: favicon},
];
}
/**
* Access the result of the root loader from a React component.
*/
export const useRootLoaderData = () => {
const [root] = useMatches();
return root?.data as SerializeFrom<typeof loader>;
};
export async function loader({context}: LoaderFunctionArgs) {
const {customerAccount, cart, env} = context;
const isLoggedInPromise = customerAccount.isLoggedIn();
// defer the cart query by not awaiting it
const cartPromise = cart.get();
return defer(
{
cart: cartPromise,
isLoggedIn: isLoggedInPromise,
// 2. Return the environment variables required by the ShopifyCookieBanner component
env: {
publicStoreDomain: env.PUBLIC_STORE_DOMAIN,
checkoutRootDomain: env.PUBLIC_CHECKOUT_DOMAIN,
storefrontAccessToken: env.PUBLIC_STOREFRONT_API_TOKEN,
storefrontRootDomain: env.PUBLIC_STORE_DOMAIN,
},
},
{
headers: {
'Set-Cookie': await context.session.commit(),
},
},
);
}
export default function App() {
const nonce = useNonce();
const {env} = useLoaderData<typeof loader>();
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
{/* 3. Render the ShopifyCookieBanner component with the environment variables */}
<ShopifyCookieBanner
checkoutRootDomain={env.checkoutRootDomain}
shopDomain={env.publicStoreDomain}
storefrontAccessToken={env.storefrontAccessToken}
storefrontRootDomain={env.storefrontRootDomain}
/>
</head>
<body>
<Outlet />
<ScrollRestoration nonce={nonce} />
<Scripts nonce={nonce} />
<LiveReload nonce={nonce} />
</body>
</html>
);
}
export function ErrorBoundary() {
const error = useRouteError();
const nonce = useNonce();
let errorMessage = 'Unknown error';
let errorStatus = 500;
if (isRouteErrorResponse(error)) {
errorMessage = error?.data?.message ?? error.data;
errorStatus = error.status;
} else if (error instanceof Error) {
errorMessage = error.message;
}
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<div className="route-error">
<h1>Oops</h1>
<h2>{errorStatus}</h2>
{errorMessage && (
<fieldset>
<pre>{errorMessage}</pre>
</fieldset>
)}
</div>
<ScrollRestoration nonce={nonce} />
<Scripts nonce={nonce} />
<LiveReload nonce={nonce} />
</body>
</html>
);
}