` elements but only the React Components. If you want the `expanded view` similar to how it looks in the course then you can delete the default `component filter` from the React devtools.
10 |
11 | [https://github.com/facebook/react/blob/main/packages/react-devtools/CHANGELOG.md#component-filters](https://github.com/facebook/react/blob/main/packages/react-devtools/CHANGELOG.md#component-filters)
12 |
--------------------------------------------------------------------------------
/RFB/14 - Loading data into state onClick - 257754270.md:
--------------------------------------------------------------------------------
1 | # Loading data into state onClick
2 |
3 | If you are experiencing issues with the property `value.value` being *_undefined_* then please follow this solution.
4 |
5 | On each occurance where a React Ref is used as `value.value` in the course you need to replace it with `current.value`. The `starter files` for the course have been updated to use `React 16.6.3` which uses the new syntax but the course videos are still using the previous syntax.
6 |
7 | [GitHub Stepped Solutions](https://github.com/wesbos/React-For-Beginners-Starter-Files/blob/master/stepped-solutions/14/components/AddFishForm.js#L14)
8 |
9 | ```jsx:title=src/components/AddFishForm.js {6,7,8,9,10}
10 | createFish = event => {
11 | // 1. stop the form from submitting
12 | event.preventDefault();
13 |
14 | const fish = {
15 | name: this.nameRef.current.value,
16 | price: parseFloat(this.priceRef.current.value),
17 | status: this.statusRef.current.value,
18 | desc: this.descRef.current.value,
19 | image: this.imageRef.current.value
20 | };
21 |
22 | this.props.addFish(fish);
23 | // refresh the form
24 |
25 | event.currentTarget.reset();
26 | };
27 | ```
28 |
--------------------------------------------------------------------------------
/GAT/26 - Sourcing Data from an external API - 455742585.md:
--------------------------------------------------------------------------------
1 | # Sourcing Data from an external API
2 |
3 | To fix the issue where no *beer ratings* are being generated, please add `if (!beer.rating.average) return;` to your `gatsby-node.js` file inside the beers `for...of` loop.
4 |
5 | The reason it is failing is because the last "beers" items in the API response are returning invalid strings instead of an object for the ratings. You need to add an `if statement` to your code to skip the beers with the incorrect data until they fix the API.
6 |
7 | ```js:gatsby/gatsby-node.js {10}
8 | async function fetchBeersAndTurnIntoNodes({
9 | actions,
10 | createNodeId,
11 | createContentDigest,
12 | }) {
13 | const res = await fetch('https://api.sampleapis.com/beers/ale');
14 | const beers = await res.json();
15 |
16 | for (const beer of beers) {
17 | if (!beer.rating.average) return;
18 |
19 | const nodeMeta = {
20 | id: createNodeId(`beer-${beer.name}`),
21 | parent: null,
22 | children: [],
23 | internal: {
24 | type: 'Beer',
25 | mediaType: 'application/json',
26 | contentDigest: createContentDigest(beer),
27 | },
28 | };
29 |
30 | actions.createNode({
31 | ...beer,
32 | ...nodeMeta,
33 | });
34 | }
35 | }
36 | ```
37 |
--------------------------------------------------------------------------------
/make-files.mjs:
--------------------------------------------------------------------------------
1 | import ARG from '../../Sites/bosmonster-v1/data/videos-ARG.js';
2 | import BJS from '../../Sites/bosmonster-v1/data/videos-BJS.js';
3 | import CLPU from '../../Sites/bosmonster-v1/data/videos-CLPU.js';
4 | import ES6 from '../../Sites/bosmonster-v1/data/videos-ES6.js';
5 | import GAT from '../../Sites/bosmonster-v1/data/videos-GAT.js';
6 | import GRID from '../../Sites/bosmonster-v1/data/videos-GRID.js';
7 | import JS3 from '../../Sites/bosmonster-v1/data/videos-JS3.js';
8 | import MMD from '../../Sites/bosmonster-v1/data/videos-MMD.js';
9 | import NODE from '../../Sites/bosmonster-v1/data/videos-NODE.js';
10 | import RDX from '../../Sites/bosmonster-v1/data/videos-RDX.js';
11 | import RFB from '../../Sites/bosmonster-v1/data/videos-RFB.js';
12 | import STPU from '../../Sites/bosmonster-v1/data/videos-STPU.js';
13 | import WTF from '../../Sites/bosmonster-v1/data/videos-WTF.js';
14 | import fs from 'fs';
15 |
16 | const courses = { ARG, BJS, CLPU, ES6, GAT, GRID, JS3, MMD, NODE, RDX, RFB, RFB, STPU, WTF };
17 |
18 | for(const [course, { videos }] of Object.entries(courses)) {
19 | console.log(course)
20 | // loop over each video and create a folder and file for i
21 | for(const [i, video] of Object.entries(videos)) {
22 | // create folder
23 | fs.mkdirSync(`./${course}`, {recursive: true});
24 | // create file
25 | fs.writeFileSync(`./${course}/${video.num} - ${video.title} - ${video.id}.md`, `# ${video.title}`);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/STPU/1 - 01 - Sublime Text Settings - 220667759.md:
--------------------------------------------------------------------------------
1 | # 01 - Sublime Text Settings
2 |
3 | ## Update for SublimeText 4
4 |
5 | ### Preferences
6 |
7 | The menu option _"Preferences - Settings Default"_ does not exist anymore. It is not necessary to open the default & user preferences separately. When clicking _"Preferences - Settings"_ Sublime will open a split view with the default settings on one side and overriding user settings on the other. The same is true for keyboard shortcuts (_"Preferences - Key Bindings"_).
8 |
9 | ### Keyboard shortcut for "Preferences - Settings".
10 |
11 | The video mentions `"ctrl+,"` as the keyboard shortcut for Settings on non-macOS systems. This does not work.
12 | SublimeText 4 on Linux doesn't seem to have a keyboard shortcut set for Settings. It is not even mentioned in the default `Preferences.sublime-settings` file.
13 | One has to configure this explicitely (_"Preferences - Key Bindings")_:
14 |
15 | ```json
16 | [
17 | { "keys": ["ctrl+,"], "command": "edit_settings", "args":
18 | {
19 | "base_file": "${packages}/Default/Preferences.sublime-settings",
20 | "default": "// Settings in here override those in \"Default/Preferences.sublime-settings\",\n// and are overridden in turn by syntax-specific settings.\n{\n\t$0\n}\n"
21 | }
22 | },
23 | ]
24 | ```
25 |
26 | Credits to this solution to https://stackoverflow.com/a/38376612/128030
27 |
28 | ### Trailing comma problem
29 |
30 | Sublime Text 4 seems to have learned to tolerate trailing commas. It is not a problem anymore.
31 |
--------------------------------------------------------------------------------
/RFB/18 - Persisting our State with Firebase - 257756817.md:
--------------------------------------------------------------------------------
1 | # Persisting our State with Firebase
2 |
3 | If you don't have a `databaseURL` in your Firebase SDK config then you likely skipped the step where you had to create a `Realtime Database`. If you go and create a `Realtime Database` and then go back to the Firebase config webpage the config should then have a `databaseURL`.
4 |
5 | If you get any `@firebase/database: FIREBASE WARNING` warnings in the Browser Console that refers to `permission_denied` then you either accidentally created a `Firestore Database` instead of a `Realtime Database` or you forgot the steps to configure the Firebase `rules` for the `Realtime Database`. The database you need to configure for the course is the `Realtime Database`.
6 |
7 | Also note, the Firebase imports have been updated since the recording of the course.
8 |
9 | You can use these imports in the `base.js` file.
10 |
11 | ```js {3,4,5}
12 | import Rebase from 're-base';
13 | import firebase from 'firebase/app';
14 | import 'firebase/auth';
15 | import 'firebase/firestore';
16 | import 'firebase/database';
17 |
18 | const firebaseApp = firebase.initializeApp({
19 | apiKey: "AIzaSyDXUCNSpi5u07F76httlCTXAA4mPVQlEHs",
20 | authDomain: "catch-of-the-day-wes-bos-2.firebaseapp.com",
21 | databaseURL: "https://catch-of-the-day-wes-bos-2.firebaseio.com"
22 | });
23 |
24 | const base = Rebase.createClass(firebaseApp.database());
25 |
26 | // This is a named export
27 | export { firebaseApp };
28 |
29 | // this is a default export
30 | export default base;
31 | ```
32 |
--------------------------------------------------------------------------------
/ARG/73 - Testing our formatMoney function - 626507510.md:
--------------------------------------------------------------------------------
1 | # Testing our formatMoney function
2 |
3 | If your *Currency Strings* aren't matching in Jest when you test the `formatMoney` util function and the currency has spaces in it then it won't match, the reason is because the `Intl.NumberFormat` method uses non-breaking spaces. The `Intl.NumberFormat` method does this because you wouldn't want a currency to wrap onto multiple lines, but this causes the test to break because we use normal spaces in the strings that we type in our code.
4 |
5 | If the currency you are testing contains spaces then you'll need to use this solution. Every space in the Currency String has to be replaced by `\xa0` for the test to pass. `\xa0` is the non-breaking space character.
6 |
7 | ```js:title=__tests__/utils/formatMoney.test.js {5,6,7,8,12,13,14,15}
8 | import formatMoney from "../../utils/formatMoney";
9 |
10 | describe("formatMoney function", () => {
11 | it("works with fractional units", () => {
12 | expect(formatMoney(1)).toBe("R\xa00,01"); // R 0,01
13 | expect(formatMoney(10)).toBe("R\xa00,10"); // R 0,10
14 | expect(formatMoney(99)).toBe("R\xa00,99"); // R 0,99
15 | expect(formatMoney(101)).toBe("R\xa01,01"); // R 1,01
16 | });
17 |
18 | it("leaves off cents on whole units", () => {
19 | expect(formatMoney(100)).toBe("R\xa01"); // R 1
20 | expect(formatMoney(21000)).toBe("R\xa0210"); // R 210
21 | expect(formatMoney(55340000)).toBe("R\xa0553\xa0400"); // R 553 400
22 | expect(formatMoney(785340000)).toBe("R\xa07\xa0853\xa0400"); // R 7 853 400
23 | });
24 | })
25 | ```
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | # Logs
3 | logs
4 | *.log
5 | npm-debug.log*
6 | yarn-debug.log*
7 | yarn-error.log*
8 | lerna-debug.log*
9 | .pnpm-debug.log*
10 |
11 | # Diagnostic reports (https://nodejs.org/api/report.html)
12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13 |
14 | # Runtime data
15 | pids
16 | *.pid
17 | *.seed
18 | *.pid.lock
19 |
20 | # Directory for instrumented libs generated by jscoverage/JSCover
21 | lib-cov
22 |
23 | # Coverage directory used by tools like istanbul
24 | coverage
25 | *.lcov
26 |
27 | # nyc test coverage
28 | .nyc_output
29 |
30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
31 | .grunt
32 |
33 | # Bower dependency directory (https://bower.io/)
34 | bower_components
35 |
36 | # node-waf configuration
37 | .lock-wscript
38 |
39 | # Compiled binary addons (https://nodejs.org/api/addons.html)
40 | build/Release
41 |
42 | # Dependency directories
43 | node_modules/
44 | jspm_packages/
45 |
46 | # Snowpack dependency directory (https://snowpack.dev/)
47 | web_modules/
48 |
49 | # TypeScript cache
50 | *.tsbuildinfo
51 |
52 | # Optional npm cache directory
53 | .npm
54 |
55 | # Optional eslint cache
56 | .eslintcache
57 |
58 | # Microbundle cache
59 | .rpt2_cache/
60 | .rts2_cache_cjs/
61 | .rts2_cache_es/
62 | .rts2_cache_umd/
63 |
64 | # Optional REPL history
65 | .node_repl_history
66 |
67 | # Output of 'npm pack'
68 | *.tgz
69 |
70 | # Yarn Integrity file
71 | .yarn-integrity
72 |
73 | # dotenv environment variables file
74 | .env
75 | .env.test
76 | .env.production
77 |
78 | # parcel-bundler cache (https://parceljs.org/)
79 | .cache
80 | .parcel-cache
81 |
82 | # Next.js build output
83 | .next
84 | out
85 |
86 | # Nuxt.js build / generate output
87 | .nuxt
88 | dist
89 |
90 | # Gatsby files
91 | .cache/
92 | # Comment in the public line in if your project uses Gatsby and not Next.js
93 | # https://nextjs.org/blog/next-9-1#public-directory-support
94 | # public
95 |
96 | # vuepress build output
97 | .vuepress/dist
98 |
99 | # Serverless directories
100 | .serverless/
101 |
102 | # FuseBox cache
103 | .fusebox/
104 |
105 | # DynamoDB Local files
106 | .dynamodb/
107 |
108 | # TernJS port file
109 | .tern-port
110 |
111 | # Stores VSCode versions used for testing VSCode extensions
112 | .vscode-test
113 |
114 | # yarn v2
115 | .yarn/cache
116 | .yarn/unplugged
117 | .yarn/build-state.yml
118 | .yarn/install-state.gz
119 | .pnp.*
120 | # Logs
121 | logs
122 | *.log
123 | npm-debug.log*
124 | yarn-debug.log*
125 | yarn-error.log*
126 | lerna-debug.log*
127 | .pnpm-debug.log*
128 |
129 | # Diagnostic reports (https://nodejs.org/api/report.html)
130 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
131 |
132 | # Runtime data
133 | pids
134 | *.pid
135 | *.seed
136 | *.pid.lock
137 |
138 | # Directory for instrumented libs generated by jscoverage/JSCover
139 | lib-cov
140 |
141 | # Coverage directory used by tools like istanbul
142 | coverage
143 | *.lcov
144 |
145 | # nyc test coverage
146 | .nyc_output
147 |
148 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
149 | .grunt
150 |
151 | # Bower dependency directory (https://bower.io/)
152 | bower_components
153 |
154 | # node-waf configuration
155 | .lock-wscript
156 |
157 | # Compiled binary addons (https://nodejs.org/api/addons.html)
158 | build/Release
159 |
160 | # Dependency directories
161 | node_modules/
162 | jspm_packages/
163 |
164 | # Snowpack dependency directory (https://snowpack.dev/)
165 | web_modules/
166 |
167 | # TypeScript cache
168 | *.tsbuildinfo
169 |
170 | # Optional npm cache directory
171 | .npm
172 |
173 | # Optional eslint cache
174 | .eslintcache
175 |
176 | # Microbundle cache
177 | .rpt2_cache/
178 | .rts2_cache_cjs/
179 | .rts2_cache_es/
180 | .rts2_cache_umd/
181 |
182 | # Optional REPL history
183 | .node_repl_history
184 |
185 | # Output of 'npm pack'
186 | *.tgz
187 |
188 | # Yarn Integrity file
189 | .yarn-integrity
190 |
191 | # dotenv environment variables file
192 | .env
193 | .env.test
194 | .env.production
195 |
196 | # parcel-bundler cache (https://parceljs.org/)
197 | .cache
198 | .parcel-cache
199 |
200 | # Next.js build output
201 | .next
202 | out
203 |
204 | # Nuxt.js build / generate output
205 | .nuxt
206 | dist
207 |
208 | # Gatsby files
209 | .cache/
210 | # Comment in the public line in if your project uses Gatsby and not Next.js
211 | # https://nextjs.org/blog/next-9-1#public-directory-support
212 | # public
213 |
214 | # vuepress build output
215 | .vuepress/dist
216 |
217 | # Serverless directories
218 | .serverless/
219 |
220 | # FuseBox cache
221 | .fusebox/
222 |
223 | # DynamoDB Local files
224 | .dynamodb/
225 |
226 | # TernJS port file
227 | .tern-port
228 |
229 | # Stores VSCode versions used for testing VSCode extensions
230 | .vscode-test
231 |
232 | # yarn v2
233 | .yarn/cache
234 | .yarn/unplugged
235 | .yarn/build-state.yml
236 | .yarn/install-state.gz
237 | .pnp.*
238 |
--------------------------------------------------------------------------------
/ARG/84 - Keystone Upgrades.md:
--------------------------------------------------------------------------------
1 |
5 | # Keystone 6 Upgrade
6 |
7 | This course was recorded with a beta version of Keystone, since Keystone 6 has now launched in stable, there are a few minor updates to the app to get it working with the latest.
8 |
9 | The largest difference is that Keystone 6 now uses Prisma under the hood. Prisma is an "ORM", which provides a set of APIs to interface with the database of your choice. It works really well with GraphQL and TypeScript! This mostly doesn't matter to us, but there are a few API changes like `{ name_contains_i: $searchTerm }` is now `{ name: { contains: $searchTerm } }`
10 |
11 | ## Starter file Updates
12 |
13 | If you already have the files on your computer, go ahead and switch these out:
14 |
15 | 1. `package.json` needs to be updated with the one on github.
16 | * Delete `.keystone` and `node_modules` folder, along with the `package-lock.json` file
17 | * after you update `package.json`, run a `npm install` on the `backend` directory
18 | 1. `.gitignore` needs `*.db` added
19 | 2. `tsconfig.json` has some options, grab the latest from the [GitHub Repo](https://github.com/wesbos/Advanced-React)
20 | 3. `/seed-data/index.ts` is updated, get whole new file
21 | 4. `types.ts` is updated - get the new file
22 | 5. `compat.ts` needs to be added
23 |
24 | ## Sitewide Imports
25 | Find and Replace globally in your project
26 |
27 | * `@keystone-next/fields` → `@keystone-6/core`
28 | * `from '@keystone-next/keystone/schema'` → `from '@keystone-6/core/fields'`
29 | * `@keystone-next/cloudinary` → `@keystone-6/cloudinary`
30 | * `@keystone-next/auth` → `@keystone-6/auth`
31 | * `@keystone-next/keystone/session` → `@keystone-6/core/session`
32 | * `import { KeystoneContext, SessionStore } from '@keystone-next/types';` → `import { KeystoneContext} from '@keystone-6/core/types';`
33 | * `id: session.itemId` → `id: { equals: session!.itemId }`
34 | * `read: ` → `query: ` (keep the spaces in this one!)
35 | * `read: ` → `query: ` (keep the spaces in this one!)
36 | * `text({ isRequired: true })` → `text({ validation: { isRequired: true } })`
37 | * `status: 'AVAILABLE'` → `status: { equals: 'AVAILABLE' }`
38 |
39 | ## `keystone.ts` Setup File:
40 | The setup of this file has been re-recorded, but here are the steps to update your existing keystone:
41 |
42 | 1. Delete the createSchema import and delete where it wraps the `lists:` property.
43 | 1. Update the database url. If you have any DATABASE_URL in your `.env` file, delete it.
44 | ```js
45 | const databaseURL = process.env.DATABASE_URL || 'file:./app.db'
46 | ```
47 |
48 | 1. `adapter: 'mongoose',` is now `'provider': 'sqlite',`
49 | 1. `extendGraphqlSchema` is now like below. Make sure to import the `addCompatibilityForQueries` function.
50 |
51 | ```js
52 | // At the top of keystone.ts
53 | import { addCompatibilityForQueries } from './compat';
54 | // ... then lower down:
55 | extendGraphqlSchema: (schema) => addCompatibilityForQueries(extendGraphqlSchema(schema)),
56 | ```
57 |
58 | 1. the `onConnect` method for seeding data, replaced `keystone` param with `context` and passes `context.prisma`
59 |
60 | ```diff
61 | - async onConnect(context) {
62 | + async onConnect(context) {
63 | console.log('Connected to the database!');
64 | if (process.argv.includes('--seed-data')) {
65 | - await insertSeedData(keystone);
66 | + await insertSeedData(context.prisma);
67 | }
68 | },
69 | ```
70 |
71 | 3. Delete `withItemData` import and delete where it wrapped statelessSessions. Delete the second argument and move that to createAuth:
72 |
73 | ```js
74 | // ...
75 | // begin-highlight
76 | sessionData: `id name email role { ${permissionsList.join(' ')} }`,
77 | // end-highlight
78 | passwordResetLink: {
79 | // ...
80 | ```
81 |
82 | ## Access Control Updates
83 |
84 | Each of our schemas needs some slight updates to how access control works.
85 |
86 | `access` was previously `read`, `write`, `update`, `delete`. They are now split into:
87 |
88 | `access.operation` for Clear yes/no allowances.
89 |
90 | `access.filter` for filtering which items someone should have access to.
91 |
92 | #### schemas/CartItem.ts
93 |
94 | ```ts
95 | operation: {
96 | create: isSignedIn,
97 | },
98 | filter: {
99 | query: rules.canOrder,
100 | update: rules.canOrder,
101 | delete: rules.canOrder,
102 | },
103 | ```
104 |
105 | #### schemas/Order.ts
106 | ```ts
107 | operation: {
108 | create: isSignedIn,
109 | update: () => false,
110 | delete: () => false,
111 | },
112 | filter: {
113 | query: rules.canOrder,
114 | },
115 | ```
116 |
117 | #### schemas/OrderItem.ts
118 |
119 | ```ts
120 | operation: {
121 | create: isSignedIn,
122 | update: () => false,
123 | delete: () => false,
124 | },
125 | filter: {
126 | query: rules.canManageOrderItems,
127 | },
128 | ```
129 |
130 | #### schemas/Product.ts
131 |
132 | ```ts
133 | operation: {
134 | create: isSignedIn,
135 | },
136 | filter: {
137 | query: rules.canReadProducts,
138 | update: rules.canManageProducts,
139 | delete: rules.canManageProducts,
140 | },
141 | ```
142 |
143 | #### schemas/ProductImage.ts
144 |
145 | ```ts
146 | operation: {
147 | create: isSignedIn,
148 | query: () => true,
149 | update: permissions.canManageProducts,
150 | delete: permissions.canManageProducts,
151 | },
152 | ```
153 |
154 | #### schemas/Role.ts
155 |
156 | ```ts
157 | operation: {
158 | create: permissions.canManageRoles,
159 | query: permissions.canManageRoles,
160 | update: permissions.canManageRoles,
161 | delete: permissions.canManageRoles,
162 | },
163 | ```
164 |
165 | #### schemas/User.ts
166 |
167 | ```ts
168 | operation: {
169 | create: () => true,
170 | // only people with the permission can delete themselves!
171 | // You can't delete yourself
172 | delete: permissions.canManageUsers,
173 | },
174 | filter: {
175 | query: rules.canManageUsers,
176 | update: rules.canManageUsers,
177 | },
178 | ```
179 |
180 | ## Data Types
181 | `isRequired` is now under a validation object - this was part of our find/replace.
182 |
183 | `isIndexed: unique` now added to `User` email field:
184 |
185 | ```js
186 | email: text({ validation: { isRequired: true }, isIndexed: 'unique' }),
187 | ```
188 |
189 | ## Custom Virtual Fields are now different
190 | In your Order.ts model, it looks like this now. Make sure to import `graphql`
191 |
192 | ```js
193 | // at the top:
194 | import { list, graphql } from '@keystone-6/core';
195 | // then later down
196 | fields: {
197 | // highlight-start
198 | label: virtual({
199 | field: graphql.field({
200 | type: graphql.String,
201 | resolve(item) {
202 | return `${formatMoney(item.total)}`;
203 | },
204 | }),
205 | }),
206 | // highlight-end
207 | total: integer(),
208 | items: relationship({ ref: 'OrderItem.order', many: true }),
209 | user: relationship({ ref: 'User.orders' }),
210 | charge: text(),
211 | },
212 | ```
213 |
214 | ## addToCart.ts and checkout.ts
215 | These have a handful of smaller changes. You can view the diff on github, or just grab the latest. The whole video for these are re-recorded.
216 |
217 | ## Start It Up!
218 |
219 | That should be it. run `npm run dev`
220 |
221 | Open it in your browser.
222 |
223 |
224 | ## Database Switch
225 |
226 | Since we switched from Mongodb, over the sqlite, you will need to repopulate your data. run `npm run dev -- --seed-data` to populate all the seed data.
227 |
228 | A great app for visualizing your data is Table Plus.
229 |
230 | ## Frontend
231 |
232 | Most of the frontend is unaffected. Just a few minor updates.
233 |
234 |
235 |
236 | ### Search.js:
237 |
238 | ```diff
239 | - { name_contains_i: $searchTerm }
240 | - { description_contains_i: $searchTerm }
241 | + { name: { contains: $searchTerm } }
242 | + { description: { contains: { $searchTerm }} }
243 | ```
244 |
245 | There is also an issue with useLazyQuery right now, this will fix it:
246 |
247 | ```js
248 | function ClientOnly({ children, ...delegated }) {
249 | const [hasMounted, setHasMounted] = useState(false);
250 | useEffect(() => {
251 | setHasMounted(true);
252 | }, []);
253 | if (!hasMounted) {
254 | return null;
255 | }
256 | return
{children}
;
257 | }
258 | // then wrap Search
259 |
260 |
261 | ```
262 |
263 | ## Signin.js
264 |
265 | `UserAuthenticationWithPasswordFailure` no longer returns a `code`, remove it.
266 |
267 | ```diff
268 | ... on UserAuthenticationWithPasswordFailure {
269 | - code
270 | message
271 | }
272 | ```
273 |
274 |
275 | Unrelated, but we took the chance to upgrade Next.js. The updates here are:
276 |
277 | 1. Delete `.next`, `node_modules` and `package-lock.json`
278 | 2. Get the new `package.json` from github for the `frontend` folder.
279 | 3. Create a new file called `next.config.js` and use this config:
280 |
281 | ```js
282 | module.exports = {
283 | experimental: {
284 | // Enables the styled-components SWC transform
285 | styledComponents: true,
286 | },
287 | };
288 | ```
289 |
290 |
299 |
300 |
301 |
302 |
--------------------------------------------------------------------------------