├── .env.example ├── .gitignore ├── .markdownlint.json ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── backend ├── package-lock.json ├── package.json └── server.js ├── docs ├── Event_Description.md ├── Solution_server.js ├── Workshop_Steps.md ├── Workshop_Steps.pdf ├── Zoom_Chat.md └── img │ ├── Build_Screenshot.png │ ├── CORS.png │ ├── Kintone-App-Name.png │ ├── Kintone-Field-Codes.gif │ ├── PROJECT_DEMO_GIF.gif │ ├── banner.png │ ├── common_kintone │ ├── CreateApp-1.png │ ├── CreateApp-2.png │ ├── Kintone-Button-Edit.png │ ├── Kintone-View-Setting-Record-Count-HD.png │ ├── Kintone-View-Setting-Record-Count.png │ ├── KintoneApp_API_1.png │ ├── KintoneApp_API_2.png │ └── KintoneApp_URL.png │ ├── common_signup │ ├── SignUp-1.png │ ├── SignUp-2.png │ ├── SignUp-3.png │ └── SignUp-4.png │ ├── common_vscode │ ├── vscode-setting-extension-HD.png │ └── vscode-setting-extension.png │ └── main.png ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html └── src ├── App.css ├── App.js ├── components ├── cityPicker.js ├── countryPicker.js ├── spinner.js └── statePicker.js ├── index.js └── requests ├── getRecords.js └── postRecord.js /.env.example: -------------------------------------------------------------------------------- 1 | SUBDOMAIN = "example" 2 | APPID = "1" 3 | APITOKEN = "1J22qNAR54I4eiMcd0JmfDAavJNfNJDVaqt34X9A" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /backend/node_modules 6 | /.pnp 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | temp.* 12 | 13 | # production 14 | /build 15 | 16 | # misc 17 | .DS_Store 18 | .env 19 | .env.local 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD001": false, 3 | "MD002": false, 4 | "MD006": false, 5 | "MD009": { 6 | "br_spaces": 2 7 | }, 8 | "MD013": false, 9 | "MD014": false, 10 | "MD022": { 11 | "lines_below": 0 12 | }, 13 | "MD024": false, 14 | "MD026": false, 15 | "MD032": false, 16 | "MD033": { 17 | "allowed_elements": ["br", "pre", "ul", "li", "ol", "details", "summary"] 18 | }, 19 | "MD034": false, 20 | "MD036": false, 21 | "MD041": false, 22 | "MD051": false 23 | } 24 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "wayou.vscode-todo-highlight" 4 | ] 5 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[markdown]": { "editor.defaultFormatter": "yzhang.markdown-all-in-one" }, 3 | "cSpell.words": ["APITOKEN", "Kintone", "nodenv", "youtu.be"], 4 | "editor.tabSize": 2, 5 | "editor.wordWrap": "on", 6 | "markdown.extension.italic.indicator": "_", 7 | "markdown.extension.list.indentationSize": "inherit", 8 | "markdown.extension.toc.levels": "2..4", 9 | "markdown.extension.toc.unorderedList.marker": "*", 10 | "markdown.extension.toc.updateOnSave": false, 11 | "markdown.preview.fontFamily": "Fira Code", 12 | "[javascript]": { 13 | "editor.defaultFormatter": "vscode.typescript-language-features" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Kintone Developer Program 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Workshop - Build a React App Using Web Database ⚙️ 2 | 3 | --- 4 | 5 | ![banner.png](./docs/img/banner.png) 6 | 7 | Let's create a front-end React Component that exchanges the contents of a 3rd party Web Database service using Express as a proxy. 8 | 9 | ## Outline 10 | * [Completed Project](#completed-project) 11 | * [Get Started](#get-started) 12 | * [Terminal 1](#terminal-1) 13 | * [Terminal 2](#terminal-2) 14 | * [Get Your Free Kintone Database](#get-your-free-kintone-database) 15 | * [Workshop Steps](#workshop-steps) 16 | * [Debugging](#debugging) 17 | * [`npm install` command is not working](#npm-install-command-is-not-working) 18 | * [Errors related to .env](#errors-related-to-env) 19 | * [Errors related to Node.js \& npm](#errors-related-to-nodejs--npm) 20 | * [Express Server inside backend folder not working?](#express-server-inside-backend-folder-not-working) 21 | * [Not seeing a highlighted `TODO:`?](#not-seeing-a-highlighted-todo) 22 | * [Completed Code](#completed-code) 23 | * [Overview of the Repo](#overview-of-the-repo) 24 | 25 | ## Completed Project 26 | ![PROJECT_DEMO_GIF.gif](./docs/img/PROJECT_DEMO_GIF.gif) 27 | 28 | ## Get Started 29 | _Clone the Repo & Install Dependencies_ 💪 30 | 31 | First, clone the [kintone-workshops/React-x-REST-API-Workshop](https://github.com/kintone-workshops/React-x-REST-API-Workshop) repo! 🚀 32 | Then go inside the folders & install the dependencies! 33 | 34 | ⚡ Two terminal windows are required for this workshop. 35 | 36 | ### Terminal 1 37 | 38 | ```shell 39 | cd Downloads 40 | 41 | git clone https://github.com/kintone-workshops/React-x-REST-API-Workshop 42 | 43 | cd React-x-REST-API-Workshop 44 | 45 | npm install 46 | ``` 47 | 48 | ### Terminal 2 49 | 50 | ```shell 51 | cd Downloads/React-x-REST-API-Workshop 52 | 53 | cd backend && npm install 54 | ``` 55 | 56 | ### ⚠️ WARNING ⚠️ 57 | ⚡ **Node.js v18.16.1** or higher is required to run this workshop. 58 | (The current LTS version is recommended) 59 | 60 | For more information, refer to the [Guide on Installing Node.js & npm {macOS & Windows}](https://dev.to/kintonedevprogram/guide-on-installing-nodejs-npm-macos-windows-16ii). 61 | 62 | Open the `React-x-REST-API-Workshop` folder in [VS Code](https://code.visualstudio.com/docs/getstarted/tips-and-tricks#_command-line) as well: 63 | 64 | ```shell 65 | code . 66 | ``` 67 | 68 | ## Get Your Free Kintone Database 69 | 70 | [kintone.dev/new/](http://kintone.dev/new/) 71 | * ⚡ Only use lowercase, numbers, & hyphens in your subdomain 72 | * ⚠ Do not use uppercase or special characters 73 | 74 | | | | 75 | | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | 76 | | ![Step 1: Fill out the Kintone Developer license sign-up form](./docs/img/common_signup/SignUp-1.png) | ![Step 2: Email address will be the login name & the subdomain will be your unique link](./docs/img/common_signup/SignUp-2.png) | 77 | | ![Step 3: Check for a "Welcome to Kintone! One More Step To..." email](./docs/img/common_signup/SignUp-3.png) | ![Step 4: Log into Kintone](./docs/img/common_signup/SignUp-4.png) | 78 | 79 | For more information, check out the [Workshop_Steps.md > B. Get Your Free Kintone Database](./docs/Workshop_Steps.md#b-get-your-free-kintone-database) section! 80 | 81 | --- 82 | 83 | ## Workshop Steps 84 | 85 | 1. [A. Get started - clone the repo \& install dependencies](./docs/Workshop_Steps.md#a-get-started---clone-the-repo--install-dependencies) 86 | 1. [B. Get your free Kintone database](./docs/Workshop_Steps.md#b-get-your-free-kintone-database) 87 | 1. [C. Create a `.env` file](./docs/Workshop_Steps.md#c-create-a-env-file) 88 | 1. [D. Create a Kintone web database app](./docs/Workshop_Steps.md#d-create-a-kintone-web-database-app) 89 | 1. [E. Generate an API token for the Kintone app](./docs/Workshop_Steps.md#e-generate-an-api-token-for-the-kintone-app) 90 | 1. [H. Edit server.js](./docs/Workshop_Steps.md#h-edit-serverjs) 91 | 1. [I. Start the servers](./docs/Workshop_Steps.md#i-start-the-servers) 92 | 93 | --- 94 | 95 | --- 96 | 97 | ## Debugging 98 | **Let's Fix Those Problems** 💪 99 | 100 | Here is a rundown of common problems that may occur & their solutions! 101 | 102 | ### `npm install` command is not working 103 | 104 | 1. Verify the Node.js & npm versions **inside** the `React-x-REST-API-Workshop` folder 105 | 2. Just installed Node.js? Verify you configured Node.js versions **inside** the `React-x-REST-API-Workshop` folder 106 | 107 | * Mac:`nodenv install 18.16.1 && nodenv local 18.16.1` 108 | * Windows: `nvm install 18.16.1 && nvm use 18.16.1` 109 | 110 | Not the correct versions, or confused? 🤔 → Check out the [Guide on Installing Node.js & npm {macOS & Windows}](https://dev.to/kintonedevprogram/guide-on-installing-nodejs-npm-macos-windows-16ii). 111 | 112 | ### Errors related to .env 113 | 114 | If you get one of the following error messages: 115 | 116 | * `[webpack-cli] Error: Missing environment variable: KINTONE_BASE_URL` 117 | * `[webpack-cli] Error: Missing environment variable: KINTONE_PASSWORD` 118 | * `[webpack-cli] Error: Missing environment variable: KINTONE_USERNAME` 119 | * `[webpack-cli] Error: Missing environment variable: VIEW_ID` 120 | * `[webpack-cli] TypeError: Cannot convert undefined or null to object` 121 | * `Failed to find .env file at default paths: [./.env,./.env.js,./.env.json]` 122 | * `Failed to find .env file at default paths: [./.env,./.env.js,./.env.json]` 123 | * `Failed to upload JavaScript/CSS files` 124 | * `KintoneRestAPIError: [520] [CB_WA01] Password authentication failed...` 125 | 126 | Then please verify that 127 | * your `.env` file has been correctly configured 128 | * your username and password for your Kintone account are correct 129 | * you have not modified the `.env.example` 130 | 131 | ### Errors related to Node.js & npm 132 | 133 | Error Message: 134 | 135 | ```shell 136 | ❯ npm run start 137 | 138 | > react-x-rest-api-workshop@1.0.0 start 139 | > react-scripts start 140 | 141 | sh: react-scripts: command not found 142 | ``` 143 | 144 | Solution: 145 | 146 | ```shell 147 | cd React-x-REST-API-Workshop 148 | npm install 149 | ``` 150 | 151 | ### Express Server inside backend folder not working? 152 | 153 | Inside `backend` folder and trying to execute `npm run start` command 154 | 155 | Error Message: 156 | 157 | ```shell 158 | > backend@1.0.0 start 159 | > nodemon --watch .env --watch ../frontend server.js 160 | 161 | [nodemon] 2.0.22 162 | [nodemon] to restart at any time, enter `rs` 163 | [nodemon] watching path(s): .env ../frontend 164 | [nodemon] watching extensions: js,mjs,json 165 | [nodemon] starting `node server.js` 166 | node:events:491 167 | throw er; // Unhandled 'error' event 168 | ^ 169 | 170 | Error: listen EADDRINUSE: address already in use :::50000 171 | at Server.setupListenHandle [as _listen2] (node:net:1740:16) 172 | at listenInCluster (node:net:1788:12) 173 | at Server.listen (node:net:1876:7) 174 | at Function.listen (/Users/username/Downloads/React-x-REST-API-Workshop/backend/node_modules/express/lib/application.js:635:24) 175 | at Object. (/Users/username/Downloads/React-x-REST-API-Workshop/backend/server.js:78:5) 176 | at Module._compile (node:internal/modules/cjs/loader:1254:14) 177 | at Module._extensions..js (node:internal/modules/cjs/loader:1308:10) 178 | at Module.load (node:internal/modules/cjs/loader:1117:32) 179 | at Module._load (node:internal/modules/cjs/loader:958:12) 180 | at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) 181 | Emitted 'error' event on Server instance at: 182 | at emitErrorNT (node:net:1767:8) 183 | at process.processTicksAndRejections (node:internal/process/task_queues:82:21) { 184 | code: 'EADDRINUSE', 185 | errno: -48, 186 | syscall: 'listen', 187 | address: '::', 188 | port: 50000 189 | } 190 | 191 | Node.js v18.16.1 192 | [nodemon] app crashed - waiting for file changes before starting... 193 | ``` 194 | 195 | Solution: 196 | The important line is `Error: listen EADDRINUSE: address already in use :::50000`. 197 | This means that the port 50000 is already in use. 198 | 199 | Restart the terminal and try again. 200 | 201 | If the error persists, let's kill the process that is using port 50000 manually. 202 | 203 | ```shell 204 | # Find the process that is using port 50000 205 | lsof -i tcp:50000 206 | # Kill the process 207 | kill -9 208 | ``` 209 | 210 | For more information, refer to the [How to kill server when seeing "EADDRINUSE: address already in use" post by B. Chen](https://levelup.gitconnected.com/how-to-kill-server-when-seeing-eaddrinuse-address-already-in-use-16c4c4d7fe5d). 211 | 212 | ### Not seeing a highlighted `TODO:`? 213 | Click the `Install` button on the VS Code pop-up message to install [TODO Highlight extension](https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight). 214 | * [![vscode-setting-extension.png](./docs/img/common_vscode/vscode-setting-extension.png)](./docs/img/common_vscode/vscode-setting-extension-HD.png) 215 | 216 | --- 217 | 218 | ## Completed Code 219 | If you want the completed code for the index.js file, you can find it here: 220 | [Solution_server.js](./docs/Solution_server.js) 221 | 222 | --- 223 | 224 | ## Overview of the Repo 225 | 226 |
227 | ↯ Overview of the Repo ↯ 228 | 229 | | File | Purpose | Need to Modify? | 230 | | -------------------------------------------------- | ------------------------------------------------------------------------- | ---------------------- | 231 | | [package.json](package.json) | Project's metadata & scripts for building and uploading the customization | | 232 | | [.env.example](.env.example) | The template for the .env file | | 233 | | [.env](.env) | Holds the Kintone login credential and View ID | Yes! - Create it | 234 | | | | | 235 | | [./backend/server.js](./backend/server.js) | Express server that handles the Kintone API requests | Yes! Complete the code | 236 | | | | | 237 | | [docs/Workshop_Steps.md](./docs/Workshop_Steps.md) | Step-by-step guide that we do during the workshop | | 238 | 239 |
240 | -------------------------------------------------------------------------------- /backend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "backend", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "cors": "^2.8.5", 13 | "dotenv": "^10.0.0", 14 | "express": "^4.18.2", 15 | "nodemon": "^2.0.12" 16 | } 17 | }, 18 | "node_modules/abbrev": { 19 | "version": "1.1.1", 20 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 21 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" 22 | }, 23 | "node_modules/accepts": { 24 | "version": "1.3.8", 25 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 26 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 27 | "dependencies": { 28 | "mime-types": "~2.1.34", 29 | "negotiator": "0.6.3" 30 | }, 31 | "engines": { 32 | "node": ">= 0.6" 33 | } 34 | }, 35 | "node_modules/anymatch": { 36 | "version": "3.1.3", 37 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 38 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 39 | "dependencies": { 40 | "normalize-path": "^3.0.0", 41 | "picomatch": "^2.0.4" 42 | }, 43 | "engines": { 44 | "node": ">= 8" 45 | } 46 | }, 47 | "node_modules/array-flatten": { 48 | "version": "1.1.1", 49 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 50 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 51 | }, 52 | "node_modules/balanced-match": { 53 | "version": "1.0.2", 54 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 55 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 56 | }, 57 | "node_modules/binary-extensions": { 58 | "version": "2.2.0", 59 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 60 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 61 | "engines": { 62 | "node": ">=8" 63 | } 64 | }, 65 | "node_modules/body-parser": { 66 | "version": "1.20.1", 67 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 68 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 69 | "dependencies": { 70 | "bytes": "3.1.2", 71 | "content-type": "~1.0.4", 72 | "debug": "2.6.9", 73 | "depd": "2.0.0", 74 | "destroy": "1.2.0", 75 | "http-errors": "2.0.0", 76 | "iconv-lite": "0.4.24", 77 | "on-finished": "2.4.1", 78 | "qs": "6.11.0", 79 | "raw-body": "2.5.1", 80 | "type-is": "~1.6.18", 81 | "unpipe": "1.0.0" 82 | }, 83 | "engines": { 84 | "node": ">= 0.8", 85 | "npm": "1.2.8000 || >= 1.4.16" 86 | } 87 | }, 88 | "node_modules/brace-expansion": { 89 | "version": "1.1.11", 90 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 91 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 92 | "dependencies": { 93 | "balanced-match": "^1.0.0", 94 | "concat-map": "0.0.1" 95 | } 96 | }, 97 | "node_modules/braces": { 98 | "version": "3.0.2", 99 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 100 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 101 | "dependencies": { 102 | "fill-range": "^7.0.1" 103 | }, 104 | "engines": { 105 | "node": ">=8" 106 | } 107 | }, 108 | "node_modules/bytes": { 109 | "version": "3.1.2", 110 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 111 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 112 | "engines": { 113 | "node": ">= 0.8" 114 | } 115 | }, 116 | "node_modules/call-bind": { 117 | "version": "1.0.2", 118 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 119 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 120 | "dependencies": { 121 | "function-bind": "^1.1.1", 122 | "get-intrinsic": "^1.0.2" 123 | }, 124 | "funding": { 125 | "url": "https://github.com/sponsors/ljharb" 126 | } 127 | }, 128 | "node_modules/chokidar": { 129 | "version": "3.5.3", 130 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 131 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 132 | "funding": [ 133 | { 134 | "type": "individual", 135 | "url": "https://paulmillr.com/funding/" 136 | } 137 | ], 138 | "dependencies": { 139 | "anymatch": "~3.1.2", 140 | "braces": "~3.0.2", 141 | "glob-parent": "~5.1.2", 142 | "is-binary-path": "~2.1.0", 143 | "is-glob": "~4.0.1", 144 | "normalize-path": "~3.0.0", 145 | "readdirp": "~3.6.0" 146 | }, 147 | "engines": { 148 | "node": ">= 8.10.0" 149 | }, 150 | "optionalDependencies": { 151 | "fsevents": "~2.3.2" 152 | } 153 | }, 154 | "node_modules/concat-map": { 155 | "version": "0.0.1", 156 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 157 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" 158 | }, 159 | "node_modules/content-disposition": { 160 | "version": "0.5.4", 161 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 162 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 163 | "dependencies": { 164 | "safe-buffer": "5.2.1" 165 | }, 166 | "engines": { 167 | "node": ">= 0.6" 168 | } 169 | }, 170 | "node_modules/content-type": { 171 | "version": "1.0.5", 172 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 173 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 174 | "engines": { 175 | "node": ">= 0.6" 176 | } 177 | }, 178 | "node_modules/cookie": { 179 | "version": "0.5.0", 180 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 181 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 182 | "engines": { 183 | "node": ">= 0.6" 184 | } 185 | }, 186 | "node_modules/cookie-signature": { 187 | "version": "1.0.6", 188 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 189 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 190 | }, 191 | "node_modules/cors": { 192 | "version": "2.8.5", 193 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 194 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 195 | "dependencies": { 196 | "object-assign": "^4", 197 | "vary": "^1" 198 | }, 199 | "engines": { 200 | "node": ">= 0.10" 201 | } 202 | }, 203 | "node_modules/debug": { 204 | "version": "2.6.9", 205 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 206 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 207 | "dependencies": { 208 | "ms": "2.0.0" 209 | } 210 | }, 211 | "node_modules/depd": { 212 | "version": "2.0.0", 213 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 214 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 215 | "engines": { 216 | "node": ">= 0.8" 217 | } 218 | }, 219 | "node_modules/destroy": { 220 | "version": "1.2.0", 221 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 222 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 223 | "engines": { 224 | "node": ">= 0.8", 225 | "npm": "1.2.8000 || >= 1.4.16" 226 | } 227 | }, 228 | "node_modules/dotenv": { 229 | "version": "10.0.0", 230 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", 231 | "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", 232 | "engines": { 233 | "node": ">=10" 234 | } 235 | }, 236 | "node_modules/ee-first": { 237 | "version": "1.1.1", 238 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 239 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 240 | }, 241 | "node_modules/encodeurl": { 242 | "version": "1.0.2", 243 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 244 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 245 | "engines": { 246 | "node": ">= 0.8" 247 | } 248 | }, 249 | "node_modules/escape-html": { 250 | "version": "1.0.3", 251 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 252 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 253 | }, 254 | "node_modules/etag": { 255 | "version": "1.8.1", 256 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 257 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 258 | "engines": { 259 | "node": ">= 0.6" 260 | } 261 | }, 262 | "node_modules/express": { 263 | "version": "4.18.2", 264 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 265 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 266 | "dependencies": { 267 | "accepts": "~1.3.8", 268 | "array-flatten": "1.1.1", 269 | "body-parser": "1.20.1", 270 | "content-disposition": "0.5.4", 271 | "content-type": "~1.0.4", 272 | "cookie": "0.5.0", 273 | "cookie-signature": "1.0.6", 274 | "debug": "2.6.9", 275 | "depd": "2.0.0", 276 | "encodeurl": "~1.0.2", 277 | "escape-html": "~1.0.3", 278 | "etag": "~1.8.1", 279 | "finalhandler": "1.2.0", 280 | "fresh": "0.5.2", 281 | "http-errors": "2.0.0", 282 | "merge-descriptors": "1.0.1", 283 | "methods": "~1.1.2", 284 | "on-finished": "2.4.1", 285 | "parseurl": "~1.3.3", 286 | "path-to-regexp": "0.1.7", 287 | "proxy-addr": "~2.0.7", 288 | "qs": "6.11.0", 289 | "range-parser": "~1.2.1", 290 | "safe-buffer": "5.2.1", 291 | "send": "0.18.0", 292 | "serve-static": "1.15.0", 293 | "setprototypeof": "1.2.0", 294 | "statuses": "2.0.1", 295 | "type-is": "~1.6.18", 296 | "utils-merge": "1.0.1", 297 | "vary": "~1.1.2" 298 | }, 299 | "engines": { 300 | "node": ">= 0.10.0" 301 | } 302 | }, 303 | "node_modules/fill-range": { 304 | "version": "7.0.1", 305 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 306 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 307 | "dependencies": { 308 | "to-regex-range": "^5.0.1" 309 | }, 310 | "engines": { 311 | "node": ">=8" 312 | } 313 | }, 314 | "node_modules/finalhandler": { 315 | "version": "1.2.0", 316 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 317 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 318 | "dependencies": { 319 | "debug": "2.6.9", 320 | "encodeurl": "~1.0.2", 321 | "escape-html": "~1.0.3", 322 | "on-finished": "2.4.1", 323 | "parseurl": "~1.3.3", 324 | "statuses": "2.0.1", 325 | "unpipe": "~1.0.0" 326 | }, 327 | "engines": { 328 | "node": ">= 0.8" 329 | } 330 | }, 331 | "node_modules/forwarded": { 332 | "version": "0.2.0", 333 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 334 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 335 | "engines": { 336 | "node": ">= 0.6" 337 | } 338 | }, 339 | "node_modules/fresh": { 340 | "version": "0.5.2", 341 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 342 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 343 | "engines": { 344 | "node": ">= 0.6" 345 | } 346 | }, 347 | "node_modules/fsevents": { 348 | "version": "2.3.2", 349 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 350 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 351 | "hasInstallScript": true, 352 | "optional": true, 353 | "os": [ 354 | "darwin" 355 | ], 356 | "engines": { 357 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 358 | } 359 | }, 360 | "node_modules/function-bind": { 361 | "version": "1.1.1", 362 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 363 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 364 | }, 365 | "node_modules/get-intrinsic": { 366 | "version": "1.2.1", 367 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", 368 | "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", 369 | "dependencies": { 370 | "function-bind": "^1.1.1", 371 | "has": "^1.0.3", 372 | "has-proto": "^1.0.1", 373 | "has-symbols": "^1.0.3" 374 | }, 375 | "funding": { 376 | "url": "https://github.com/sponsors/ljharb" 377 | } 378 | }, 379 | "node_modules/glob-parent": { 380 | "version": "5.1.2", 381 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 382 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 383 | "dependencies": { 384 | "is-glob": "^4.0.1" 385 | }, 386 | "engines": { 387 | "node": ">= 6" 388 | } 389 | }, 390 | "node_modules/has": { 391 | "version": "1.0.3", 392 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 393 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 394 | "dependencies": { 395 | "function-bind": "^1.1.1" 396 | }, 397 | "engines": { 398 | "node": ">= 0.4.0" 399 | } 400 | }, 401 | "node_modules/has-flag": { 402 | "version": "3.0.0", 403 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 404 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 405 | "engines": { 406 | "node": ">=4" 407 | } 408 | }, 409 | "node_modules/has-proto": { 410 | "version": "1.0.1", 411 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", 412 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", 413 | "engines": { 414 | "node": ">= 0.4" 415 | }, 416 | "funding": { 417 | "url": "https://github.com/sponsors/ljharb" 418 | } 419 | }, 420 | "node_modules/has-symbols": { 421 | "version": "1.0.3", 422 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 423 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 424 | "engines": { 425 | "node": ">= 0.4" 426 | }, 427 | "funding": { 428 | "url": "https://github.com/sponsors/ljharb" 429 | } 430 | }, 431 | "node_modules/http-errors": { 432 | "version": "2.0.0", 433 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 434 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 435 | "dependencies": { 436 | "depd": "2.0.0", 437 | "inherits": "2.0.4", 438 | "setprototypeof": "1.2.0", 439 | "statuses": "2.0.1", 440 | "toidentifier": "1.0.1" 441 | }, 442 | "engines": { 443 | "node": ">= 0.8" 444 | } 445 | }, 446 | "node_modules/iconv-lite": { 447 | "version": "0.4.24", 448 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 449 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 450 | "dependencies": { 451 | "safer-buffer": ">= 2.1.2 < 3" 452 | }, 453 | "engines": { 454 | "node": ">=0.10.0" 455 | } 456 | }, 457 | "node_modules/ignore-by-default": { 458 | "version": "1.0.1", 459 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 460 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" 461 | }, 462 | "node_modules/inherits": { 463 | "version": "2.0.4", 464 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 465 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 466 | }, 467 | "node_modules/ipaddr.js": { 468 | "version": "1.9.1", 469 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 470 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 471 | "engines": { 472 | "node": ">= 0.10" 473 | } 474 | }, 475 | "node_modules/is-binary-path": { 476 | "version": "2.1.0", 477 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 478 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 479 | "dependencies": { 480 | "binary-extensions": "^2.0.0" 481 | }, 482 | "engines": { 483 | "node": ">=8" 484 | } 485 | }, 486 | "node_modules/is-extglob": { 487 | "version": "2.1.1", 488 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 489 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 490 | "engines": { 491 | "node": ">=0.10.0" 492 | } 493 | }, 494 | "node_modules/is-glob": { 495 | "version": "4.0.3", 496 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 497 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 498 | "dependencies": { 499 | "is-extglob": "^2.1.1" 500 | }, 501 | "engines": { 502 | "node": ">=0.10.0" 503 | } 504 | }, 505 | "node_modules/is-number": { 506 | "version": "7.0.0", 507 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 508 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 509 | "engines": { 510 | "node": ">=0.12.0" 511 | } 512 | }, 513 | "node_modules/media-typer": { 514 | "version": "0.3.0", 515 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 516 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 517 | "engines": { 518 | "node": ">= 0.6" 519 | } 520 | }, 521 | "node_modules/merge-descriptors": { 522 | "version": "1.0.1", 523 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 524 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 525 | }, 526 | "node_modules/methods": { 527 | "version": "1.1.2", 528 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 529 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 530 | "engines": { 531 | "node": ">= 0.6" 532 | } 533 | }, 534 | "node_modules/mime": { 535 | "version": "1.6.0", 536 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 537 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 538 | "bin": { 539 | "mime": "cli.js" 540 | }, 541 | "engines": { 542 | "node": ">=4" 543 | } 544 | }, 545 | "node_modules/mime-db": { 546 | "version": "1.52.0", 547 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 548 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 549 | "engines": { 550 | "node": ">= 0.6" 551 | } 552 | }, 553 | "node_modules/mime-types": { 554 | "version": "2.1.35", 555 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 556 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 557 | "dependencies": { 558 | "mime-db": "1.52.0" 559 | }, 560 | "engines": { 561 | "node": ">= 0.6" 562 | } 563 | }, 564 | "node_modules/minimatch": { 565 | "version": "3.1.2", 566 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 567 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 568 | "dependencies": { 569 | "brace-expansion": "^1.1.7" 570 | }, 571 | "engines": { 572 | "node": "*" 573 | } 574 | }, 575 | "node_modules/ms": { 576 | "version": "2.0.0", 577 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 578 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 579 | }, 580 | "node_modules/negotiator": { 581 | "version": "0.6.3", 582 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 583 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 584 | "engines": { 585 | "node": ">= 0.6" 586 | } 587 | }, 588 | "node_modules/nodemon": { 589 | "version": "2.0.22", 590 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", 591 | "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", 592 | "dependencies": { 593 | "chokidar": "^3.5.2", 594 | "debug": "^3.2.7", 595 | "ignore-by-default": "^1.0.1", 596 | "minimatch": "^3.1.2", 597 | "pstree.remy": "^1.1.8", 598 | "semver": "^5.7.1", 599 | "simple-update-notifier": "^1.0.7", 600 | "supports-color": "^5.5.0", 601 | "touch": "^3.1.0", 602 | "undefsafe": "^2.0.5" 603 | }, 604 | "bin": { 605 | "nodemon": "bin/nodemon.js" 606 | }, 607 | "engines": { 608 | "node": ">=8.10.0" 609 | }, 610 | "funding": { 611 | "type": "opencollective", 612 | "url": "https://opencollective.com/nodemon" 613 | } 614 | }, 615 | "node_modules/nodemon/node_modules/debug": { 616 | "version": "3.2.7", 617 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 618 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 619 | "dependencies": { 620 | "ms": "^2.1.1" 621 | } 622 | }, 623 | "node_modules/nodemon/node_modules/ms": { 624 | "version": "2.1.3", 625 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 626 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 627 | }, 628 | "node_modules/nopt": { 629 | "version": "1.0.10", 630 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 631 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", 632 | "dependencies": { 633 | "abbrev": "1" 634 | }, 635 | "bin": { 636 | "nopt": "bin/nopt.js" 637 | }, 638 | "engines": { 639 | "node": "*" 640 | } 641 | }, 642 | "node_modules/normalize-path": { 643 | "version": "3.0.0", 644 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 645 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 646 | "engines": { 647 | "node": ">=0.10.0" 648 | } 649 | }, 650 | "node_modules/object-assign": { 651 | "version": "4.1.1", 652 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 653 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 654 | "engines": { 655 | "node": ">=0.10.0" 656 | } 657 | }, 658 | "node_modules/object-inspect": { 659 | "version": "1.12.3", 660 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", 661 | "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", 662 | "funding": { 663 | "url": "https://github.com/sponsors/ljharb" 664 | } 665 | }, 666 | "node_modules/on-finished": { 667 | "version": "2.4.1", 668 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 669 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 670 | "dependencies": { 671 | "ee-first": "1.1.1" 672 | }, 673 | "engines": { 674 | "node": ">= 0.8" 675 | } 676 | }, 677 | "node_modules/parseurl": { 678 | "version": "1.3.3", 679 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 680 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 681 | "engines": { 682 | "node": ">= 0.8" 683 | } 684 | }, 685 | "node_modules/path-to-regexp": { 686 | "version": "0.1.7", 687 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 688 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 689 | }, 690 | "node_modules/picomatch": { 691 | "version": "2.3.1", 692 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 693 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 694 | "engines": { 695 | "node": ">=8.6" 696 | }, 697 | "funding": { 698 | "url": "https://github.com/sponsors/jonschlinkert" 699 | } 700 | }, 701 | "node_modules/proxy-addr": { 702 | "version": "2.0.7", 703 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 704 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 705 | "dependencies": { 706 | "forwarded": "0.2.0", 707 | "ipaddr.js": "1.9.1" 708 | }, 709 | "engines": { 710 | "node": ">= 0.10" 711 | } 712 | }, 713 | "node_modules/pstree.remy": { 714 | "version": "1.1.8", 715 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 716 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" 717 | }, 718 | "node_modules/qs": { 719 | "version": "6.11.0", 720 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 721 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 722 | "dependencies": { 723 | "side-channel": "^1.0.4" 724 | }, 725 | "engines": { 726 | "node": ">=0.6" 727 | }, 728 | "funding": { 729 | "url": "https://github.com/sponsors/ljharb" 730 | } 731 | }, 732 | "node_modules/range-parser": { 733 | "version": "1.2.1", 734 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 735 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 736 | "engines": { 737 | "node": ">= 0.6" 738 | } 739 | }, 740 | "node_modules/raw-body": { 741 | "version": "2.5.1", 742 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 743 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 744 | "dependencies": { 745 | "bytes": "3.1.2", 746 | "http-errors": "2.0.0", 747 | "iconv-lite": "0.4.24", 748 | "unpipe": "1.0.0" 749 | }, 750 | "engines": { 751 | "node": ">= 0.8" 752 | } 753 | }, 754 | "node_modules/readdirp": { 755 | "version": "3.6.0", 756 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 757 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 758 | "dependencies": { 759 | "picomatch": "^2.2.1" 760 | }, 761 | "engines": { 762 | "node": ">=8.10.0" 763 | } 764 | }, 765 | "node_modules/safe-buffer": { 766 | "version": "5.2.1", 767 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 768 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 769 | "funding": [ 770 | { 771 | "type": "github", 772 | "url": "https://github.com/sponsors/feross" 773 | }, 774 | { 775 | "type": "patreon", 776 | "url": "https://www.patreon.com/feross" 777 | }, 778 | { 779 | "type": "consulting", 780 | "url": "https://feross.org/support" 781 | } 782 | ] 783 | }, 784 | "node_modules/safer-buffer": { 785 | "version": "2.1.2", 786 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 787 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 788 | }, 789 | "node_modules/semver": { 790 | "version": "5.7.1", 791 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 792 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 793 | "bin": { 794 | "semver": "bin/semver" 795 | } 796 | }, 797 | "node_modules/send": { 798 | "version": "0.18.0", 799 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 800 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 801 | "dependencies": { 802 | "debug": "2.6.9", 803 | "depd": "2.0.0", 804 | "destroy": "1.2.0", 805 | "encodeurl": "~1.0.2", 806 | "escape-html": "~1.0.3", 807 | "etag": "~1.8.1", 808 | "fresh": "0.5.2", 809 | "http-errors": "2.0.0", 810 | "mime": "1.6.0", 811 | "ms": "2.1.3", 812 | "on-finished": "2.4.1", 813 | "range-parser": "~1.2.1", 814 | "statuses": "2.0.1" 815 | }, 816 | "engines": { 817 | "node": ">= 0.8.0" 818 | } 819 | }, 820 | "node_modules/send/node_modules/ms": { 821 | "version": "2.1.3", 822 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 823 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 824 | }, 825 | "node_modules/serve-static": { 826 | "version": "1.15.0", 827 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 828 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 829 | "dependencies": { 830 | "encodeurl": "~1.0.2", 831 | "escape-html": "~1.0.3", 832 | "parseurl": "~1.3.3", 833 | "send": "0.18.0" 834 | }, 835 | "engines": { 836 | "node": ">= 0.8.0" 837 | } 838 | }, 839 | "node_modules/setprototypeof": { 840 | "version": "1.2.0", 841 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 842 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 843 | }, 844 | "node_modules/side-channel": { 845 | "version": "1.0.4", 846 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 847 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 848 | "dependencies": { 849 | "call-bind": "^1.0.0", 850 | "get-intrinsic": "^1.0.2", 851 | "object-inspect": "^1.9.0" 852 | }, 853 | "funding": { 854 | "url": "https://github.com/sponsors/ljharb" 855 | } 856 | }, 857 | "node_modules/simple-update-notifier": { 858 | "version": "1.1.0", 859 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", 860 | "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", 861 | "dependencies": { 862 | "semver": "~7.0.0" 863 | }, 864 | "engines": { 865 | "node": ">=8.10.0" 866 | } 867 | }, 868 | "node_modules/simple-update-notifier/node_modules/semver": { 869 | "version": "7.0.0", 870 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", 871 | "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", 872 | "bin": { 873 | "semver": "bin/semver.js" 874 | } 875 | }, 876 | "node_modules/statuses": { 877 | "version": "2.0.1", 878 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 879 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 880 | "engines": { 881 | "node": ">= 0.8" 882 | } 883 | }, 884 | "node_modules/supports-color": { 885 | "version": "5.5.0", 886 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 887 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 888 | "dependencies": { 889 | "has-flag": "^3.0.0" 890 | }, 891 | "engines": { 892 | "node": ">=4" 893 | } 894 | }, 895 | "node_modules/to-regex-range": { 896 | "version": "5.0.1", 897 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 898 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 899 | "dependencies": { 900 | "is-number": "^7.0.0" 901 | }, 902 | "engines": { 903 | "node": ">=8.0" 904 | } 905 | }, 906 | "node_modules/toidentifier": { 907 | "version": "1.0.1", 908 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 909 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 910 | "engines": { 911 | "node": ">=0.6" 912 | } 913 | }, 914 | "node_modules/touch": { 915 | "version": "3.1.0", 916 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 917 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 918 | "dependencies": { 919 | "nopt": "~1.0.10" 920 | }, 921 | "bin": { 922 | "nodetouch": "bin/nodetouch.js" 923 | } 924 | }, 925 | "node_modules/type-is": { 926 | "version": "1.6.18", 927 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 928 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 929 | "dependencies": { 930 | "media-typer": "0.3.0", 931 | "mime-types": "~2.1.24" 932 | }, 933 | "engines": { 934 | "node": ">= 0.6" 935 | } 936 | }, 937 | "node_modules/undefsafe": { 938 | "version": "2.0.5", 939 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", 940 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" 941 | }, 942 | "node_modules/unpipe": { 943 | "version": "1.0.0", 944 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 945 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 946 | "engines": { 947 | "node": ">= 0.8" 948 | } 949 | }, 950 | "node_modules/utils-merge": { 951 | "version": "1.0.1", 952 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 953 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 954 | "engines": { 955 | "node": ">= 0.4.0" 956 | } 957 | }, 958 | "node_modules/vary": { 959 | "version": "1.1.2", 960 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 961 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 962 | "engines": { 963 | "node": ">= 0.8" 964 | } 965 | } 966 | } 967 | } 968 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "Express server that makes the Kintone API calls", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon --watch .env --watch ../frontend server.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cors": "^2.8.5", 14 | "dotenv": "^10.0.0", 15 | "express": "^4.18.2", 16 | "nodemon": "^2.0.12" 17 | } 18 | } -------------------------------------------------------------------------------- /backend/server.js: -------------------------------------------------------------------------------- 1 | // backend - server.js - Routes API requests from the frontend to Kintone 2 | 3 | // Express Server Setup 4 | const express = require('express'); 5 | const cors = require('cors'); 6 | const PORT = 50000; 7 | const app = express(); 8 | 9 | // Hide sensitive info in a .env file with dotenv 10 | require('dotenv').config({ path: '../.env' }); 11 | 12 | // Get Kintone credentials from a .env file 13 | const subdomain = process.env.SUBDOMAIN; 14 | const appID = process.env.APPID; 15 | const apiToken = process.env.APITOKEN; 16 | 17 | // Parse incoming requests with JSON payloads 18 | app.use(express.json()); 19 | 20 | // Set Cross-Origin Resource Sharing (CORS) to frontend React App 21 | app.use(cors()); 22 | const corsOptions = { 23 | origin: 'http://localhost:3000' 24 | }; 25 | 26 | // Kintone's record(s) endpoints 27 | const multipleRecordsEndpoint = `https://${subdomain}.kintone.com/k/v1/records.json?app=${appID}` 28 | const singleRecordEndpoint = `https://${subdomain}.kintone.com/k/v1/record.json?app=${appID}`; 29 | 30 | // Kintone app's field codes are 'country' 'state' and 'city'. 31 | 32 | // TODO: Create a GET endpoint at /getData 33 | 34 | // TODO: Create a POST endpoint at /postData 35 | 36 | app.listen(PORT, () => { 37 | console.log(`\n Backend server listening at http://localhost:${PORT} \n Confirm if Kintone records are being retrieved at \n http://localhost:${PORT}/getData`); 38 | }); -------------------------------------------------------------------------------- /docs/Event_Description.md: -------------------------------------------------------------------------------- 1 | # JavaScript Workshop - Build a React App Using Web Database 2 | 3 | Let's create a front-end React Component that exchanges the contents of a 3rd party Web Database service using Express as a proxy. 4 | 5 | ## ABOUT THIS EVENT 6 | 7 | In this 2 hour workshop, you'll walk away with a React project that retrieves data from and uploads data to Kintone, a web database service. 8 | 9 | We'll walk you through the basics of REST API calls and CORS, usage of State and Effect Hooks, setting up an Express back-end, and using it as a proxy. 10 | 11 | --- 12 | 13 | ## 📎 PREREQUISITE 14 | 15 | ### 🤖 CLONE THE WORKSHOP REPOSITORY 16 | 17 | This is the codebase that we will start the workshop from! 18 | * [bit.ly/react-x-rest](https://bit.ly/react-x-rest) 19 | 20 | ### 📂 GET A KINTONE SUBDOMAIN (DATABASE) 21 | 22 | Apply for a free developer license and subdomain. You can also read up on all things Kintone API & customization! 23 | * [Kintone.dev/new](http://kintone.dev/new/) 24 | 25 | ### 💾 INSTALL NODE & NPM 26 | 27 | Verify that you have the latest Node.js & npm installed on your computer. 28 | If you don't have Node.js & npm installed, refer to the [Guide on Installing Node.js & npm {macOS & Windows}](https://dev.to/kintonedevprogram/guide-on-installing-nodejs-npm-macos-windows-16ii) post for instructions. 29 | 30 | ## 🕒 EVENT SCHEDULE (IN PACIFIC TIME) 31 | 32 | * 6:00 PM - Hello 33 | * 6:10 PM - Workshop Overview 34 | * 6:20 PM - Web Database Setup 35 | * 6:50 PM - React Project Setup 36 | * 7:00 PM - Build the React App 37 | * 7:40 PM - Connect the App to the Web Database 38 | * 7:50 PM - Wrap Up and Q&A 39 | * 8:00 PM - Thank you & Survey Raffle 40 | 41 | ## 📚 SUGGESTED READING 42 | We advise you to have a look through the following React documents beforehand: 43 | * [Quick Start - React](https://react.dev/learn) 44 | * [Writing Markup with JSX - React](https://react.dev/learn/writing-markup-with-jsx) 45 | 46 | ## 📺 CAN'T MAKE IT? 47 | 48 | Subscribe to our [YouTube channel](https://www.youtube.com/c/KintoneDeveloperProgram) to get notified when we post this workshop's recording! 49 | 50 | This workshop will be live-streamed on YouTube Live. 51 | * [youtu.be/O6FnSGgGBRk](https://youtu.be/O6FnSGgGBRk) 52 | 53 | ## ⚙️ WHAT IS KINTONE? 54 | 55 | Kintone is a no-code/low-code cloud platform for teams to quickly & easily share and collaborate on their data. 56 | You can add JavaScript, CSS, &/or HTML to enhance the front-end UI/UX of a Kintone App. This can include features such as maps, buttons, and color-coding. 57 | 58 | Read how to customize and develop on the Kintone platform at [kintone.dev](http://kintone.dev/)! 59 | -------------------------------------------------------------------------------- /docs/Solution_server.js: -------------------------------------------------------------------------------- 1 | // Completed Version of server.js 2 | 3 | // backend - server.js - Routes API requests from the frontend to Kintone 4 | 5 | // Express Server Setup 6 | const express = require('express'); 7 | const cors = require('cors'); 8 | const PORT = 50000; 9 | const app = express(); 10 | 11 | // Hide sensitive info in a .env file with dotenv 12 | require('dotenv').config({ path: '../.env' }); 13 | 14 | // Get Kintone credentials from a .env file 15 | const subdomain = process.env.SUBDOMAIN; 16 | const appID = process.env.APPID; 17 | const apiToken = process.env.APITOKEN; 18 | 19 | // Parse incoming requests with JSON payloads 20 | app.use(express.json()); 21 | 22 | // Set Cross-Origin Resource Sharing (CORS) to frontend React App 23 | app.use(cors()); 24 | const corsOptions = { 25 | origin: 'http://localhost:3000' 26 | }; 27 | 28 | // Kintone's record(s) endpoints 29 | const multipleRecordsEndpoint = `https://${subdomain}.kintone.com/k/v1/records.json?app=${appID}` 30 | const singleRecordEndpoint = `https://${subdomain}.kintone.com/k/v1/record.json?app=${appID}`; 31 | // Kintone app's field codes are 'country' 'state' and 'city'. 32 | 33 | // TODO: Create a GET endpoint at /getData 34 | // This route executes when a GET request lands on localhost:50000/getData 35 | app.get('/getData', cors(corsOptions), async (req, res) => { 36 | const fetchOptions = { 37 | method: 'GET', 38 | headers: { 39 | 'X-Cybozu-API-Token': apiToken 40 | } 41 | } 42 | const response = await fetch(multipleRecordsEndpoint, fetchOptions); 43 | const jsonResponse = await response.json(); 44 | res.json(jsonResponse); 45 | }); 46 | 47 | // TODO: Create a POST endpoint at /postData 48 | // This route executes when a POST request lands on localhost:50000/postData 49 | app.post('/postData', cors(corsOptions), async (req, res) => { 50 | const requestBody = { 51 | 'app': appID, 52 | 'record': { 53 | 'country': { 54 | 'value': req.body.country 55 | }, 56 | 'state': { 57 | 'value': req.body.state 58 | }, 59 | 'city': { 60 | 'value': req.body.city 61 | } 62 | } 63 | }; 64 | const options = { 65 | method: 'POST', 66 | headers: { 67 | 'X-Cybozu-API-Token': apiToken, 68 | 'Content-Type': 'application/json', 69 | }, 70 | body: JSON.stringify(requestBody) 71 | } 72 | const response = await fetch(singleRecordEndpoint, options); 73 | const jsonResponse = await response.json(); 74 | res.json(jsonResponse); 75 | }); 76 | 77 | app.listen(PORT, () => { 78 | console.log(`\n Backend server listening at http://localhost:${PORT} \n Confirm if Kintone records are being retrieved at \n http://localhost:${PORT}/getData`); 79 | }); 80 | -------------------------------------------------------------------------------- /docs/Workshop_Steps.md: -------------------------------------------------------------------------------- 1 | # Workshop Steps 2 | This guide outlines all the steps required to complete the workshop. 3 | 4 | ## Outline 5 | * [A. Get started - clone the repo \& install dependencies](#a-get-started---clone-the-repo--install-dependencies) 6 | * [Terminal 1](#terminal-1) 7 | * [Terminal 2](#terminal-2) 8 | * [B. Get your free Kintone database](#b-get-your-free-kintone-database) 9 | * [C. Create a `.env` file](#c-create-a-env-file) 10 | * [D. Create a Kintone web database app](#d-create-a-kintone-web-database-app) 11 | * [Input Fields](#input-fields) 12 | * [Steps to create the Kintone App](#steps-to-create-the-kintone-app) 13 | * [E. Generate an API token for the Kintone app](#e-generate-an-api-token-for-the-kintone-app) 14 | * [H. Edit server.js](#h-edit-serverjs) 15 | * [What do you mean, CORS?](#what-do-you-mean-cors) 16 | * [Overview](#overview) 17 | * [server.js setup](#serverjs-setup) 18 | * [Let's Start Coding!](#lets-start-coding) 19 | * [I. Start the servers](#i-start-the-servers) 20 | * [Terminal 1 - Frontend](#terminal-1---frontend) 21 | * [Terminal 2 - Backend](#terminal-2---backend) 22 | * [Check your work](#check-your-work) 23 | * [Still got a problem?](#still-got-a-problem) 24 | 25 | ## A. Get started - clone the repo & install dependencies 26 | 27 | First, clone the [kintone-workshops/React-x-REST-API-Workshop](https://github.com/kintone-workshops/React-x-REST-API-Workshop) repo! 🚀 28 | Then go inside the folders & install the dependencies! 29 | 30 | ⚡ Two terminal windows are required for this workshop. 31 | 32 | ### Terminal 1 33 | 34 | ```shell 35 | cd Downloads 36 | 37 | git clone https://github.com/kintone-workshops/React-x-REST-API-Workshop 38 | 39 | cd React-x-REST-API-Workshop 40 | 41 | npm install 42 | ``` 43 | 44 | ### Terminal 2 45 | 46 | ```shell 47 | cd Downloads/React-x-REST-API-Workshop 48 | 49 | cd backend && npm install 50 | ``` 51 | 52 | ### ⚠️ WARNING ⚠️ 53 | ⚡ **Node.js v18.16.1** or higher is required to run this workshop. 54 | (The current LTS version is recommended) 55 | 56 | Not the correct versions, or confused? 🤔 → Check out the [Guide on Installing Node.js & npm {macOS & Windows}](https://dev.to/kintonedevprogram/guide-on-installing-nodejs-npm-macos-windows-16ii). 57 | 58 | ## B. Get your free Kintone database 59 | 60 | 1. Go to [kintone.dev/new/](http://kintone.dev/new/) and fill out the form. 61 | * ⚡ Only use lowercase, numbers, & hyphens in your subdomain 62 | * ⚠ Do not use uppercase or special characters 63 | * 🤖 Example subdomain: `example` 64 | * ✅ Use Chrome or Firefox 65 | * ❌ Do not use Safari 66 | 2. Look for "**Welcome to Kintone! One More Step for Developer License**" email in your inbox and click the **Activate Now** button. 67 | * Sent from `developer@kintone.com` 68 | * If you don't see it, check your spam folder 69 | 3. Set the **Initial Password** 70 | 4. Log into your Kintone Subdomain 71 | * URL: {your subdomain}.kintone.com (e.g. `example.kintone.com`) 72 | * Login Name: Your email address 73 | * Password: The password you set in Step 3 74 | * ⚡ If you forget your password, you can reset it by clicking the **Having Trouble Logging In?** link on the login screen. 75 | 76 | | | | 77 | | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | 78 | | ![Step 1: Fill out the Kintone Developer license sign-up form](././img/common_signup/SignUp-1.png) | ![Step 2: Email address will be the login name & the subdomain will be your unique link](././img/common_signup/SignUp-2.png) | 79 | | ![Step 3: Check for a "Welcome to Kintone! One More Step To..." email](././img/common_signup/SignUp-3.png) | ![Step 4: Log into Kintone](././img/common_signup/SignUp-4.png) | 80 | 81 | ## C. Create a `.env` file 82 | 83 | Duplicate the [.env.example](./../.env.example) file and save as `.env` file. 84 | This is where we will be saving the login credentials and API Keys. 85 | 86 | Here is what your `.env` might look like: 87 | 88 | ```txt 89 | SUBDOMAIN = "example" 90 | APPID = "1" 91 | APITOKEN = "1J22qNAR54I4eiMcd0JmfDAavJNfNJDVaqt34X9A" 92 | ``` 93 | 94 | So far, you can fill out the following variables: 95 | * `SUBDOMAIN` 96 | 97 | ### ⚠️ WARNING ⚠️ 98 | 99 | ⚠️ DO NOT DELETE THE [.env.example](./../.env.example) FILE! 100 | [.env.example](./../.env.example) is used by env-cmd to verify that the `.env` file is correctly configured. 101 | 102 | ## D. Create a Kintone web database app 103 | 104 | Let's create a Kintone App to store Kintone User's Country, State, and City. 105 | 106 | Here are the required fields & their configurations for our workshop: 107 | 108 | ### Input Fields 109 | 110 | | Field Type | Field Name | Field Code | 111 | | ------------- | ----------- | ---------- | 112 | | Text Field #1 | **Country** | `country` | 113 | | Text Field #2 | **State** | `state` | 114 | | Text Field #3 | **City** | `city` | 115 | 116 | ### Steps to create the Kintone App 117 | 118 | To create the Kintone App, click the **➕** button on the upper right side of the Kintone Portal. 119 | ![Screenshot: The "➕" button](img/common_kintone/CreateApp-1.png) 120 | 121 | Click the **Create App from Scratch** button. 122 | ![Screenshot: The create app screen](img/common_kintone/CreateApp-2.png) 123 | 124 | Name your App. We chose **I Use Kintone!** 125 | ![Screenshot: The create app screen](img/Kintone-App-Name.png) 126 | 127 | Configure your App to have three Text Fields, with field codes for `country`, `state`, and `city`. 128 | ![Screenshot of the completed Kintone App](img/Kintone-Field-Codes.gif) 129 | 130 | Then, click the **Save** and **Activate App** buttons! 💪 131 | 132 | _Confused? 🤔 → Check out the [How to Create a Kintone Database App](https://youtu.be/pRtfn-8cf_I) video 📺_ 133 | 134 | ## E. Generate an API token for the Kintone app 135 | 136 | We need to generate an API Token for our Kintone App. 137 | 138 | 1. From the Kintone App, click the **App Settings** button ⚙️ on the upper right side. 139 | * ![Screenshot: The "App Settings" button](https://get.kintone.help/k/img/settings_new_icon.png) 140 | 1. Select the **App Settings** tab 141 | 1. Under **Customization and Integration**, click the **API Token** button. 142 | 1. Click **Generate**. ![Screenshot: The "Generate" button](img/common_kintone/KintoneApp_API_1.png) 143 | 1. Check the `Add records` and `Edit records` boxes. 144 | * ![Screenshot: The "Add records" and "Edit records" boxes](img/common_kintone/KintoneApp_API_2.png) 145 | 1. Copy the API Token and paste it to the `APITOKEN` variable in your `.env` file. 146 | 1. Click the **Save** button on the bottom right side of the screen. 147 | 1. Click the **Update App** button on the upper right side of the screen. 148 | 149 | ![KintoneApp_URL.png](img/common_kintone/KintoneApp_URL.png) 150 | 151 | ### Update the `.env` file with the App ID as well! 152 | Input the App ID into the `APPID` variable in your `.env` file. 153 | 154 | If this is NOT your first Kintone App, then you need to update the `"app"` variable with your App ID! 155 | 156 | The App ID number can be easily found in the Kintone App's URL! 157 | 158 | Go to the Kintone App and grab the URL. 159 | * Example: `https://devevents.kintone.com/k/52/` 160 | 161 | Kintone App's URL follows this template: 162 | * `https://.kintone.com/k//show#record=` 163 | 164 | So then the `https://devevents.kintone.com/k/52/` URL tells us that this App's ID is `52` 165 | 166 | --- 167 | 168 | ## H. Edit server.js 169 | 170 | For this workshop, we will only be coding in [./backend/server.js](../backend/server.js). 171 | This tutorial is focused only on connecting a React frontend to a Kintone Web Database. As such, we won't be covering the front end components (located at [./src/App.js](../src/App.js)). 172 | 173 | As is common for Web Development, API calls from the frontend directly to your Kintone Database are not allowed, due to CORS security risks. 174 | 175 | ### What do you mean, CORS? 176 | 177 | Since our frontend resides on localhost:3000 and any API calls to our Kintone Database would be directed at your Kintone subdomain, a backend is needed to act as a proxy. 178 | ![CORS.png](img/CORS.png) 179 | 180 | By configuring CORS settings on our Express Server backend, we can make REST API requests to our Kintone Web Database. 181 | 182 | ### Overview 183 | 184 | In short, our React Frontend, located on `localhost:3000` will make a fetch request of either `GET` or `POST` to our Express Server at `localhost:50000/getData` or `localhost:50000/postData`. Then, acting as our proxy, our backend will then make a fetch request to `https://example.kintone.com/k/v1/record.json?app=1`, to either GET or POST our data. The data will be returned our backend as JSON, which we will then pass back to the frontend to be displayed. 185 | 186 | ### server.js setup 187 | 188 | Navigate to [./backend/server.js](../backend/server.js). 189 | 190 | At the top of the file, we have our dependency imports and class instantiation: 191 | 192 | ``` javascript 193 | const express = require('express'); 194 | const cors = require('cors'); 195 | const PORT = 50000; 196 | const app = express(); 197 | ``` 198 | 199 | Next, we have our authentication setup via our `.env` file: 200 | 201 | ``` javascript 202 | require('dotenv').config({path: '../.env'}); 203 | const subdomain = process.env.SUBDOMAIN; 204 | const appID = process.env.APPID; 205 | const apiToken = process.env.APITOKEN; 206 | ``` 207 | 208 | And lastly, we have some CORS configuration: 209 | 210 | ```javascript 211 | app.use(cors()); 212 | const corsOptions = { 213 | origin: 'http://localhost:3000' 214 | }; 215 | ``` 216 | 217 | and some pre-configured REST API endpoints: 218 | 219 | ```javascript 220 | const multipleRecordsEndpoint = `https://${subdomain}.kintone.com/k/v1/records.json?app=${appID}` 221 | const singleRecordEndpoint = `https://${subdomain}.kintone.com/k/v1/record.json?app=${appID}`; 222 | ``` 223 | 224 | We got this information from our [Kintone Developer Program](https://kintone.dev/en/) website, specifically from our [REST API Records](https://kintone.dev/en/docs/kintone/rest-api/records/) documentation. 225 | 226 | ### Let's Start Coding! 227 | 228 | We've instantiated our Express Server as `app`, so let's first make a `GET` request route on `localhost:50000/getData`. 229 | 230 | ```javascript 231 | app.get('/getData', cors(corsOptions), async (req, res) => { 232 | // configure here 233 | }); 234 | ``` 235 | 236 | Express Server routes look and function much like functions. We specify this is a `GET` request route with `app.get()`, and then fill in the route name, and its CORS options. Because it is a function, we can designate it as asynchronous easily. One point to note, is how Express Servers designated return values. 237 | 238 | You may have noticed that `(req, res)` specifies a request object (normal), **and** and response object. (Not exactly normal!) Normally in a function, responses are handled via `return` statements. This is specific to Express, so be careful. 239 | 240 | Thankfully, the rest of routing with Express is simple `fetch` requests. 241 | 242 | ```javascript 243 | app.get('/getData', cors(corsOptions), async (req, res) => { 244 | const fetchOptions = { 245 | method: 'GET', 246 | headers: { 247 | 'X-Cybozu-API-Token': apiToken 248 | } 249 | } 250 | const response = await fetch(multipleRecordsEndpoint, fetchOptions); 251 | const jsonResponse = await response.json(); 252 | }); 253 | ``` 254 | 255 | Like a normal `fetch` request, we designate some options and our headers with our API Token. 256 | Designate a new constant variable `response` and set it equal to the result of awaiting a `fetch` request to `multipleRecordsEndpoint`. This is a `GET` request, so when we **GET** our database records, we want to see **all** records in the database. Therefore, we are fetching from `records.json`. 257 | 258 | Lastly, another Express Server quirk, we designate our JSON response (which gets sent back to our frontend) like so: 259 | 260 | ```javascript 261 | // This route executes when a GET request lands on localhost:50000/getData 262 | app.get('/getData', cors(corsOptions), async (req, res) => { 263 | const fetchOptions = { 264 | method: 'GET', 265 | headers: { 266 | 'X-Cybozu-API-Token': apiToken 267 | } 268 | } 269 | const response = await fetch(multipleRecordsEndpoint, fetchOptions); 270 | const jsonResponse = await response.json(); 271 | res.json(jsonResponse); 272 | }); 273 | ``` 274 | 275 | With this, restart your Express Server, and from your React frontend click the `Get!` button. If you have any data in your database, it should be displayed on the page. If the loading spinner never stops, check developer options with `F12` for errors, and reference the [Debugging](../README.md#debugging) section. 276 | 277 | Last, we'll code out the `POST` route. It's similar, however we need to correctly structure our `POST BODY` data, so it can be saved to Kintone properly. 278 | 279 | ```javascript 280 | app.post('/postData', cors(corsOptions), async (req, res) => { 281 | 282 | }); 283 | ``` 284 | 285 | This time, specify `app.post`, with an endpoint of `/postData`. Express Server makes it easy to create different routes. 286 | 287 | Next, we'll structure our data to save to Kintone. 288 | Looking at our frontend, we can see that the submit button in [App.js](../src/App.js) sends a `location` object with properties of `country`, `state`, and `city`. For this tutorial, we've handled the frontend so we can focus on the backend. 289 | 290 | According to the [Kintone REST API documentation](https://kintone.dev/en/docs/kintone/rest-api/records/add-record/#sample-request) our `requestBody` should be formatted as so: 291 | 292 | ```javascript 293 | app.post('/postData', cors(corsOptions), async (req, res) => { 294 | const requestBody = { 295 | 'app': appID, 296 | 'record': { 297 | 'country': { 298 | 'value': req.body.country 299 | }, 300 | 'state': { 301 | 'value': req.body.state 302 | }, 303 | 'city': { 304 | 'value': req.body.city 305 | } 306 | } 307 | }; 308 | }); 309 | ``` 310 | 311 | We then put our `requestBody` in our `options` for `fetch`, and make a request to the `singleRecordEndpoint`, as we only wish to save one location at a time to our Kintone Database. 312 | 313 | ```javascript 314 | app.post('/postData', cors(corsOptions), async (req, res) => { 315 | const requestBody = { 316 | 'app': appID, 317 | 'record': { 318 | 'country': { 319 | 'value': req.body.country 320 | }, 321 | 'state': { 322 | 'value': req.body.state 323 | }, 324 | 'city': { 325 | 'value': req.body.city 326 | } 327 | } 328 | }; 329 | const options = { 330 | method: 'POST', 331 | headers: { 332 | 'X-Cybozu-API-Token': apiToken, 333 | 'Content-Type': 'application/json', 334 | }, 335 | body: JSON.stringify(requestBody) 336 | } 337 | const response = await fetch(singleRecordEndpoint, options); 338 | const jsonResponse = await response.json(); 339 | res.json(jsonResponse); 340 | }); 341 | ``` 342 | 343 | --- 344 | 345 | ## I. Start the servers 346 | 347 | Open two terminal windows 348 | 349 | ### Terminal 1 - Frontend 350 | 351 | ```shell 352 | cd React-x-REST-API-Workshop 353 | 354 | npm run start 355 | ``` 356 | 357 | ### Terminal 2 - Backend 358 | 359 | ```shell 360 | cd React-x-REST-API-Workshop/backend 361 | 362 | npm run start 363 | ``` 364 | 365 | Navigate to [`localhost:3000`](http://localhost:3000/) in your browser, enter your Country, State, and City, and click `submit`! 366 | If your entry appears in your Kintone Database, then congratulations, you did it! 367 | 368 | ## Check your work 369 | 370 | Is your code not working? 371 | 372 | Compare your [backend/server.js](../backend/server.js) with the [Solution_server.js](./Solution_server.js) to see if it is all written correctly. 373 | 374 | ## Still got a problem? 375 | 376 | Check out README's [Debugging](../README.md#debugging) section! 377 | 378 | And finally, post your Kintone customization questions over at our community forum: 379 | [forum.kintone.dev](https://forum.kintone.dev/) 380 | 381 | Good luck coding! 💪 382 | -------------------------------------------------------------------------------- /docs/Workshop_Steps.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/Workshop_Steps.pdf -------------------------------------------------------------------------------- /docs/Zoom_Chat.md: -------------------------------------------------------------------------------- 1 | # Zoom Chat Snippets 2 | 3 | --- 4 | 5 | ## Table of Content 6 | * [Check-in Time Slots](#check-in-time-slots) 7 | * [Quick Links](#quick-links) 8 | * [Waiting Room](#waiting-room) 9 | * [NodeJS](#nodejs) 10 | * [Start](#start) 11 | * [Live on YouTube](#live-on-youtube) 12 | * [Install Commands {Get Started}](#install-commands-get-started) 13 | * [Workshop Steps](#workshop-steps) 14 | * [YouTube](#youtube) 15 | * [Create a .env File](#create-a-env-file) 16 | * [Debugging - Let's Fix Those Problems 💪](#debugging---lets-fix-those-problems-) 17 | * [Additional Questions 🤔](#additional-questions-) 18 | * [Create a Kintone Web Database App](#create-a-kintone-web-database-app) 19 | * [Fields \& Field Codes](#fields--field-codes) 20 | * [Kintone API Token](#kintone-api-token) 21 | * [Kintone Customization Tutorials](#kintone-customization-tutorials) 22 | * [Quick Check-in](#quick-check-in) 23 | * [Looking for the Kintone Subdomain Email? ✉️](#looking-for-the-kintone-subdomain-email-️) 24 | * [Errors related to .env](#errors-related-to-env) 25 | * [Join our Meetup Group](#join-our-meetup-group) 26 | * [Got Kintone Questions?](#got-kintone-questions) 27 | * [Survey \& Gift Card Raffle](#survey--gift-card-raffle) 28 | * [Write up your experience!](#write-up-your-experience) 29 | * [Log into Kintone Subdomain?](#log-into-kintone-subdomain) 30 | * [step-by-step guide](#step-by-step-guide) 31 | * [Becoming a Kintone Partner?](#becoming-a-kintone-partner) 32 | * [What are Kintone Plug-ins](#what-are-kintone-plug-ins) 33 | * [🚀 Have your Kintone Subdomain ready!](#-have-your-kintone-subdomain-ready) 34 | * [Got Questions? 🤔](#got-questions-) 35 | * [Why use Kintone?](#why-use-kintone) 36 | * [Start the servers](#start-the-servers) 37 | * [Where to get the Subdomain, View ID, and App ID?](#where-to-get-the-subdomain-view-id-and-app-id) 38 | * [Live on YouTube](#live-on-youtube-1) 39 | * [Contest](#contest) 40 | * [Completed Code](#completed-code) 41 | 42 | --- 43 | 44 | ## Check-in Time Slots 45 | 46 | * 10:00 - Hello 47 | * 10:10 - Get Started 48 | * 10:25 - npm install (root & backend) 49 | * 10:35 - Walk through repo (.env.example, App.js, server.js, etc.) 50 | * 10:45 - Create a Kintone App 51 | * 11:00 - 1 hour left 52 | * 11:15 - 45 min left 53 | * 11:30 - 30 min left 54 | * 11:45 - Wrap Up and Q&A 55 | * 12:00 - Thank you & Survey Raffle 56 | 57 | = = = = = = = = = = 58 | 59 | ## Quick Links 60 | 61 | 🤖 Clone the Workshop Repository! 62 | https://bit.ly/react-x-rest 63 | 64 | 🚀 Have your Kintone Subdomain ready! 65 | https://kintone.dev/new 66 | 67 | 📺 YouTube live stream 68 | https://youtu.be/JaWjQkeninU 69 | 70 | 🏆 Contest 71 | https://bit.ly/kintonecontest23 72 | 73 | 🗓️ Meetup 74 | https://www.meetup.com/kintone-developers/ 75 | 76 | 🗓️ Eventbrite 77 | https://www.eventbrite.com/o/35299961053 78 | 79 | 📺 YouTube Channel 80 | https://bit.ly/KDP_Video 81 | 82 | = = = = = = = = = = 83 | 84 | ## Waiting Room 85 | = = = = = = = = = = 86 | 87 | Hello everyone, the workshop will start real soon! 88 | 89 | Be sure you are ready by completing the following tasks: 90 | 91 | 1. 🤖 Clone the Workshop Repository! 92 | https://bit.ly/react-x-rest 93 | 94 | 2. 🚀 Have your Kintone Subdomain ready! 95 | If you have not already, sign up for the FREE Kintone Developer License: 96 | https://kintone.dev/new 97 | 98 | * ✅ Use Chrome or Firefox 99 | * ⚠️ NO Safari 100 | * ⚡ Accept Cookies first! 101 | 102 | Thank you for waiting & see you soon! 103 | 104 | = = = = = = = = = = 105 | 106 | ## Node.js 107 | 108 | ⚡ Node.js v18.16.1 or higher is required to run this workshop. 109 | (The current LTS version is recommended) 110 | 111 | For more information, refer to the Guide on Installing Node.js & npm {macOS & Windows}: 112 | https://bit.ly/nodejs-setup-guide 113 | 114 | = = = = = = = = = = 115 | 116 | ## Start 117 | = = = = = = = = = = 118 | 119 | Hello everyone, thank you for joining the workshop! 120 | 121 | Here is how to get started: 122 | 123 | 1. 🤖 Clone the Workshop Repository! 124 | https://bit.ly/react-x-rest 125 | 126 | 2. 🚀 Have your Kintone Subdomain ready! 127 | If you have not already, sign up for the FREE Kintone Developer License by filling out this web form: 128 | https://kintone.dev/new 129 | 130 | * ✅ Use Chrome or Firefox 131 | * ⚠️ NO Safari 132 | * ⚡ Accept Cookies first! 133 | 134 | = = = = = = = = = = 135 | 136 | ## Live on YouTube 137 | 138 | If you get lost, you can "rewind" on our lives stream on YouTube: 139 | https://youtu.be/JaWjQkeninU 140 | 141 | = = = = = = = = = = 142 | 143 | ## Install Commands {Get Started} 144 | 145 | # 2 terminal windows are needed for this workshop. 146 | 147 | # First clone the workshop repo: 148 | 149 | cd Downloads 150 | 151 | git clone https://github.com/kintone-workshops/React-x-REST-API-Workshop 152 | 153 | cd React-x-REST-API-Workshop && npm install 154 | 155 | cd React-x-REST-API-Workshop && cd backend && npm install 156 | 157 | 158 | # Then install the dependencies from the project root directory: 159 | 160 | npm install 161 | 162 | # Then install the dependencies from the backend directory: 163 | 164 | cd backend && npm install 165 | 166 | = = = = = = = = = = 167 | 168 | ## Workshop Steps 169 | 170 | We have all the steps for the workshop here in the repo: 171 | 172 | ./docs/Workshop_Steps.md 173 | 174 | or https://github.com/kintone-workshops/React-x-REST-API-Workshop/blob/main/docs/Workshop_Steps.md 175 | 176 | = = = = = = = = = = 177 | 178 | ## Where to get Kintone Web Database Subdomain? 179 | 180 | Sign up for the FREE Kintone Developer License by filling out this web form: 181 | 182 | https://kintone.dev/new 183 | 184 | * ✅ Use Chrome or Firefox 185 | * ⚠️ NO Safari 186 | * ⚡ Accept Cookies first! 187 | 188 | = = = = = = = = = = 189 | 190 | ## YouTube 191 | = = = = = = = = = = 192 | 193 | This is also live on YouTube: 194 | https://youtu.be/JaWjQkeninU 195 | 196 | It is a bit delayed but for those who want to "rewind", this is another great option ~ 197 | 198 | This workshop will also be uploaded to our YouTube Channel! 199 | 200 | Kintone Developer Program 201 | https://bit.ly/KDP_Video 202 | 203 | Subscribe so you get notified with the workshop recording gets uploaded! 🔔 204 | 205 | = = = = = = = = = = 206 | 207 | ## Create a .env File 208 | 209 | Using the .env.example file as a template, create a .env file. 210 | 211 | Then input your Kintone credentials like the following: 212 | 213 | SUBDOMAIN = "example" 214 | APPID = "1" 215 | APITOKEN = "1J22qNAR54I4eiMcd0JmfDAavJNfNJDVaqt34X9A" 216 | 217 | ⚠️ DO NOT DELETE THE .env.example FILE! 218 | .env.example is used by env-cmd to verify that the .env file is correctly configured. 219 | 220 | = = = = = = = = = = 221 | 222 | ## Debugging - Let's Fix Those Problems 💪 223 | 224 | Here is a rundown of common problems that may occur & its solutions! 225 | 226 | https://github.com/kintone-workshops/React-x-REST-API-Workshop#debugging 227 | 228 | If you have additional questions during the workshop, feel free to message me. 229 | 230 | = = = = = = = = = = 231 | 232 | ## Additional Questions 🤔 233 | 234 | If you have questions afterwards, post them at our Kintone Developer Community 235 | 236 | https://forum.kintone.dev/ 237 | 238 | = = = = = = = = = = 239 | 240 | ## Create a Kintone Web Database App 241 | 242 | ### Fields & Field Codes 243 | How to set the Field Codes for the Kintone App? 244 | 1. Hover over the field 245 | 2. Click the top right gear icon ⚙️ 246 | 3. Select Settings from the drop-down menu 247 | 4. Click the edit button Edit Button 248 | 5. Enter the new field code 249 | 6. Click the Save button 250 | 251 | ⚠️ Field Codes are case-sensitive ⚠️ 252 | 253 | Set the following Field Codes 254 | 255 | 3x Text Fields 256 | * Field Name -> Field Code 257 | * Country -> country 258 | * State -> state 259 | * City -> city 260 | 261 | Save! 262 | 263 | ⚡ Be sure to click Save and Activate App buttons! 💪 264 | 265 | ### Kintone API Token 266 | 267 | To generate an API Token for a Kintone App: 268 | 269 | 1. Go to the Kintone App 270 | 1. Go to the Gear icon ⚙️ (top right corner) > Open the App Settings page 271 | 1. Click on the **App Settings** Tab > Click on **API Token** settings 272 | 1. Click the `Generate` button to generate a token 273 | 1. Enable the `View records` & `Add records` checkboxes 274 | 1. Click the `Save` button (top left corner) to save the token setting 275 | 1. Finally, click the Activate / Update App button (top right corner) to implement the token setting change. 276 | 277 | Ref: 278 | https://github.com/kintone-workshops/React-x-REST-API-Workshop/blob/main/docs/Workshop_Steps.md#d-create-a-kintone-web-database-app 279 | 280 | = = = = = = = = = = 281 | 282 | ## Kintone Customization Tutorials 283 | 284 | If you want additional projects to start playing around with Kintone, check out this page: 285 | 286 | https://kintone.dev/en/landing-page/tutorial-gallery/ 287 | 288 | = = = = = = = = = = 289 | 290 | ## Quick Check-in 291 | 292 | Thank you for all those who DM me with questions 293 | 294 | Looks like everyone figured out where you need to go. 295 | 296 | If you are still stuck, please let me know ~ 297 | 298 | = = = = = = = = = = 299 | 300 | ## Looking for the Kintone Subdomain Email? ✉️ 301 | 302 | Search the following in your email app: 303 | 304 | Welcome to Kintone! One More Step to Developer License 305 | 306 | The email will be from developer@kintone.com 307 | 308 | = = = = = = = = = = 309 | 310 | ## Errors related to .env 311 | 312 | If you get one of the following error messages: 313 | 314 | * [webpack-cli] Error: Missing environment variable: KINTONE_BASE_URL 315 | * [webpack-cli] Error: Missing environment variable: KINTONE_PASSWORD 316 | * [webpack-cli] Error: Missing environment variable: KINTONE_USERNAME 317 | * [webpack-cli] Error: Missing environment variable: VIEW_ID 318 | * [webpack-cli] TypeError: Cannot convert undefined or null to object 319 | * Failed to find .env file at default paths: [./.env,./.env.js,./.env.json] 320 | * Failed to find .env file at default paths: [./.env,./.env.js,./.env.json] 321 | * Failed to upload JavaScript/CSS files 322 | * KintoneRestAPIError: [520] [CB_WA01] Password authentication failed... 323 | 324 | Then please verify that 325 | * your .env file has been correctly configured 326 | * your username and password for your Kintone account are correct 327 | * you have not modified the .env.example 328 | 329 | = = = = = = = = = = 330 | 331 | ## Join our Meetup Group 332 | https://www.meetup.com/kintone-developers/ 333 | 334 | ## Got Kintone Questions? 335 | 336 | Please post them in our Kintone Developer Community! 337 | 338 | https://forum.kintone.dev/ 339 | 340 | = = = = = = = = = = 341 | 342 | ## Survey & Gift Card Raffle 343 | 344 | Enter to WIN a $25 Amazon Gift Card! 💰️ 345 | 346 | https://bit.ly/kdp-aug-2023 347 | 348 | Your feedback is vital for us to improve our workshop! 349 | Thank you for your time & input ~ 350 | 351 | = = = = = = = = = = 352 | 353 | ## Write up your experience! 354 | 355 | Post to Dev.to or Medium about your experience with Kintone customization ~ 356 | 357 | See what others post about Kintone 358 | https://dev.to/t/kintone 359 | 360 | You might be interested in 361 | Deploy a REST API calling node.js App to Heroku article 362 | 363 | https://dev.to/will_yama/deploy-a-rest-api-calling-node-js-app-to-heroku-2mia 364 | 365 | React & REST API: How to render responses 366 | 367 | https://dev.to/will_yama/how-to-render-responses-96c 368 | 369 | = = = = = = = = = = 370 | 371 | If you want to check out our amChart x Data Visualization workshop content: 372 | 373 | https://youtu.be/fHNj6MieBzw 374 | 375 | = = = = = = = = = = 376 | 377 | ## Log into Kintone Subdomain? 378 | 379 | Your login link would be 380 | YOUR_SUBDOMAIN.kintone.com 381 | 382 | --- 383 | 384 | Subdomain: example 385 | URL: example.kintone.com 386 | 387 | = = = = = = = = = = 388 | 389 | ## step-by-step guide 390 | 391 | If you are ever lost, check out our step-by-step guide here: 392 | 393 | https://github.com/kintone-workshops/React-x-REST-API-Workshop/blob/main/docs/Workshop_Steps.md 394 | 395 | = = = = = = = = = = 396 | 397 | ## Becoming a Kintone Partner? 398 | 399 | https://www.kintone.com/en-us/become-a-partner/ 400 | 401 | = = = = = = = = = = 402 | 403 | ## What are Kintone Plug-ins 404 | 405 | https://kintone.dev/en/plugins/introduction-to-plug-ins/what-are-kintone-plug-ins/ 406 | 407 | = = = = = = = = = = 408 | 409 | ## 🚀 Have your Kintone Subdomain ready! 410 | 411 | If you have not already, sign up for the FREE Kintone Developer License by filling out this web form: 412 | 413 | https://kintone.dev/new 414 | 415 | * ✅ Use Chrome or Firefox 416 | * ⚠️ NO Safari 417 | * ⚡ Accept Cookies first! 418 | 419 | = = = = = = = = = = 420 | 421 | ## Got Questions? 🤔 422 | Feel free to msg me with a workshop-related or a general Kintone question to me anytime ~ 423 | 424 | = = = = = = = = = = 425 | 426 | ## Why use Kintone? 427 | * Super easy to use database / backend solution 428 | * You can use vanilla JS to build customizations right on the platform 429 | * Companies are hiring engineers to build Kintone integrations 430 | 431 | More information: 432 | * Get Hacking with Kintone - https://kintone.dev/en/landing-page/hackathon/ 433 | * Job Listing - Kintone Developer Forum - https://forum.kintone.dev/t/seeking-independent-contractors-with-kintone-customization-programming-skills/550 434 | 435 | = = = = = = = = = = 436 | 437 | ## Start the servers 438 | 439 | Open two terminal windows 440 | 441 | From the project root directory, run: 442 | npm run start 443 | 444 | From the backend directory, run: 445 | npm run start 446 | 447 | = = = = = = = = = = 448 | 449 | ## Where to get the Subdomain, View ID, and App ID? 450 | 451 | Go to your Kintone App's custom view & grab the URL 452 | Kintone App's URL follows this template: 453 | https://.kintone.com/k// 454 | Example: 455 | 456 | https://example.kintone.com/k/1/ 457 | Subdomain = example 458 | KINTONE_BASE_URL = https://example.kintone.com 459 | App ID = 1 460 | 461 | = = = = = = = = = = 462 | 463 | ## Live on YouTube 📺 464 | 465 | If you get lost, you can "rewind" on our lives stream on YouTube: 466 | https://youtu.be/JaWjQkeninU 467 | 468 | = = = = = = = = = = 469 | 470 | Direct Message with your email address if you forgot your Kintone Subdomain 471 | 472 | = = = = = = = = = = 473 | 474 | The KINTONE_BASE_URL variable is based on your subdomain. 475 | 476 | For example: 477 | Subdomain = example 478 | KINTONE_BASE_URL = https://example.kintone.com 479 | 480 | = = = = = = = = = = 481 | 482 | ## Contest 483 | 484 | 🏆 Contest - Kintone Customization Contest 2023 Announcement 🏆 485 | https://bit.ly/kintonecontest23 486 | 487 | Example Kintone Customization: 488 | https://dev.to/kintonedevprogram/preview-powerpoint-slides-on-kintone-13eo 489 | 490 | * Forum Category: https://forum.kintone.dev/c/contest/11 491 | 492 | = = = = = = = = = = 493 | 494 | ## Completed Code 495 | 496 | If you want the completed code for the index.js file, you can find it here: 497 | ./docs/Solution_server.js 498 | 499 | = = = = = = = = = = 500 | -------------------------------------------------------------------------------- /docs/img/Build_Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/Build_Screenshot.png -------------------------------------------------------------------------------- /docs/img/CORS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/CORS.png -------------------------------------------------------------------------------- /docs/img/Kintone-App-Name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/Kintone-App-Name.png -------------------------------------------------------------------------------- /docs/img/Kintone-Field-Codes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/Kintone-Field-Codes.gif -------------------------------------------------------------------------------- /docs/img/PROJECT_DEMO_GIF.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/PROJECT_DEMO_GIF.gif -------------------------------------------------------------------------------- /docs/img/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/banner.png -------------------------------------------------------------------------------- /docs/img/common_kintone/CreateApp-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_kintone/CreateApp-1.png -------------------------------------------------------------------------------- /docs/img/common_kintone/CreateApp-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_kintone/CreateApp-2.png -------------------------------------------------------------------------------- /docs/img/common_kintone/Kintone-Button-Edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_kintone/Kintone-Button-Edit.png -------------------------------------------------------------------------------- /docs/img/common_kintone/Kintone-View-Setting-Record-Count-HD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_kintone/Kintone-View-Setting-Record-Count-HD.png -------------------------------------------------------------------------------- /docs/img/common_kintone/Kintone-View-Setting-Record-Count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_kintone/Kintone-View-Setting-Record-Count.png -------------------------------------------------------------------------------- /docs/img/common_kintone/KintoneApp_API_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_kintone/KintoneApp_API_1.png -------------------------------------------------------------------------------- /docs/img/common_kintone/KintoneApp_API_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_kintone/KintoneApp_API_2.png -------------------------------------------------------------------------------- /docs/img/common_kintone/KintoneApp_URL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_kintone/KintoneApp_URL.png -------------------------------------------------------------------------------- /docs/img/common_signup/SignUp-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_signup/SignUp-1.png -------------------------------------------------------------------------------- /docs/img/common_signup/SignUp-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_signup/SignUp-2.png -------------------------------------------------------------------------------- /docs/img/common_signup/SignUp-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_signup/SignUp-3.png -------------------------------------------------------------------------------- /docs/img/common_signup/SignUp-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_signup/SignUp-4.png -------------------------------------------------------------------------------- /docs/img/common_vscode/vscode-setting-extension-HD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_vscode/vscode-setting-extension-HD.png -------------------------------------------------------------------------------- /docs/img/common_vscode/vscode-setting-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/common_vscode/vscode-setting-extension.png -------------------------------------------------------------------------------- /docs/img/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/docs/img/main.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-x-rest-api-workshop", 3 | "version": "1.0.0", 4 | "private": true, 5 | "type": "module", 6 | "dependencies": { 7 | "country-state-city": "^3.1.4", 8 | "express": "^4.18.2", 9 | "react": "^18.2.0", 10 | "react-dom": "^18.2.0", 11 | "react-loader-spinner": "^5.3.4", 12 | "react-select": "^5.7.3" 13 | }, 14 | "devDependencies": { 15 | "react-scripts": "5.0.1" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build" 20 | }, 21 | "eslintConfig": { 22 | "extends": [ 23 | "react-app", 24 | "react-app/jest" 25 | ] 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kintone-workshops/React-x-REST-API-Workshop/4e9247c20aebe7dff02a1696da589acb9ca4af12/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | React App 13 | 14 | 15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .main { 2 | display: flex; 3 | flex-direction: column; 4 | align-content: center; 5 | justify-content: center; 6 | } 7 | 8 | .loadingDiv { 9 | position: absolute; 10 | top: 50%; 11 | left: 50%; 12 | transform: translate(-50%, -50%); 13 | z-index: 99; 14 | } 15 | 16 | .selectDiv { 17 | padding: 5%; 18 | } -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | import { useState } from "react"; 3 | import LoadingSpinner from './components/spinner.js' 4 | import CountryPicker from './components/countryPicker.js' 5 | import StatePicker from './components/statePicker.js' 6 | import CityPicker from './components/cityPicker.js' 7 | 8 | // Import the functions to make API calls 9 | import getRecords from './requests/getRecords.js'; 10 | import postRecord from './requests/postRecord.js'; 11 | 12 | function App() { 13 | // Our hooks for data and setting that data. 14 | const [loading, setLoading] = useState(false); 15 | const [selectedCountry, setSelectedCountry] = useState(""); 16 | const [selectedState, setSelectedState] = useState(""); 17 | const [selectedCity, setSelectedCity] = useState(""); 18 | const [records, setRecords] = useState([]); 19 | 20 | // Submit button's onclick function. Calls POST request 21 | const submit = async () => { 22 | setLoading(true); 23 | let location = { 24 | country: selectedCountry.name, 25 | state: selectedState.name, 26 | city: selectedCity.name 27 | } 28 | console.log(selectedCountry) 29 | if (selectedCountry === "") { 30 | alert("At least pick a country...") 31 | } else { 32 | let response = await postRecord(location); 33 | console.log(response) 34 | } 35 | setLoading(false); 36 | } 37 | 38 | // Get button's onClick function. Calls GET API request. 39 | const get = async () => { 40 | setLoading(true); 41 | let response = await getRecords(); 42 | let locationArray = []; 43 | response.records.forEach((record, index) => { 44 | locationArray.push(
  • {record.country.value}, {record.state.value}, {record.city.value}
  • ) 45 | }); 46 | setRecords(locationArray); 47 | setLoading(false); 48 | } 49 | 50 | // Our react JSX. 51 | return ( 52 |
    53 |

    I Use Kintone!

    54 | {/* If loading is true, show a spinner, otherwise show nothing. */} 55 | {loading ? ( 56 |
    57 | 58 |
    59 | ) : null} 60 | Welcome to React and Kintone! 61 |
    62 |

    Pick a Country

    63 | 64 |

    Then Pick a State

    65 | 66 |

    Lastly, Pick a City

    67 | 68 |
    69 |
    70 | 73 | 76 |
    77 |
    78 |
      {records}
    79 |
    80 |
    81 | ); 82 | } 83 | 84 | export default App; 85 | -------------------------------------------------------------------------------- /src/components/cityPicker.js: -------------------------------------------------------------------------------- 1 | import { City } from "country-state-city"; 2 | import Select from 'react-select' 3 | 4 | 5 | const CityPicker = ({selectedState, selectedCity, setSelectedCity}) => { 6 | return( 7 | { 9 | return options["name"]; 10 | }} 11 | getOptionValue={(options) => { 12 | return options["name"]; 13 | }} 14 | value={selectedCountry} 15 | onChange={(item) => { 16 | setSelectedCountry(item); 17 | }} 18 | /> 19 | ); 20 | } 21 | export default CountryPicker; 22 | -------------------------------------------------------------------------------- /src/components/spinner.js: -------------------------------------------------------------------------------- 1 | import { TailSpin } from 'react-loader-spinner' 2 | 3 | const LoadingSpinner = () => { 4 | return( 5 | 15 | ); 16 | } 17 | export default LoadingSpinner; 18 | -------------------------------------------------------------------------------- /src/components/statePicker.js: -------------------------------------------------------------------------------- 1 | import { State } from "country-state-city"; 2 | import Select from 'react-select' 3 | 4 | 5 | const StatePicker = ({selectedCountry, selectedState, setSelectedState}) => { 6 | return( 7 |