├── .DS_Store ├── .github └── workflows │ └── vercel.yml ├── .gitignore ├── .vercelignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── jsconfig.json ├── main.tf ├── package.json ├── postcss.config.js ├── preview-env ├── loadbalancer.tf ├── main.tf ├── outputs.tf ├── setup-hashicups.yaml ├── terraform.tf ├── variables.tf └── vercel.tf ├── public ├── favicon-120.png ├── favicon-152.png ├── favicon-167.png ├── favicon-180.png ├── favicon.ico ├── images │ ├── boundary.png │ ├── card-amex.svg │ ├── card-mastercard.svg │ ├── card-visa.svg │ ├── consul.png │ ├── demo.svg │ ├── hashicorp.png │ ├── logo.svg │ ├── nomad.png │ ├── orders.svg │ ├── packer.png │ ├── terraform.png │ ├── thumbnails │ │ ├── boundary.png │ │ ├── consul.png │ │ ├── hashicorp.png │ │ ├── nomad.png │ │ ├── packer.png │ │ ├── terraform.png │ │ ├── vagrant.png │ │ ├── vault.png │ │ └── waypoint.png │ ├── user.svg │ ├── vagrant.png │ ├── vault.png │ └── waypoint.png └── robots.txt ├── src ├── components │ ├── Account.js │ ├── Cart.js │ ├── CartButton.js │ ├── CheckoutButton.js │ ├── CoffeeMenu.js │ ├── Field.js │ ├── Footer.js │ ├── Header.js │ ├── Orders.js │ ├── PaymentForm.js │ ├── Radio.js │ └── Theme.js ├── gql │ ├── apolloClient.js │ ├── gqlMutations.js │ └── gqlQueries.js ├── pages │ ├── _app.js │ ├── checkout.js │ ├── coffee │ │ └── [id].js │ ├── index.js │ └── order │ │ └── [id].js ├── styles │ └── globals.css └── useLocalStorage.js ├── tailwind.config.js └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/.DS_Store -------------------------------------------------------------------------------- /.github/workflows/vercel.yml: -------------------------------------------------------------------------------- 1 | name: "Build and Deploy Preview Environment" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | types: [opened, closed] 9 | 10 | jobs: 11 | preview-environment: 12 | name: "Build and Deploy Preview Environment" 13 | runs-on: ubuntu-latest 14 | env: 15 | tfcWorkspaceName: hcup-be-${{ github.head_ref }} 16 | tfcOrg: hashicorp-training 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 20 | # Only set up preview environment for pull requests 21 | - name: Setup Terraform 22 | uses: hashicorp/setup-terraform@v1 23 | with: 24 | cli_config_credentials_token: ${{ secrets.TFC_API_TOKEN }} 25 | # Update main.tf to default to single workspace 26 | - name: Terraform Init, create TFC workspace 27 | id: init-workspace 28 | if: github.event_name == 'pull_request' 29 | run: | 30 | sed -i 's/tags = \["hashicupsBackend"\]/name = "'$tfcWorkspaceName'"/g' main.tf 31 | terraform init -input=false 32 | # Builds and deploys backend + Vercel preview environments 33 | - name: Build and deploy preview environment 34 | if: github.event_name == 'pull_request' && github.event.action != 'closed' 35 | id: build-deploy-preview-environment 36 | run: | 37 | terraform apply --auto-approve 38 | # Runs Terraform output to display the backend URL and Vercel preview URL 39 | - name: Terraform Output 40 | id: output 41 | if: github.event_name == 'pull_request' && github.event.action != 'closed' 42 | run: | 43 | terraform output -no-color 44 | continue-on-error: true 45 | # Creates comments on pull request with Terraform output 46 | - name: Create comment with Terraform output 47 | uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 48 | if: github.event_name == 'pull_request' && github.event.action != 'closed' 49 | env: 50 | OUTPUT: "${{ steps.output.outputs.stdout }}" 51 | with: 52 | github-token: ${{ secrets.GITHUB_TOKEN }} 53 | script: | 54 | const output = `#### Preview Environment Outputs 🖌 55 | \`\`\` 56 | ${process.env.OUTPUT} 57 | \`\`\` 58 | ` 59 | github.issues.createComment({ 60 | issue_number: context.issue.number, 61 | owner: context.repo.owner, 62 | repo: context.repo.repo, 63 | body: output 64 | }) 65 | # When user closes or merges pull request, this will destroy the resources then delete the TFC workspace 66 | - name: Destroy preview environment 67 | if: github.event.action == 'closed' 68 | id: destroy-preview-environment 69 | run: | 70 | terraform destroy --auto-approve 71 | curl --header "Authorization: Bearer ${{ secrets.TFC_API_TOKEN }}" --header "Content-Type: application/vnd.api+json" --request DELETE "https://app.terraform.io/api/v2/organizations/${tfcOrg}/workspaces/${tfcWorkspaceName}" 72 | # Builds and deploys production environment, similar to preview environment but isProd is set to true 73 | # This builds the production environment and does not build any accompanying backend preview resources 74 | - name: Build and deploy Prod Environment 75 | id: build-deploy-prod-environment 76 | if: github.ref == 'refs/heads/main' && github.event_name == 'push' 77 | run: | 78 | sed -i 's/tags = \["hashicupsBackend"\]/name = "hcup-frontend-vercel"/g' main.tf 79 | terraform init -input=false 80 | terraform apply --auto-approve -var="is_prod=true" 81 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # TypeScript v1 declaration files 47 | typings/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Microbundle cache 59 | .rpt2_cache/ 60 | .rts2_cache_cjs/ 61 | .rts2_cache_es/ 62 | .rts2_cache_umd/ 63 | 64 | # Optional REPL history 65 | .node_repl_history 66 | 67 | # Output of 'npm pack' 68 | *.tgz 69 | 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | 73 | # dotenv environment variables file 74 | .env 75 | .env.test 76 | 77 | # parcel-bundler cache (https://parceljs.org/) 78 | .cache 79 | 80 | # Next.js build output 81 | .next 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | build 109 | 110 | .vercel 111 | 112 | hashicups-backend-poc 113 | hashicups-backend-poc.pub 114 | 115 | # Local .terraform directories 116 | **/.terraform/* 117 | 118 | # .tfstate files 119 | *.tfstate 120 | *.tfstate.* 121 | 122 | # Crash log files 123 | crash.log 124 | 125 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 126 | # .tfvars files are managed as part of configuration and so should be included in 127 | # version control. 128 | # 129 | # example.tfvars 130 | 131 | # Ignore override files as they are usually used to override resources locally and so 132 | # are not checked in 133 | override.tf 134 | override.tf.json 135 | *_override.tf 136 | *_override.tf.json 137 | 138 | # Include override files you do wish to add to version control using negated pattern 139 | # 140 | # !example_override.tf 141 | 142 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 143 | # example: *tfplan* 144 | -------------------------------------------------------------------------------- /.vercelignore: -------------------------------------------------------------------------------- 1 | backend-terraform 2 | .github 3 | .circleci 4 | build 5 | node_modules 6 | .terraform 7 | *.tf -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Install dependencies only when needed 2 | FROM node:16-alpine AS deps 3 | # Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. 4 | RUN apk add --no-cache libc6-compat 5 | WORKDIR /app 6 | COPY package.json yarn.lock ./ 7 | RUN yarn install --frozen-lockfile 8 | 9 | # If using npm with a `package-lock.json` comment out above and use below instead 10 | # COPY package.json package-lock.json ./ 11 | # RUN npm ci 12 | 13 | # Rebuild the source code only when needed 14 | FROM node:16-alpine AS builder 15 | WORKDIR /app 16 | COPY --from=deps /app/node_modules ./node_modules 17 | COPY . . 18 | 19 | # Next.js collects completely anonymous telemetry data about general usage. 20 | # Learn more here: https://nextjs.org/telemetry 21 | # Uncomment the following line in case you want to disable telemetry during the build. 22 | # ENV NEXT_TELEMETRY_DISABLED 1 23 | 24 | RUN yarn build 25 | 26 | # Production image, copy all the files and run next 27 | FROM node:16-alpine AS runner 28 | WORKDIR /app 29 | 30 | ENV NODE_ENV production 31 | # Uncomment the following line in case you want to disable telemetry during runtime. 32 | # ENV NEXT_TELEMETRY_DISABLED 1 33 | 34 | RUN addgroup --system --gid 1001 nodejs 35 | RUN adduser --system --uid 1001 nextjs 36 | 37 | # You only need to copy next.config.js if you are NOT using the default configuration 38 | # COPY --from=builder /app/next.config.js ./ 39 | COPY --from=builder /app/public ./public 40 | COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next 41 | COPY --from=builder /app/node_modules ./node_modules 42 | COPY --from=builder /app/package.json ./package.json 43 | 44 | USER nextjs 45 | 46 | EXPOSE 3000 47 | 48 | ENV PORT 3000 49 | 50 | CMD ["node_modules/.bin/next", "start"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022 HashiCorp, Inc. 2 | 3 | Mozilla Public License Version 2.0 4 | ================================== 5 | 6 | 1. Definitions 7 | -------------- 8 | 9 | 1.1. "Contributor" 10 | means each individual or legal entity that creates, contributes to 11 | the creation of, or owns Covered Software. 12 | 13 | 1.2. "Contributor Version" 14 | means the combination of the Contributions of others (if any) used 15 | by a Contributor and that particular Contributor's Contribution. 16 | 17 | 1.3. "Contribution" 18 | means Covered Software of a particular Contributor. 19 | 20 | 1.4. "Covered Software" 21 | means Source Code Form to which the initial Contributor has attached 22 | the notice in Exhibit A, the Executable Form of such Source Code 23 | Form, and Modifications of such Source Code Form, in each case 24 | including portions thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | (a) that the initial Contributor has attached the notice described 30 | in Exhibit B to the Covered Software; or 31 | 32 | (b) that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the 34 | terms of a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | means any form of the work other than Source Code Form. 38 | 39 | 1.7. "Larger Work" 40 | means a work that combines Covered Software with other material, in 41 | a separate file or files, that is not Covered Software. 42 | 43 | 1.8. "License" 44 | means this document. 45 | 46 | 1.9. "Licensable" 47 | means having the right to grant, to the maximum extent possible, 48 | whether at the time of the initial grant or subsequently, any and 49 | all of the rights conveyed by this License. 50 | 51 | 1.10. "Modifications" 52 | means any of the following: 53 | 54 | (a) any file in Source Code Form that results from an addition to, 55 | deletion from, or modification of the contents of Covered 56 | Software; or 57 | 58 | (b) any new file in Source Code Form that contains any Covered 59 | Software. 60 | 61 | 1.11. "Patent Claims" of a Contributor 62 | means any patent claim(s), including without limitation, method, 63 | process, and apparatus claims, in any patent Licensable by such 64 | Contributor that would be infringed, but for the grant of the 65 | License, by the making, using, selling, offering for sale, having 66 | made, import, or transfer of either its Contributions or its 67 | Contributor Version. 68 | 69 | 1.12. "Secondary License" 70 | means either the GNU General Public License, Version 2.0, the GNU 71 | Lesser General Public License, Version 2.1, the GNU Affero General 72 | Public License, Version 3.0, or any later versions of those 73 | licenses. 74 | 75 | 1.13. "Source Code Form" 76 | means the form of the work preferred for making modifications. 77 | 78 | 1.14. "You" (or "Your") 79 | means an individual or a legal entity exercising rights under this 80 | License. For legal entities, "You" includes any entity that 81 | controls, is controlled by, or is under common control with You. For 82 | purposes of this definition, "control" means (a) the power, direct 83 | or indirect, to cause the direction or management of such entity, 84 | whether by contract or otherwise, or (b) ownership of more than 85 | fifty percent (50%) of the outstanding shares or beneficial 86 | ownership of such entity. 87 | 88 | 2. License Grants and Conditions 89 | -------------------------------- 90 | 91 | 2.1. Grants 92 | 93 | Each Contributor hereby grants You a world-wide, royalty-free, 94 | non-exclusive license: 95 | 96 | (a) under intellectual property rights (other than patent or trademark) 97 | Licensable by such Contributor to use, reproduce, make available, 98 | modify, display, perform, distribute, and otherwise exploit its 99 | Contributions, either on an unmodified basis, with Modifications, or 100 | as part of a Larger Work; and 101 | 102 | (b) under Patent Claims of such Contributor to make, use, sell, offer 103 | for sale, have made, import, and otherwise transfer either its 104 | Contributions or its Contributor Version. 105 | 106 | 2.2. Effective Date 107 | 108 | The licenses granted in Section 2.1 with respect to any Contribution 109 | become effective for each Contribution on the date the Contributor first 110 | distributes such Contribution. 111 | 112 | 2.3. Limitations on Grant Scope 113 | 114 | The licenses granted in this Section 2 are the only rights granted under 115 | this License. No additional rights or licenses will be implied from the 116 | distribution or licensing of Covered Software under this License. 117 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 118 | Contributor: 119 | 120 | (a) for any code that a Contributor has removed from Covered Software; 121 | or 122 | 123 | (b) for infringements caused by: (i) Your and any other third party's 124 | modifications of Covered Software, or (ii) the combination of its 125 | Contributions with other software (except as part of its Contributor 126 | Version); or 127 | 128 | (c) under Patent Claims infringed by Covered Software in the absence of 129 | its Contributions. 130 | 131 | This License does not grant any rights in the trademarks, service marks, 132 | or logos of any Contributor (except as may be necessary to comply with 133 | the notice requirements in Section 3.4). 134 | 135 | 2.4. Subsequent Licenses 136 | 137 | No Contributor makes additional grants as a result of Your choice to 138 | distribute the Covered Software under a subsequent version of this 139 | License (see Section 10.2) or under the terms of a Secondary License (if 140 | permitted under the terms of Section 3.3). 141 | 142 | 2.5. Representation 143 | 144 | Each Contributor represents that the Contributor believes its 145 | Contributions are its original creation(s) or it has sufficient rights 146 | to grant the rights to its Contributions conveyed by this License. 147 | 148 | 2.6. Fair Use 149 | 150 | This License is not intended to limit any rights You have under 151 | applicable copyright doctrines of fair use, fair dealing, or other 152 | equivalents. 153 | 154 | 2.7. Conditions 155 | 156 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 157 | in Section 2.1. 158 | 159 | 3. Responsibilities 160 | ------------------- 161 | 162 | 3.1. Distribution of Source Form 163 | 164 | All distribution of Covered Software in Source Code Form, including any 165 | Modifications that You create or to which You contribute, must be under 166 | the terms of this License. You must inform recipients that the Source 167 | Code Form of the Covered Software is governed by the terms of this 168 | License, and how they can obtain a copy of this License. You may not 169 | attempt to alter or restrict the recipients' rights in the Source Code 170 | Form. 171 | 172 | 3.2. Distribution of Executable Form 173 | 174 | If You distribute Covered Software in Executable Form then: 175 | 176 | (a) such Covered Software must also be made available in Source Code 177 | Form, as described in Section 3.1, and You must inform recipients of 178 | the Executable Form how they can obtain a copy of such Source Code 179 | Form by reasonable means in a timely manner, at a charge no more 180 | than the cost of distribution to the recipient; and 181 | 182 | (b) You may distribute such Executable Form under the terms of this 183 | License, or sublicense it under different terms, provided that the 184 | license for the Executable Form does not attempt to limit or alter 185 | the recipients' rights in the Source Code Form under this License. 186 | 187 | 3.3. Distribution of a Larger Work 188 | 189 | You may create and distribute a Larger Work under terms of Your choice, 190 | provided that You also comply with the requirements of this License for 191 | the Covered Software. If the Larger Work is a combination of Covered 192 | Software with a work governed by one or more Secondary Licenses, and the 193 | Covered Software is not Incompatible With Secondary Licenses, this 194 | License permits You to additionally distribute such Covered Software 195 | under the terms of such Secondary License(s), so that the recipient of 196 | the Larger Work may, at their option, further distribute the Covered 197 | Software under the terms of either this License or such Secondary 198 | License(s). 199 | 200 | 3.4. Notices 201 | 202 | You may not remove or alter the substance of any license notices 203 | (including copyright notices, patent notices, disclaimers of warranty, 204 | or limitations of liability) contained within the Source Code Form of 205 | the Covered Software, except that You may alter any license notices to 206 | the extent required to remedy known factual inaccuracies. 207 | 208 | 3.5. Application of Additional Terms 209 | 210 | You may choose to offer, and to charge a fee for, warranty, support, 211 | indemnity or liability obligations to one or more recipients of Covered 212 | Software. However, You may do so only on Your own behalf, and not on 213 | behalf of any Contributor. You must make it absolutely clear that any 214 | such warranty, support, indemnity, or liability obligation is offered by 215 | You alone, and You hereby agree to indemnify every Contributor for any 216 | liability incurred by such Contributor as a result of warranty, support, 217 | indemnity or liability terms You offer. You may include additional 218 | disclaimers of warranty and limitations of liability specific to any 219 | jurisdiction. 220 | 221 | 4. Inability to Comply Due to Statute or Regulation 222 | --------------------------------------------------- 223 | 224 | If it is impossible for You to comply with any of the terms of this 225 | License with respect to some or all of the Covered Software due to 226 | statute, judicial order, or regulation then You must: (a) comply with 227 | the terms of this License to the maximum extent possible; and (b) 228 | describe the limitations and the code they affect. Such description must 229 | be placed in a text file included with all distributions of the Covered 230 | Software under this License. Except to the extent prohibited by statute 231 | or regulation, such description must be sufficiently detailed for a 232 | recipient of ordinary skill to be able to understand it. 233 | 234 | 5. Termination 235 | -------------- 236 | 237 | 5.1. The rights granted under this License will terminate automatically 238 | if You fail to comply with any of its terms. However, if You become 239 | compliant, then the rights granted under this License from a particular 240 | Contributor are reinstated (a) provisionally, unless and until such 241 | Contributor explicitly and finally terminates Your grants, and (b) on an 242 | ongoing basis, if such Contributor fails to notify You of the 243 | non-compliance by some reasonable means prior to 60 days after You have 244 | come back into compliance. Moreover, Your grants from a particular 245 | Contributor are reinstated on an ongoing basis if such Contributor 246 | notifies You of the non-compliance by some reasonable means, this is the 247 | first time You have received notice of non-compliance with this License 248 | from such Contributor, and You become compliant prior to 30 days after 249 | Your receipt of the notice. 250 | 251 | 5.2. If You initiate litigation against any entity by asserting a patent 252 | infringement claim (excluding declaratory judgment actions, 253 | counter-claims, and cross-claims) alleging that a Contributor Version 254 | directly or indirectly infringes any patent, then the rights granted to 255 | You by any and all Contributors for the Covered Software under Section 256 | 2.1 of this License shall terminate. 257 | 258 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 259 | end user license agreements (excluding distributors and resellers) which 260 | have been validly granted by You or Your distributors under this License 261 | prior to termination shall survive termination. 262 | 263 | ************************************************************************ 264 | * * 265 | * 6. Disclaimer of Warranty * 266 | * ------------------------- * 267 | * * 268 | * Covered Software is provided under this License on an "as is" * 269 | * basis, without warranty of any kind, either expressed, implied, or * 270 | * statutory, including, without limitation, warranties that the * 271 | * Covered Software is free of defects, merchantable, fit for a * 272 | * particular purpose or non-infringing. The entire risk as to the * 273 | * quality and performance of the Covered Software is with You. * 274 | * Should any Covered Software prove defective in any respect, You * 275 | * (not any Contributor) assume the cost of any necessary servicing, * 276 | * repair, or correction. This disclaimer of warranty constitutes an * 277 | * essential part of this License. No use of any Covered Software is * 278 | * authorized under this License except under this disclaimer. * 279 | * * 280 | ************************************************************************ 281 | 282 | ************************************************************************ 283 | * * 284 | * 7. Limitation of Liability * 285 | * -------------------------- * 286 | * * 287 | * Under no circumstances and under no legal theory, whether tort * 288 | * (including negligence), contract, or otherwise, shall any * 289 | * Contributor, or anyone who distributes Covered Software as * 290 | * permitted above, be liable to You for any direct, indirect, * 291 | * special, incidental, or consequential damages of any character * 292 | * including, without limitation, damages for lost profits, loss of * 293 | * goodwill, work stoppage, computer failure or malfunction, or any * 294 | * and all other commercial damages or losses, even if such party * 295 | * shall have been informed of the possibility of such damages. This * 296 | * limitation of liability shall not apply to liability for death or * 297 | * personal injury resulting from such party's negligence to the * 298 | * extent applicable law prohibits such limitation. Some * 299 | * jurisdictions do not allow the exclusion or limitation of * 300 | * incidental or consequential damages, so this exclusion and * 301 | * limitation may not apply to You. * 302 | * * 303 | ************************************************************************ 304 | 305 | 8. Litigation 306 | ------------- 307 | 308 | Any litigation relating to this License may be brought only in the 309 | courts of a jurisdiction where the defendant maintains its principal 310 | place of business and such litigation shall be governed by laws of that 311 | jurisdiction, without reference to its conflict-of-law provisions. 312 | Nothing in this Section shall prevent a party's ability to bring 313 | cross-claims or counter-claims. 314 | 315 | 9. Miscellaneous 316 | ---------------- 317 | 318 | This License represents the complete agreement concerning the subject 319 | matter hereof. If any provision of this License is held to be 320 | unenforceable, such provision shall be reformed only to the extent 321 | necessary to make it enforceable. Any law or regulation which provides 322 | that the language of a contract shall be construed against the drafter 323 | shall not be used to construe this License against a Contributor. 324 | 325 | 10. Versions of the License 326 | --------------------------- 327 | 328 | 10.1. New Versions 329 | 330 | Mozilla Foundation is the license steward. Except as provided in Section 331 | 10.3, no one other than the license steward has the right to modify or 332 | publish new versions of this License. Each version will be given a 333 | distinguishing version number. 334 | 335 | 10.2. Effect of New Versions 336 | 337 | You may distribute the Covered Software under the terms of the version 338 | of the License under which You originally received the Covered Software, 339 | or under the terms of any subsequent version published by the license 340 | steward. 341 | 342 | 10.3. Modified Versions 343 | 344 | If you create software not governed by this License, and you want to 345 | create a new license for such software, you may create and use a 346 | modified version of this License if you rename the license and remove 347 | any references to the name of the license steward (except to note that 348 | such modified license differs from this License). 349 | 350 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 351 | Licenses 352 | 353 | If You choose to distribute Source Code Form that is Incompatible With 354 | Secondary Licenses under the terms of this version of the License, the 355 | notice described in Exhibit B of this License must be attached. 356 | 357 | Exhibit A - Source Code Form License Notice 358 | ------------------------------------------- 359 | 360 | This Source Code Form is subject to the terms of the Mozilla Public 361 | License, v. 2.0. If a copy of the MPL was not distributed with this 362 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 363 | 364 | If it is not possible or desirable to put the notice in a particular 365 | file, then You may include the notice in a location (such as a LICENSE 366 | file in a relevant directory) where a recipient would be likely to look 367 | for such a notice. 368 | 369 | You may add additional accurate notices of copyright ownership. 370 | 371 | Exhibit B - "Incompatible With Secondary Licenses" Notice 372 | --------------------------------------------------------- 373 | 374 | This Source Code Form is "Incompatible With Secondary Licenses", as 375 | defined by the Mozilla Public License, v. 2.0. 376 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION=v0.0.8 2 | REPOSITORY=hashicorpdemoapp/frontend 3 | 4 | build_docker: 5 | docker build -t ${REPOSITORY}:${VERSION} . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn Terraform - Preview Environments 2 | 3 | This is a companion repository to the "Create Preview Environments with Terraform and GitHub Actions" tutorial on [HashiCorp Learn](https://learn.hashicorp.com/tutorials/terraform/preview-environments-vercel). -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./src", 4 | "paths": { 5 | "@/*": ["../src/*"] 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | cloud { 3 | hostname = "app.terraform.io" 4 | organization = "hashicorp-training" 5 | workspaces { 6 | tags = ["hashicupsBackend"] 7 | } 8 | } 9 | 10 | required_providers { 11 | vercel = { 12 | source = "vercel/vercel" 13 | version = "0.2.0" 14 | } 15 | } 16 | } 17 | 18 | variable "is_prod" { 19 | description = "If false, deploys preview environment EC2 and LB" 20 | default = false 21 | } 22 | 23 | module "preview_env" { 24 | source = "./preview-env" 25 | is_prod = var.is_prod 26 | } 27 | 28 | output "lb_dns_name" { 29 | value = module.preview_env.lb_dns_name 30 | } 31 | 32 | output "preview_url" { 33 | value = module.preview_env.preview_url 34 | } 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "next dev -p 4001", 5 | "build": "next build", 6 | "start": "next start -p 4001" 7 | }, 8 | "dependencies": { 9 | "@apollo/client": "^3.5.8", 10 | "@hashicorp/flight-icons": "^2.0.1", 11 | "@tailwindcss/line-clamp": "^0.3.0", 12 | "axios": "^0.24.0", 13 | "flatted": "^3.2.4", 14 | "graphql": "^16.3.0", 15 | "miragejs": "^0.1.43", 16 | "next": "latest", 17 | "next-dark-mode": "^3.0.0", 18 | "next-themes": "^0.0.15", 19 | "react": "^17.0.2", 20 | "react-dom": "^17.0.2", 21 | "react-number-format": "^4.9.1", 22 | "react-scroll": "^1.8.4", 23 | "swr": "^1.1.2" 24 | }, 25 | "devDependencies": { 26 | "autoprefixer": "^10.4.0", 27 | "postcss": "^8.4.4", 28 | "tailwindcss": "^3.0.0" 29 | } 30 | } -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | // If you want to use other PostCSS plugins, see the following: 2 | // https://tailwindcss.com/docs/using-with-preprocessors 3 | module.exports = { 4 | plugins: { 5 | tailwindcss: {}, 6 | autoprefixer: {}, 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /preview-env/loadbalancer.tf: -------------------------------------------------------------------------------- 1 | resource "aws_lb" "app" { 2 | count = var.is_prod ? 0 : 1 3 | name = terraform.workspace 4 | internal = false 5 | load_balancer_type = "application" 6 | subnets = data.terraform_remote_state.shared.outputs.public_subnets 7 | security_groups = [data.terraform_remote_state.shared.outputs.hashicups_security_group_id] 8 | } 9 | 10 | resource "aws_lb_listener" "app" { 11 | count = var.is_prod ? 0 : 1 12 | load_balancer_arn = aws_lb.app[count.index].arn 13 | port = "443" 14 | protocol = "HTTPS" 15 | ssl_policy = "ELBSecurityPolicy-2016-08" 16 | certificate_arn = data.terraform_remote_state.shared.outputs.ssl_cert_arn 17 | 18 | default_action { 19 | type = "forward" 20 | target_group_arn = aws_lb_target_group.hashicups-backend[count.index].arn 21 | } 22 | } 23 | 24 | resource "aws_lb_target_group" "hashicups-backend" { 25 | count = var.is_prod ? 0 : 1 26 | name = terraform.workspace 27 | port = 8080 28 | protocol = "HTTP" 29 | vpc_id = data.terraform_remote_state.shared.outputs.vpc_id 30 | 31 | health_check { 32 | port = 8080 33 | protocol = "HTTP" 34 | timeout = 5 35 | interval = 10 36 | } 37 | } 38 | 39 | resource "aws_lb_target_group_attachment" "hashicups-backend" { 40 | count = var.is_prod ? 0 : 1 41 | target_group_arn = aws_lb_target_group.hashicups-backend[count.index].arn 42 | target_id = aws_instance.hashicups-backend[count.index].id 43 | port = 8080 44 | } -------------------------------------------------------------------------------- /preview-env/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | } 4 | 5 | data "terraform_remote_state" "shared" { 6 | backend = "remote" 7 | 8 | config = { 9 | organization = "hashicorp-training" 10 | workspaces = { 11 | name = "hcup-be-shared" 12 | } 13 | } 14 | } 15 | 16 | data "aws_ami" "ubuntu" { 17 | most_recent = true 18 | 19 | filter { 20 | name = "name" 21 | values = ["ubuntu/images/hvm-ssd/ubuntu-*20*-amd64-server-*"] 22 | } 23 | 24 | filter { 25 | name = "virtualization-type" 26 | values = ["hvm"] 27 | } 28 | 29 | owners = ["099720109477"] # Canonical 30 | } 31 | 32 | data "template_file" "user_data" { 33 | template = file("${path.module}/setup-hashicups.yaml") 34 | } 35 | 36 | resource "aws_instance" "hashicups-backend" { 37 | count = var.is_prod ? 0 : 1 38 | ami = data.aws_ami.ubuntu.id 39 | instance_type = "t2.micro" 40 | subnet_id = data.terraform_remote_state.shared.outputs.public_subnets[0] 41 | vpc_security_group_ids = [data.terraform_remote_state.shared.outputs.hashicups_security_group_id] 42 | associate_public_ip_address = true 43 | user_data = data.template_file.user_data.rendered 44 | 45 | tags = { 46 | Name = terraform.workspace 47 | } 48 | } -------------------------------------------------------------------------------- /preview-env/outputs.tf: -------------------------------------------------------------------------------- 1 | output "lb_dns_name" { 2 | value = length(aws_lb.app) > 0 ? "https://${aws_lb.app[0].dns_name}" : "" 3 | } 4 | 5 | output "public_ip" { 6 | value = length(aws_instance.hashicups-backend) > 0 ? "https://${aws_instance.hashicups-backend[0].public_ip}" : "" 7 | } 8 | 9 | output "preview_url" { 10 | value = vercel_deployment.frontend.url 11 | } -------------------------------------------------------------------------------- /preview-env/setup-hashicups.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | # Add groups to the system 3 | # Adds the ubuntu group with members 'root' and 'sys' 4 | # and the empty group hashicorp. 5 | groups: 6 | - ubuntu: [root, sys] 7 | - hashicorp 8 | 9 | # Add users to the system. Users are added after groups are added. 10 | users: 11 | - default 12 | - name: terraform 13 | gecos: terraform 14 | shell: /bin/bash 15 | primary_group: hashicorp 16 | sudo: ALL=(ALL) NOPASSWD:ALL 17 | groups: users, admin 18 | lock_passwd: false 19 | ssh_authorized_keys: 20 | - ssh-rsa AAAAHHHHHH 21 | 22 | # Clone repo and start hashicups backend 23 | runcmd: 24 | - sudo su terraform 25 | - cd /home/terraform 26 | - sudo apt-get update 27 | - sudo apt-get -y -qq install docker.io docker-compose git 28 | - git clone https://github.com/hashicorp-demoapp/hashicups-setups 29 | - cd hashicups-setups/docker-compose-backend-deployment 30 | - sudo docker-compose up -d 31 | -------------------------------------------------------------------------------- /preview-env/terraform.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | vercel = { 4 | source = "vercel/vercel" 5 | version = "0.2.0" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /preview-env/variables.tf: -------------------------------------------------------------------------------- 1 | variable "environment_tag" { 2 | description = "Environment tag" 3 | default = "Learn" 4 | } 5 | 6 | variable "region" { 7 | description = "The region Terraform deploys your instance" 8 | default = "us-east-2" 9 | } 10 | 11 | variable "is_prod" { 12 | description = "If false, deploys preview environment EC2 and LB" 13 | default = false 14 | } -------------------------------------------------------------------------------- /preview-env/vercel.tf: -------------------------------------------------------------------------------- 1 | data "vercel_project_directory" "frontend" { 2 | path = "." 3 | } 4 | 5 | locals { 6 | public_api_url = length(aws_lb.app) > 0 ? "https://${aws_lb.app[0].dns_name}" : "" 7 | } 8 | 9 | resource "vercel_deployment" "frontend" { 10 | project_id = data.terraform_remote_state.shared.outputs.vercel_project_id 11 | files = data.vercel_project_directory.frontend.files 12 | production = var.is_prod 13 | environment = { 14 | NEXT_PUBLIC_PUBLIC_API_URL = var.is_prod ? "" : local.public_api_url 15 | } 16 | } -------------------------------------------------------------------------------- /public/favicon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/favicon-120.png -------------------------------------------------------------------------------- /public/favicon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/favicon-152.png -------------------------------------------------------------------------------- /public/favicon-167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/favicon-167.png -------------------------------------------------------------------------------- /public/favicon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/favicon-180.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/favicon.ico -------------------------------------------------------------------------------- /public/images/boundary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/boundary.png -------------------------------------------------------------------------------- /public/images/card-amex.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | card-amex 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /public/images/card-mastercard.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | card-mastercard 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/images/card-visa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | card-visa 4 | 5 | 6 | 7 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /public/images/consul.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/consul.png -------------------------------------------------------------------------------- /public/images/demo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | demo 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /public/images/hashicorp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/hashicorp.png -------------------------------------------------------------------------------- /public/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Group 3 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /public/images/nomad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/nomad.png -------------------------------------------------------------------------------- /public/images/orders.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | orders 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /public/images/packer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/packer.png -------------------------------------------------------------------------------- /public/images/terraform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/terraform.png -------------------------------------------------------------------------------- /public/images/thumbnails/boundary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/thumbnails/boundary.png -------------------------------------------------------------------------------- /public/images/thumbnails/consul.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/thumbnails/consul.png -------------------------------------------------------------------------------- /public/images/thumbnails/hashicorp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/thumbnails/hashicorp.png -------------------------------------------------------------------------------- /public/images/thumbnails/nomad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/thumbnails/nomad.png -------------------------------------------------------------------------------- /public/images/thumbnails/packer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/thumbnails/packer.png -------------------------------------------------------------------------------- /public/images/thumbnails/terraform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/thumbnails/terraform.png -------------------------------------------------------------------------------- /public/images/thumbnails/vagrant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/thumbnails/vagrant.png -------------------------------------------------------------------------------- /public/images/thumbnails/vault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/thumbnails/vault.png -------------------------------------------------------------------------------- /public/images/thumbnails/waypoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/thumbnails/waypoint.png -------------------------------------------------------------------------------- /public/images/user.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/images/vagrant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/vagrant.png -------------------------------------------------------------------------------- /public/images/vault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/vault.png -------------------------------------------------------------------------------- /public/images/waypoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashicorp-education/learn-terraform-preview-environment/5b33bb8994e68db953a26b9c0b1ada189e1202e7/public/images/waypoint.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /src/components/Account.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useRef } from 'react' 2 | import { useRouter } from 'next/router' 3 | import Image from 'next/image' 4 | import NumberFormat from 'react-number-format' 5 | 6 | import Field from 'components/Field' 7 | import Orders from 'components/Orders' 8 | 9 | import ChevronsIcon from '@hashicorp/flight-icons/svg/chevrons-right-24.svg' 10 | import AvatarIcon from '@hashicorp/flight-icons/svg/user-circle-16.svg' 11 | import ErrorIcon from '@hashicorp/flight-icons/svg/alert-circle-16.svg' 12 | 13 | import { mutationFetcher } from 'gql/apolloClient'; 14 | import { SIGNUP_MUTATION, LOGIN_MUTATION, SIGNOUT_MUTATION } from 'gql/gqlMutations' 15 | 16 | export default function Account(props) { 17 | const router = useRouter(); 18 | 19 | const timer = useRef(null); 20 | 21 | const [isCreatingAccount, setIsCreatingAccount] = useState(false) 22 | const [signInFieldsComplete, setSignInFieldsComplete] = useState(false) 23 | const [signUpFieldsComplete, setSignUpFieldsComplete] = useState(false) 24 | 25 | const [hasErrors, setHasErrors] = useState(false) 26 | const [errorMessages, setErrorMessages] = useState(['']) 27 | 28 | const [username, setUsername] = useState(''); 29 | const [password, setPassword] = useState(''); 30 | const [confirmPassword, setConfirmPassword] = useState(''); 31 | 32 | const dismiss = async (event) => { 33 | setHasErrors(false) 34 | setErrorMessages(['']) 35 | props.setAccountVisible(false); 36 | }; 37 | 38 | const switchToNewAccount = async (event) => { 39 | setHasErrors(false) 40 | setErrorMessages(['']) 41 | setIsCreatingAccount(true); 42 | }; 43 | 44 | const switchToSignIn = async (event) => { 45 | setHasErrors(false) 46 | setErrorMessages(['']) 47 | setIsCreatingAccount(false); 48 | }; 49 | 50 | const signIn = async (event) => { 51 | event.preventDefault(); 52 | 53 | if (isCreatingAccount) { 54 | setHasErrors(false) 55 | 56 | // Create new account 57 | mutationFetcher({ 58 | mutation: SIGNUP_MUTATION, 59 | variables: { username, password } 60 | }).then(data => { 61 | props.setToken(data.data.signUp.token) 62 | props.setUsername(data.data.signUp.username) 63 | successfulAuth() 64 | }).catch(err => { 65 | setHasErrors(true) 66 | setErrorMessages([err]) 67 | }) 68 | } else { 69 | setHasErrors(false) 70 | 71 | // Sign into existing account 72 | mutationFetcher({ 73 | mutation: LOGIN_MUTATION, 74 | variables: { username, password } 75 | }).then(data => { 76 | props.setToken(data.data.login.token) 77 | props.setUsername(data.data.login.username) 78 | successfulAuth() 79 | }).catch(err => { 80 | setHasErrors(true) 81 | setErrorMessages([err]) 82 | }) 83 | } 84 | }; 85 | 86 | const successfulAuth = () => { 87 | setHasErrors(false) 88 | setErrorMessages(['']) 89 | 90 | if (router.pathname == '/checkout') { 91 | props.setAccountVisible(false) 92 | 93 | timer.current = setTimeout(() => { 94 | props.setIsAuthed(true); 95 | }, 500); 96 | } else { 97 | props.setIsAuthed(true); 98 | } 99 | } 100 | 101 | const signOut = async (event) => { 102 | event.preventDefault(); 103 | 104 | // Sign Out 105 | mutationFetcher({ 106 | mutation: SIGNOUT_MUTATION, 107 | }).then(data => { 108 | props.setToken('') 109 | props.setUsername('') 110 | props.setIsAuthed(false); 111 | }).catch(err => { 112 | setHasErrors(true) 113 | setErrorMessages([err]) 114 | }) 115 | }; 116 | 117 | useEffect(() => { 118 | if (username != "" && password != '') { 119 | setSignInFieldsComplete(true) 120 | } else { 121 | setSignInFieldsComplete(false) 122 | } 123 | 124 | if (username != "" && password != '' && confirmPassword != '') { 125 | setSignUpFieldsComplete(true) 126 | } else { 127 | setSignUpFieldsComplete(false) 128 | } 129 | }) 130 | 131 | useEffect(() => { 132 | return () => clearTimeout(timer.current); 133 | }, []); 134 | 135 | return ( 136 | <> 137 |
138 | 139 |
140 | 141 |
142 | {props.isAuthed ? ( 143 | <> 144 |

Your account

145 |
146 |

Signed in as {props.username}

147 | 148 |
149 | 150 | ) : ( 151 | <> 152 | {isCreatingAccount ? ( 153 | <>

Create account

154 |

Already have an account?

155 | 156 | ) : ( 157 | <> 158 |

Sign in

159 |

Or create a

160 | 161 | )} 162 | 163 | )} 164 |
165 | 166 |
167 | {props.isAuthed ? ( 168 | <> 169 | 170 | 171 | ) : ( 172 |
173 | {hasErrors && errorMessages.map((error, index) => ( 174 |
175 | 176 |

{error.message}

177 |
178 | ))} 179 | 180 | {isCreatingAccount ? ( 181 | <> 182 |
183 | 184 |
185 |
186 | 187 |
188 |
189 | 190 |
191 | 192 | 193 | 194 | ) : ( 195 | <> 196 |
197 | 198 |
199 |
200 | 201 |
202 | 203 | 204 | 205 | )} 206 | 207 | )} 208 |
209 | 210 | 213 |
214 | 215 | ) 216 | } 217 | 218 | function SignInButton(props) { 219 | 220 | return ( 221 | 228 | ) 229 | } -------------------------------------------------------------------------------- /src/components/Cart.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | import { useState } from 'react' 3 | import NumberFormat from 'react-number-format' 4 | 5 | import CheckoutButton from 'components/CheckoutButton' 6 | 7 | import CheckIcon from '@hashicorp/flight-icons/svg/check-circle-16.svg' 8 | import FailIcon from '@hashicorp/flight-icons/svg/x-square-16.svg' 9 | 10 | export default function Cart(props) { 11 | const removeItemFromCart = (coffeeID) => { 12 | delete props.cart[coffeeID] 13 | 14 | if (props.onRemoveItem != undefined) { 15 | props.onRemoveItem() 16 | } 17 | 18 | if (props.isSticky && Object.keys(props.cart).length === 0) { 19 | props.setCartVisible(false) 20 | } 21 | 22 | // Refreshes cart 23 | props.setCart({ ...props.cart }) 24 | }; 25 | 26 | return ( 27 | <> 28 | {props.isSticky ? ( 29 |
30 |
31 |
32 | {props.cart && Object.keys(props.cart).length !== 0 ? ( 33 |
34 | 35 |
36 | ) : ( 37 |

No items in your cart

38 | )} 39 | 40 | 41 |
42 |
43 |
44 | ) : ( 45 |
46 | {props.cart && Object.keys(props.cart).length !== 0 ? ( 47 | 48 | ) : ( 49 |

No items in your cart

50 | )} 51 |
52 | )} 53 | 54 | ) 55 | } 56 | 57 | function CartItems(props) { 58 | return ( 59 | <> 60 | 65 | 66 | ) 67 | } 68 | 69 | function CartItem(props) { 70 | function handleClick(event) { 71 | props.removeItemFromCart(props.coffee.id) 72 | } 73 | 74 | return ( 75 |
  • 76 |
    77 |
    78 | {props.count > 2 && ( 79 | 80 | )} 81 | {props.count > 1 && ( 82 | 83 | )} 84 | 85 |
    86 | {props.count} 87 |
    88 |
    89 | {props.coffee.name} 90 | 91 | 92 |
    93 |
  • 94 | ) 95 | } -------------------------------------------------------------------------------- /src/components/CartButton.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | export default function CartButton(props) { 4 | const isVault = props.id == 3 5 | 6 | return ( 7 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /src/components/CheckoutButton.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useRouter } from 'next/router' 3 | import Image from 'next/image' 4 | 5 | import ChevronsIcon from '@hashicorp/flight-icons/svg/chevrons-right-24.svg' 6 | 7 | export default function CheckoutButton(props) { 8 | const router = useRouter() 9 | 10 | const handleClick = async (event) => { 11 | router.push("/checkout") 12 | }; 13 | 14 | return ( 15 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /src/components/CoffeeMenu.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import Scroll from 'react-scroll' 3 | import { queryFetcher } from 'gql/apolloClient'; 4 | import { ALL_COFFEES_QUERY } from 'gql/gqlQueries'; 5 | 6 | import useSWR from 'swr' 7 | import Link from 'next/link' 8 | import Image from 'next/image' 9 | 10 | import ErrorIcon from '@hashicorp/flight-icons/svg/alert-triangle-24.svg' 11 | 12 | var Element = Scroll.Element 13 | var scroller = Scroll.scroller 14 | 15 | export default function CoffeeMenu(props) { 16 | const fetcher = async (url) => await axios.get(url).then((res) => res.data); 17 | const { data, error } = useSWR(ALL_COFFEES_QUERY, queryFetcher); 18 | 19 | // If data exits, set to coffees object 20 | let coffees; 21 | if (data) coffees = data.data.coffees 22 | 23 | const activeItem = 'coffee-' + props.isActive 24 | 25 | useEffect(() => { 26 | if (coffees) { 27 | scroller.scrollTo(activeItem, { 28 | duration: 500, 29 | delay: 50, 30 | offset: -120, 31 | smooth: true, 32 | horizontal: true, 33 | containerId: 'containerElement', 34 | }) 35 | } 36 | }) 37 | 38 | return ( 39 | <> 40 | {props.isHero == true ? ( 41 | <> 42 | {coffees ? ( 43 | 48 | ) : ( 49 |
    50 | {error ? ( 51 |
    52 | 53 |

    Unable to query all coffees.

    54 |

    Check the console for error messages.

    55 |
    56 | ) : ( 57 |
  • 58 | 59 |
  • 60 | )} 61 |
    62 | )} 63 | 64 | ) : ( 65 | 90 | )} 91 | 92 | ) 93 | } 94 | 95 | function CoffeeMenuItem(props) { 96 | const activeState = props.coffee.id == props.isActive 97 | 98 | return ( 99 | <> 100 | {props.isInHero == true ? ( 101 |
  • 102 | 103 | 104 | 105 | {`${props.coffee.name} `} 106 | 107 | 108 |
  • 109 | ) : ( 110 |
  • 111 | 112 | 113 |
    114 | 115 |
    116 | {`${props.coffee.name} `} 117 | 118 |
    119 | 120 |
  • 121 | )} 122 | 123 | ); 124 | } -------------------------------------------------------------------------------- /src/components/Field.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | import NumberFormat from 'react-number-format' 3 | 4 | export default function Field(props) { 5 | const [isFocused, setIsFocused] = useState(false); 6 | const isDirty = props.value !== '' 7 | 8 | const onFocus = async (event) => { 9 | setIsFocused(true); 10 | }; 11 | 12 | const onBlur = async (event) => { 13 | if (props.value == '') { 14 | setIsFocused(false); 15 | } 16 | }; 17 | 18 | const onChange = async (event) => { 19 | const currentValue = event.target.value 20 | props.setter(currentValue); 21 | }; 22 | 23 | return ( 24 |
    25 | 26 | 27 |
    28 | ) 29 | } 30 | 31 | function Input(props) { 32 | let format; 33 | let content; 34 | 35 | if (props.type == 'cardnumber') { 36 | format = "#### #### #### ####" 37 | } else if (props.type == 'cardexpiry') { 38 | format = "##/####" 39 | } else { 40 | format = "####" 41 | } 42 | 43 | if (props.type != 'text' && props.type != 'password') { 44 | content = 54 | } else { 55 | content = 65 | } 66 | 67 | return content; 68 | } 69 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import Image from 'next/image' 3 | 4 | import Theme from 'components/Theme' 5 | 6 | import InfoIcon from '@hashicorp/flight-icons/svg/info-16.svg' 7 | import DocsIcon from '@hashicorp/flight-icons/svg/docs-link-16.svg' 8 | import LearnIcon from '@hashicorp/flight-icons/svg/learn-link-16.svg' 9 | import GitHubIcon from '@hashicorp/flight-icons/svg/github-16.svg' 10 | import GlobeIcon from '@hashicorp/flight-icons/svg/globe-16.svg' 11 | 12 | export default function Footer() { 13 | 14 | return ( 15 | 39 | ) 40 | } 41 | 42 | function ExternalLink(props) { 43 | return ( 44 |
  • 45 | 46 | 47 | 48 | {props.label} 49 | 50 | 51 |
  • 52 | ) 53 | } 54 | 55 | function Copyright() { 56 | let newDate = new Date() 57 | let year = newDate.getFullYear(); 58 | 59 | return `© ${year} HashiCorp` 60 | } -------------------------------------------------------------------------------- /src/components/Header.js: -------------------------------------------------------------------------------- 1 | import Head from 'next/head' 2 | import Image from 'next/image' 3 | import Link from 'next/link' 4 | 5 | 6 | import Account from 'components/Account' 7 | import { useState } from 'react' 8 | 9 | export default function Header(props) { 10 | 11 | const showAccount = async (event) => { 12 | props.setAccountVisible(true); 13 | }; 14 | 15 | return ( 16 | <> 17 | 18 | HashiCups - Demo App 19 | 20 | 25 | 30 | 35 | 40 | 41 | 42 |
    43 |
    44 |
    45 | 46 | 47 | 48 | 49 | 50 |
    51 | 57 |
    58 |
    59 |
    60 | 61 |
    62 |
    63 | 64 | 65 | 66 | ) 67 | } 68 | -------------------------------------------------------------------------------- /src/components/Orders.js: -------------------------------------------------------------------------------- 1 | import useSWR from 'swr' 2 | import Link from 'next/link' 3 | import Image from 'next/image' 4 | import NumberFormat from 'react-number-format' 5 | 6 | import CheckIcon from '@hashicorp/flight-icons/svg/check-circle-16.svg' 7 | import FailIcon from '@hashicorp/flight-icons/svg/x-square-16.svg' 8 | 9 | import { queryFetcher } from 'gql/apolloClient'; 10 | import { ALL_ORDERS_QUERY } from 'gql/gqlQueries'; 11 | 12 | export default function Orders(props) { 13 | const { data, error } = useSWR(ALL_ORDERS_QUERY, queryFetcher); 14 | 15 | // If data exists, set to coffees object 16 | let orders; 17 | if (data) orders = data.data.orders 18 | 19 | return ( 20 | <> 21 |

    Order history

    22 | 23 |
    24 | {orders ? ( 25 |
      26 | {orders.map((order) => ( 27 | 28 | ))} 29 |
    30 | ) : ( 31 |
    32 |

    No orders placed yet

    33 |
    34 | )} 35 |
    36 | 37 | ) 38 | } 39 | 40 | function Order(props) { 41 | const orderClick = async (event) => { 42 | props.setAccountVisible(false) 43 | } 44 | 45 | const total = props.items.reduce((t, next) => { 46 | return t + (next.coffee.price * next.quantity) 47 | }, 0) 48 | 49 | return ( 50 |
  • 51 | 52 | 53 |
    54 |
    55 | {props.items.map((item) => ( 56 | 57 | ))} 58 |
    59 |
    60 |
    61 | 62 |
    63 |
    64 | 65 | 66 | Order #{props.id} 67 | 68 | 69 | 70 |
    71 | 72 |
      73 | {props.items.map((item) => ( 74 |
    • 75 | {item.quantity} x {item.coffee.name} 76 | 77 |
    • 78 | ))} 79 |
    80 | 81 | {/*

    82 | {props.status.state == "success" ? ( 83 | 84 | ) : ( 85 | 86 | )} 87 | {props.status.message} 88 |

    */} 89 | 90 | {/*

    91 | {props.encryption.state == "success" ? ( 92 | 93 | ) : ( 94 | 95 | )} 96 | {props.encryption.message} 97 |

    */} 98 | 99 | {/*
    100 |

    Plain text card number

    101 | 102 |
    */} 103 |
    104 |
  • 105 | ) 106 | } -------------------------------------------------------------------------------- /src/components/PaymentForm.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { useRouter } from 'next/router' 3 | import Image from 'next/image' 4 | import NumberFormat from 'react-number-format' 5 | 6 | 7 | import Field from 'components/Field' 8 | import Radio from 'components/Radio' 9 | 10 | import ChevronsIcon from '@hashicorp/flight-icons/svg/chevrons-right-24.svg' 11 | import CheckIcon from '@hashicorp/flight-icons/svg/check-circle-24.svg' 12 | import FailIcon from '@hashicorp/flight-icons/svg/x-square-24.svg' 13 | 14 | import { mutationFetcher } from 'gql/apolloClient' 15 | import { CREATE_ORDER_MUTATION, SUBMIT_PAYMENT_MUTATION } from 'gql/gqlMutations' 16 | import { order } from 'tailwindcss/defaultTheme' 17 | 18 | export default function PaymentForm(props) { 19 | const router = useRouter(); 20 | 21 | const [hasAutofilled, setHasAutofilled] = useState(false); 22 | 23 | const [visaSelected, setVisaSelected] = useState(true); 24 | const [mastercardSelected, setMastercardSelected] = useState(false); 25 | const [amexSelected, setAmexSelected] = useState(false); 26 | 27 | const [cardholderName, setCardholderName] = useState(''); 28 | const [cardNumber, setCardNumber] = useState(''); 29 | const [expiryDate, setExpiryDate] = useState(''); 30 | const [cvcNumber, setCvcNumber] = useState(''); 31 | 32 | const [_, setOrderID] = useState(0); 33 | 34 | const [hasErrors, setHasErrors] = useState(false) 35 | const [errorMessages, setErrorMessages] = useState(['']) 36 | 37 | const formComplete = cardholderName != "" && cardNumber != "" && expiryDate != "" && cvcNumber != ""; 38 | 39 | let total = 0 40 | let cart = {} 41 | if (typeof window !== "undefined") { 42 | if (localStorage.getItem("cart")) cart = JSON.parse(localStorage.getItem("cart")) 43 | total = Object.values(cart).reduce((t, next) => { 44 | return t + (next.coffee.price * next.quantity) 45 | }, 0) 46 | } 47 | 48 | let orders = {} 49 | if (localStorage.getItem("orders")) orders = JSON.parse(localStorage.getItem("orders")) 50 | 51 | const submit = async (event) => { 52 | event.preventDefault(); 53 | 54 | let orderItems = [] 55 | 56 | for (const coffeeID in cart) { 57 | const item = cart[coffeeID] 58 | orderItems.push({ coffee: { id: item.coffee.id }, quantity: item.quantity }) 59 | } 60 | 61 | mutationFetcher({ 62 | mutation: CREATE_ORDER_MUTATION, 63 | variables: { orderItems } 64 | }).then(async (data) => { 65 | const orderID = data.data.order.id 66 | 67 | // Process payment 68 | const pay = await submitPayment() 69 | orders[orderID] = pay 70 | localStorage.setItem("orders", JSON.stringify(orders)) 71 | 72 | setOrderID(orderID) 73 | 74 | // Clear cart 75 | localStorage.removeItem("cart") 76 | 77 | // Go to order page 78 | router.push(`/order/${orderID}`) 79 | }).catch(err => { 80 | setHasErrors(true) 81 | setErrorMessages([err]) 82 | }) 83 | }; 84 | 85 | const submitPayment = async () => { 86 | // Set cardtype 87 | let cardType = "Visa" 88 | if (mastercardSelected) cardType = "Mastercard" 89 | if (amexSelected) cardType = "AmericanExpress" 90 | 91 | return mutationFetcher({ 92 | mutation: SUBMIT_PAYMENT_MUTATION, 93 | variables: { 94 | name: cardholderName, 95 | cardType, 96 | cardNumber, 97 | expiryDate, 98 | cvc: cvcNumber, 99 | amount: total, 100 | } 101 | }).then(data => { 102 | return data.data.pay 103 | }).catch(err => { 104 | setHasErrors(true) 105 | setErrorMessages([err]) 106 | }) 107 | } 108 | 109 | const autofill = async (event) => { 110 | setCardholderName('A. Customer'); 111 | setCardNumber('1234123412341234'); 112 | setExpiryDate('122030'); 113 | if (amexSelected) { 114 | setCvcNumber('1234'); 115 | } else { 116 | setCvcNumber('123'); 117 | } 118 | event.preventDefault(); 119 | }; 120 | 121 | const onCardChange = async (event) => { 122 | const selectedRadio = event.target.id 123 | if (selectedRadio == 'card-visa') { 124 | setVisaSelected(true) 125 | setMastercardSelected(false) 126 | setAmexSelected(false) 127 | } else if (selectedRadio == 'card-mastercard') { 128 | setVisaSelected(false) 129 | setMastercardSelected(true) 130 | setAmexSelected(false) 131 | } else if (selectedRadio == 'card-amex') { 132 | setVisaSelected(false) 133 | setMastercardSelected(false) 134 | setAmexSelected(true) 135 | } 136 | }; 137 | 138 | return ( 139 |
    140 |
    141 |

    Make payment

    142 |

    Use any card details or . No payment will be taken.

    143 |
    144 | 145 |
    146 |
      147 | 148 | 149 | 150 |
    151 |
    152 | 153 |
    154 | 155 |
    156 | 157 |
    158 | 159 |
    160 | 161 |
    162 | 163 | 164 |
    165 | 166 | 167 | 168 | ) 169 | } 170 | 171 | function SubmitButton(props) { 172 | return ( 173 | 180 | ) 181 | } -------------------------------------------------------------------------------- /src/components/Radio.js: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | 3 | 4 | export default function Radio(props) { 5 | 6 | return ( 7 |
  • 8 | 12 | 13 |
  • 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /src/components/Theme.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | import { useTheme } from 'next-themes' 3 | import { useDarkMode } from 'next-dark-mode' 4 | import Image from 'next/image' 5 | 6 | 7 | import MonitorIcon from '@hashicorp/flight-icons/svg/monitor-16.svg' 8 | import SunIcon from '@hashicorp/flight-icons/svg/sun-16.svg' 9 | import MoonIcon from '@hashicorp/flight-icons/svg/moon-16.svg' 10 | 11 | import CaretIcon from '@hashicorp/flight-icons/svg/caret-16.svg' 12 | import CheckIcon from '@hashicorp/flight-icons/svg/check-16.svg' 13 | 14 | export default function Theme() { 15 | const { theme, setTheme } = useTheme() 16 | 17 | const [mounted, setMounted] = useState(false) 18 | const [isShowingSettings, setIsShowingSettings] = useState(false) 19 | 20 | const { 21 | autoModeActive, 22 | autoModeSupported, 23 | darkModeActive, 24 | switchToAutoMode, 25 | switchToDarkMode, 26 | switchToLightMode, 27 | } = useDarkMode() 28 | 29 | useEffect(() => { 30 | if (theme == 'autoDark' || theme == 'autoLight') { 31 | if (darkModeActive) { 32 | switchToDarkMode 33 | setTheme('autoDark') 34 | } else { 35 | switchToLightMode 36 | setTheme('autoLight') 37 | } 38 | } 39 | }) 40 | 41 | function switchThemeToLight() { 42 | switchToLightMode 43 | setIsShowingSettings(false) 44 | setTheme('light') 45 | } 46 | 47 | function switchThemeToDark() { 48 | switchToDarkMode 49 | setIsShowingSettings(false) 50 | setTheme('dark') 51 | } 52 | 53 | function switchThemeToAuto() { 54 | switchToAutoMode 55 | setIsShowingSettings(false) 56 | if (darkModeActive) { 57 | setTheme('autoDark') 58 | } else { 59 | setTheme('autoLight') 60 | } 61 | } 62 | 63 | function showSettings() { 64 | if (isShowingSettings) { 65 | setIsShowingSettings(false) 66 | } else { 67 | setIsShowingSettings(true) 68 | } 69 | } 70 | 71 | const dismiss = async (event) => { 72 | setIsShowingSettings(false); 73 | }; 74 | 75 | useEffect(() => setMounted(true), []) 76 | 77 | if (!mounted) return null 78 | 79 | return ( 80 |
    81 | 103 | 104 |
    105 | 106 |
    107 |
      108 |
    • Choose theme
    • 109 |
    • switchThemeToAuto()}> 110 | 111 |
    • 112 |
    • switchThemeToLight()}> 113 | 114 |
    • 115 |
    • switchThemeToDark()}> 116 | 117 |
    • 118 |
    119 |
    120 |
    121 | ) 122 | } 123 | 124 | function ThemeButton(props) { 125 | let isActive 126 | 127 | if (props.label == 'System') { 128 | isActive = (props.theme == 'system' || props.theme == 'autoDark' || props.theme == 'autoLight') 129 | } else if (props.label == 'Light') { 130 | isActive = props.theme == 'light' 131 | } else { 132 | isActive = props.theme == 'dark' 133 | } 134 | 135 | return ( 136 | 141 | ) 142 | } -------------------------------------------------------------------------------- /src/gql/apolloClient.js: -------------------------------------------------------------------------------- 1 | import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; 2 | import { setContext } from '@apollo/client/link/context'; 3 | 4 | let publicApiUrl = "http://localhost:8080" 5 | 6 | if (process.env.NEXT_PUBLIC_PUBLIC_API_URL) { 7 | publicApiUrl = process.env.NEXT_PUBLIC_PUBLIC_API_URL 8 | } 9 | 10 | const httpLink = createHttpLink({ 11 | uri: `${publicApiUrl}/api`, 12 | }) 13 | 14 | console.log(`API: ${publicApiUrl}`) 15 | 16 | const authLink = setContext((_, { headers }) => { 17 | const token = JSON.parse(localStorage.getItem('token')) 18 | return { 19 | headers: { 20 | ...headers, 21 | Authorization: token ? `${token}` : "", 22 | } 23 | } 24 | }) 25 | 26 | const client = new ApolloClient({ 27 | link: authLink.concat(httpLink), 28 | cache: new InMemoryCache() 29 | }) 30 | 31 | const queryFetcher = async (query) => await client.query({ query: query }); 32 | const queryVarFetcher = async (q) => await client.query({ 33 | query: q.query, 34 | variables: q.variables 35 | }); 36 | const mutationFetcher = async (q) => await client.mutate({ 37 | mutation: q.mutation, 38 | variables: q.variables 39 | }); 40 | 41 | export { 42 | client, 43 | queryFetcher, 44 | queryVarFetcher, 45 | mutationFetcher 46 | }; 47 | -------------------------------------------------------------------------------- /src/gql/gqlMutations.js: -------------------------------------------------------------------------------- 1 | import gql from 'graphql-tag'; 2 | 3 | const SIGNUP_MUTATION = gql` 4 | mutation SignUp($username: String!, $password: String!) { 5 | signUp(auth:{ 6 | username: $username 7 | password: $password 8 | }) { 9 | userId 10 | username 11 | token 12 | } 13 | } 14 | ` 15 | 16 | const LOGIN_MUTATION = gql` 17 | mutation LogIn($username: String!, $password: String!) { 18 | login(auth:{ 19 | username: $username 20 | password: $password 21 | }) { 22 | userId 23 | username 24 | token 25 | } 26 | } 27 | ` 28 | 29 | const SIGNOUT_MUTATION = gql` 30 | mutation SignOut { 31 | signOut 32 | } 33 | ` 34 | 35 | const SUBMIT_PAYMENT_MUTATION = gql` 36 | mutation SubmitPayment($name: String!, $cardType: String!, $cardNumber: String!, $expiryDate: String!, $cvc: Int!, $amount: Float!) { 37 | pay(details: { 38 | name: $name, 39 | type: $cardType, 40 | number: $cardNumber, 41 | expiry: $expiryDate, 42 | cv2: $cvc, 43 | amount: $amount, 44 | }) { 45 | id, 46 | card_plaintext, 47 | card_ciphertext, 48 | message 49 | } 50 | } 51 | ` 52 | 53 | const CREATE_ORDER_MUTATION = gql` 54 | mutation CreateOrder($orderItems: [OrderItemInput!]){ 55 | order(items: $orderItems) { 56 | id, 57 | items { 58 | coffee { id, name, price } 59 | quantity 60 | } 61 | } 62 | } 63 | ` 64 | 65 | export { 66 | SIGNUP_MUTATION, 67 | LOGIN_MUTATION, 68 | SIGNOUT_MUTATION, 69 | SUBMIT_PAYMENT_MUTATION, 70 | CREATE_ORDER_MUTATION 71 | }; 72 | -------------------------------------------------------------------------------- /src/gql/gqlQueries.js: -------------------------------------------------------------------------------- 1 | import gql from 'graphql-tag'; 2 | 3 | const ALL_COFFEES_QUERY = gql` 4 | query GetCoffees { 5 | 6 | coffees { 7 | id 8 | name 9 | image 10 | } 11 | } 12 | ` 13 | 14 | const COFFEE_QUERY = gql` 15 | query GetCoffee($coffeeID: String!) { 16 | coffee(id: $coffeeID) { 17 | id 18 | name 19 | image 20 | teaser 21 | collection 22 | origin 23 | color 24 | price 25 | } 26 | } 27 | `; 28 | 29 | const COFFEE_IMG_QUERY = gql` 30 | query GetCoffee($coffeeID: String!) { 31 | coffee(id: $coffeeID) { 32 | image 33 | } 34 | } 35 | `; 36 | 37 | const COFFEE_INGREDIENTS_QUERY = gql` 38 | query GetCoffeeIngredients($coffeeID: String!) { 39 | coffeeIngredients(coffeeID: $coffeeID) { 40 | unit 41 | quantity 42 | name 43 | } 44 | } 45 | `; 46 | 47 | const ALL_ORDERS_QUERY = gql` 48 | query GetAllOrders { 49 | orders { 50 | id 51 | items { 52 | coffee { name, price, image } 53 | quantity 54 | } 55 | } 56 | } 57 | `; 58 | 59 | const ORDER_QUERY = gql` 60 | query GetOrder($orderID: String!) { 61 | order(id: $orderID) { 62 | id 63 | items { 64 | coffee { name, price, image } 65 | quantity 66 | } 67 | } 68 | } 69 | `; 70 | 71 | export { 72 | ALL_COFFEES_QUERY, 73 | COFFEE_QUERY, 74 | COFFEE_IMG_QUERY, 75 | COFFEE_INGREDIENTS_QUERY, 76 | ALL_ORDERS_QUERY, 77 | ORDER_QUERY 78 | }; 79 | -------------------------------------------------------------------------------- /src/pages/_app.js: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | import { useState, useEffect } from 'react' 3 | import { ThemeProvider } from 'next-themes' 4 | import withDarkMode from 'next-dark-mode' 5 | 6 | import useLocalStorage from "../useLocalStorage"; 7 | 8 | function MyApp({ Component, pageProps }) { 9 | const [username, setUsername] = useLocalStorage("username", ''); 10 | const [token, setToken] = useLocalStorage("token", ''); 11 | const [isAuthed, setIsAuthed] = useLocalStorage("isAuthed", false); 12 | const [cart, setCart] = useLocalStorage("cart", {}); 13 | const [cartVisible, setCartVisible] = useState(false); 14 | const [accountVisible, setAccountVisible] = useState(false); 15 | 16 | useEffect(() => { 17 | if (cart && Object.keys(cart).length !== 0) { 18 | setCartVisible(true) 19 | } else { 20 | setCartVisible(false) 21 | } 22 | }) 23 | 24 | return ( 25 | 26 | 40 | 41 | ) 42 | } 43 | 44 | export default withDarkMode(MyApp) 45 | -------------------------------------------------------------------------------- /src/pages/checkout.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { useRouter } from 'next/router' 3 | import Image from 'next/image' 4 | import NumberFormat from 'react-number-format' 5 | 6 | 7 | import Header from 'components/Header' 8 | import Footer from 'components/Footer' 9 | import CoffeeMenu from 'components/CoffeeMenu' 10 | import Cart from 'components/Cart' 11 | import PaymentForm from 'components/PaymentForm' 12 | 13 | import ChevronsIcon from '@hashicorp/flight-icons/svg/chevrons-right-24.svg' 14 | import AvatarIcon from '@hashicorp/flight-icons/svg/user-circle-16.svg' 15 | 16 | export default function Checkout(props) { 17 | const router = useRouter(); 18 | 19 | const [_, setTotal] = useState("") 20 | 21 | let total = 0 22 | if (typeof window !== "undefined") { 23 | total = Object.values(props.cart).reduce((t, next) => { 24 | return t + (next.coffee.price * next.quantity) 25 | }, 0) 26 | } 27 | 28 | const getTotal = () => { 29 | total = Object.values(props.cart).reduce((t, next) => { 30 | return t + (next.coffee.price * next.quantity) 31 | }, 0) 32 | setTotal(total) 33 | } 34 | 35 | const dismiss = async (event) => { 36 | router.back() 37 | } 38 | 39 | const signIn = async (event) => { 40 | props.setAccountVisible(true) 41 | } 42 | 43 | const signOut = async (event) => { 44 | props.setToken('') 45 | props.setUsername('') 46 | props.setIsAuthed(false) 47 | } 48 | 49 | return ( 50 |
    51 |
    52 | 53 |
    54 |
    55 |
    56 |

    Checkout

    57 |

    Review and pay for your order (except not really)

    58 |
    59 | 60 | 63 |
    64 | 65 |
    66 | 67 | 68 | {props.cart && ( 69 |
    70 |

    Total to pay

    71 |

    72 |
    73 | )} 74 |
    75 | 76 | {props.cart && Object.keys(props.cart).length !== 0 && ( 77 | <> 78 |
    79 | {props.isAuthed ? ( 80 |
    81 |

    82 | Signed in as 83 | 84 | 85 | {props.username} 86 | 87 |

    88 | 89 |
    90 | ) : ( 91 | 98 | )} 99 | 100 |
    101 | 102 | {props.isAuthed && ( 103 |
    104 | 105 |
    106 | )} 107 | 108 | )} 109 |
    110 | 111 |
    112 |
    113 | ) 114 | } 115 | -------------------------------------------------------------------------------- /src/pages/coffee/[id].js: -------------------------------------------------------------------------------- 1 | import useSWR from 'swr' 2 | import Link from 'next/link' 3 | import Image from 'next/image' 4 | import { useRouter } from 'next/router' 5 | import { useState, useEffect } from 'react' 6 | import NumberFormat from 'react-number-format' 7 | 8 | import Header from 'components/Header' 9 | import Footer from 'components/Footer' 10 | import CoffeeMenu from 'components/CoffeeMenu' 11 | import CartButton from 'components/CartButton' 12 | import Cart from 'components/Cart' 13 | 14 | import PrevIcon from '@hashicorp/flight-icons/svg/chevron-left-24.svg' 15 | import NextIcon from '@hashicorp/flight-icons/svg/chevron-right-24.svg' 16 | import MinusIcon from '@hashicorp/flight-icons/svg/minus-circle-24.svg' 17 | import PlusIcon from '@hashicorp/flight-icons/svg/plus-circle-24.svg' 18 | import ErrorIcon from '@hashicorp/flight-icons/svg/alert-triangle-24.svg' 19 | 20 | import { queryVarFetcher } from 'gql/apolloClient'; 21 | import { COFFEE_QUERY, COFFEE_IMG_QUERY, COFFEE_INGREDIENTS_QUERY } from 'gql/gqlQueries'; 22 | 23 | export default function Coffee(props) { 24 | const router = useRouter(); 25 | const { id } = router.query 26 | 27 | const prev_id = id - 1 28 | const next_id = parseInt(id) + 1 29 | 30 | const [amount, setAmount] = useState(1) 31 | 32 | const incCoffeeCount = () => { 33 | const count = amount; 34 | if (count <= 10) { 35 | setAmount(count + 1) 36 | } 37 | }; 38 | 39 | const decCoffeeCount = () => { 40 | const count = amount; 41 | if (count > 1) { 42 | setAmount(count - 1) 43 | } 44 | }; 45 | 46 | const { data, error } = useSWR({ 47 | query: COFFEE_QUERY, 48 | variables: { coffeeID: String(id) } 49 | }, queryVarFetcher); 50 | 51 | // If data exists, set to coffee object 52 | let coffee; 53 | if (data) coffee = data.data.coffee 54 | 55 | const { data: idata, error: ierror } = useSWR({ 56 | query: COFFEE_INGREDIENTS_QUERY, 57 | variables: { coffeeID: String(id) } 58 | }, queryVarFetcher); 59 | 60 | // If data exists, set to coffee object 61 | let ingredients; 62 | if (idata) ingredients = idata.data.coffeeIngredients 63 | 64 | const addToCart = async (event) => { 65 | props.cart[id] = { 66 | coffee: coffee, 67 | quantity: amount, 68 | } 69 | 70 | // Refreshes cart 71 | props.setCart({ ...props.cart }); 72 | 73 | // Show cart 74 | props.setCartVisible(true) 75 | }; 76 | 77 | useEffect(() => { 78 | setAmount(1) 79 | }, [router.asPath]) 80 | 81 | return ( 82 |
    83 |
    84 | 85 | 86 | 87 |
    88 | 89 | 90 | 91 |
    92 | {coffee ? ( 93 | <> 94 | 97 | 98 |
    99 | 100 |
    101 |
    102 |

    {coffee.name}

    103 |

    {coffee.teaser}

    104 |
    105 | 106 |
    107 |
    108 |
    Collection
    109 |
    {coffee.collection}
    110 |
    Origin
    111 |
    {coffee.origin}
    112 |
    Ingredients
    113 |
    114 | {ingredients && ingredients.map((ingredient, index) => ( 115 | {`${ingredient.quantity}${ingredient.unit} ${ingredient.name} `} 116 | ))} 117 |
    118 |
    119 |
    120 |
    121 | 122 |
    123 |

    124 | 125 | 126 | 127 | 128 | 129 |

    130 | 131 |
    132 | 133 |
    134 | 135 | ) : ( 136 |
    137 | {error ? ( 138 |
    139 | 140 |

    Unable to query the selected coffee.

    141 |

    Check the console for error messages.

    142 |
    143 | ) : ( 144 |
    145 | 146 |
    147 | )} 148 |
    149 | )} 150 |
    151 | 152 | 153 | 154 |
    155 | 156 |
    157 | 158 | 159 |
    160 | ) 161 | } 162 | 163 | function CountButton(props) { 164 | return ( 165 | 166 | ) 167 | } 168 | 169 | function PrevCoffee(props) { 170 | const prev_id = parseInt(props.id) - 1 171 | 172 | const { data, error } = useSWR({ 173 | query: COFFEE_IMG_QUERY, 174 | variables: { coffeeID: String(prev_id) } 175 | }, queryVarFetcher); 176 | 177 | // If data exists, set to coffee object 178 | let coffee; 179 | if (data) coffee = data.data.coffee 180 | 181 | return ( 182 |
    183 | {coffee ? ( 184 | 185 | ) : ( 186 |
    187 | )} 188 |
    189 | ) 190 | } 191 | 192 | function NextCoffee(props) { 193 | const next_id = parseInt(props.id) + 1 194 | 195 | const { data, error } = useSWR({ 196 | query: COFFEE_IMG_QUERY, 197 | variables: { coffeeID: String(next_id) } 198 | }, queryVarFetcher); 199 | 200 | // If data exists, set to coffee object 201 | let coffee; 202 | if (data) coffee = data.data.coffee 203 | 204 | return ( 205 |
    206 | {coffee ? ( 207 | 208 | ) : ( 209 |
    210 | )} 211 |
    212 | ) 213 | } 214 | 215 | function HoverLink(props) { 216 | return ( 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | ) 226 | } -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import Header from 'components/Header' 2 | import Footer from 'components/Footer' 3 | import CoffeeMenu from 'components/CoffeeMenu' 4 | import Cart from 'components/Cart' 5 | 6 | export default function Home(props) { 7 | 8 | return ( 9 |
    10 |
    11 | 12 |
    13 | 14 |
    15 | 16 |
    17 | 18 | 19 |
    20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /src/pages/order/[id].js: -------------------------------------------------------------------------------- 1 | import useSWR from 'swr' 2 | import Link from 'next/link' 3 | import Image from 'next/image' 4 | import { useRouter } from 'next/router' 5 | import { useState, useEffect } from 'react' 6 | import NumberFormat from 'react-number-format' 7 | 8 | import Header from 'components/Header' 9 | import Footer from 'components/Footer' 10 | 11 | import CheckIcon from '@hashicorp/flight-icons/svg/check-circle-16.svg' 12 | import FailIcon from '@hashicorp/flight-icons/svg/x-square-16.svg' 13 | 14 | import { queryVarFetcher } from 'gql/apolloClient'; 15 | import { ORDER_QUERY } from 'gql/gqlQueries'; 16 | 17 | export default function Order(props) { 18 | const router = useRouter(); 19 | const { id } = router.query 20 | 21 | const { data, error } = useSWR({ 22 | query: ORDER_QUERY, 23 | variables: { orderID: String(id) } 24 | }, queryVarFetcher); 25 | 26 | const dismiss = async (event) => { 27 | router.back() 28 | } 29 | 30 | // If data exists, set to order object 31 | let order; 32 | if (data) order = data.data.order 33 | 34 | let total = 0 35 | if (order) { 36 | total = order.items.reduce((t, next) => { 37 | return t + (next.coffee.price * next.quantity) 38 | }, 0) 39 | } 40 | 41 | let pay = {} 42 | if (typeof window !== "undefined") { 43 | if (localStorage.getItem("orders")) { 44 | const orders = JSON.parse(localStorage.getItem("orders")) 45 | 46 | // if orders exist in localstorage, return payment information 47 | if (orders[id]) pay = orders[id] 48 | } 49 | } 50 | 51 | return ( 52 |
    53 |
    54 | 55 |
    56 | {order && ( 57 | <> 58 |
    59 |
    60 |

    Order confirmation

    61 |

    (Order confirmed, but no payment was taken, because this is just a demo)

    62 |
    63 |
    64 | 65 |
    66 | 67 |
    68 |
    69 | {order.items.map((item) => ( 70 |
    71 | {item.amount > 2 && ( 72 | 73 | )} 74 | {item.amount > 1 && ( 75 | 76 | )} 77 | 78 |
    79 | ))} 80 |
    81 |
    82 | 83 |
    84 |

    Order #{order.id}

    85 | 86 |
    87 |

    Items

    88 |
      89 | {order.items.map((item) => ( 90 |
    • 91 | 92 | 93 | {item.quantity} x {item.coffee.name} 94 | 95 | 96 |
    • 97 | ))} 98 |
    99 | 100 |
    101 | 102 | {Object.keys(pay).length > 0 && ( 103 | <> 104 |
    105 |
    106 |

    Plain text card number

    107 | 108 |
    109 | 110 |
    111 |

    Status

    112 |

    113 | {pay.message.includes("success") ? ( 114 | 115 | ) : ( 116 | 117 | )} 118 | {pay.message.split(",")[0]} 119 |

    120 |
    121 | 122 |
    123 |

    Encryption Status

    124 |

    125 | {!pay.card_ciphertext.includes("Disabled") ? ( 126 | 127 | ) : ( 128 | 129 | )} 130 | {pay.card_ciphertext} 131 |

    132 |
    133 |
    134 | 135 |

    Card details returned for demo purposes, not for production.

    136 | 137 | )} 138 |
    139 | 140 |
    141 | 142 | )} 143 |
    144 | 145 |
    147 | ) 148 | } -------------------------------------------------------------------------------- /src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, body { 6 | background: #F8F8F8; 7 | } 8 | 9 | html .dark body, .dark body { 10 | background: #171717; 11 | } 12 | 13 | .icon-green { 14 | filter: invert(60%) sepia(38%) saturate(5616%) hue-rotate(55deg) brightness(95%) contrast(101%); 15 | } 16 | 17 | .icon-red { 18 | filter: invert(17%) sepia(42%) saturate(7010%) hue-rotate(3deg) brightness(110%) contrast(132%); 19 | } 20 | 21 | .shimmer { 22 | animation: shimmer-move 2s ease infinite; 23 | } 24 | 25 | .scroll-style { 26 | background-clip: border-box; 27 | } 28 | 29 | .scroll-style::-webkit-scrollbar { 30 | width: 29px; 31 | height: 29px; 32 | background: transparent; 33 | } 34 | 35 | .scroll-style::-webkit-scrollbar-track { 36 | background: transparent; 37 | } 38 | 39 | .scroll-style::-webkit-scrollbar-thumb { 40 | border: 12px solid transparent; 41 | background: #d4d4d4; 42 | border-radius: 32px; 43 | background-clip: content-box; 44 | } 45 | 46 | @media (prefers-color-scheme: dark) { 47 | .scroll-style::-webkit-scrollbar-thumb { 48 | background: #737373; 49 | background-clip: content-box; 50 | } 51 | } 52 | 53 | @keyframes shimmer-move { 54 | 0% { 55 | transform:translateX(-200%) 56 | } 57 | 58 | to { 59 | transform:translateX(200%) 60 | } 61 | } -------------------------------------------------------------------------------- /src/useLocalStorage.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | const storage = { 4 | getItem(key, initialValue) { 5 | if (typeof window === "undefined") { 6 | return initialValue; 7 | } 8 | try { 9 | const unparsedValue = window.localStorage[key]; 10 | if (typeof unparsedValue === "undefined") { 11 | return initialValue; 12 | } 13 | return JSON.parse(unparsedValue); 14 | } catch (error) { 15 | return initialValue; 16 | } 17 | }, 18 | 19 | setItem(key, value) { 20 | window.localStorage[key] = JSON.stringify(value); 21 | }, 22 | }; 23 | 24 | export default function useLocalStorage(key, initialValue) { 25 | const [value, setValue] = useState(initialValue); 26 | 27 | useEffect(() => { 28 | setValue(storage.getItem(key, initialValue)); 29 | }, [key]); 30 | 31 | const setItem = (newValue) => { 32 | setValue(newValue); 33 | storage.setItem(key, newValue); 34 | }; 35 | 36 | return [value, setItem]; 37 | } -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const defaultTheme = require('tailwindcss/defaultTheme') 2 | 3 | module.exports = { 4 | content: ['./src/**/*.{js,ts,jsx,tsx}'], 5 | darkMode: 'class', 6 | theme: { 7 | screens: { 8 | 'xs': '475px', 9 | ...defaultTheme.screens, 10 | }, 11 | extend: { 12 | screens: { 13 | 'xl': '1144px', 14 | '2xl': '1280px', 15 | }, 16 | boxShadow: { 17 | fold: "-1px 0 0 rgba(0, 0, 0, .05)", 18 | darkFold: "-1px 0 0 rgba(255, 255, 255, .05)", 19 | crease: "0 -1px 0 rgba(0, 0, 0, .05)", 20 | darkCrease: "0 -1px 0 rgba(255, 255, 255, .05)", 21 | stroke: "0 0 0 1px rgba(0, 0, 0, .1)", 22 | highlight: "0 0 0 1px rgba(255, 255, 255, .1)", 23 | glare: "0 0 0 1px rgba(255, 255, 255, .25)", 24 | subtle: "0 1px 3px rgba(0, 0, 0, .2)", 25 | low: "0 1px 3px rgba(0, 0, 0, .03), 0 16px 24px rgba(0, 0, 0, .01)", 26 | mid: "0 0 0 1px rgba(0, 0, 0, .03), 0 1px 3px rgba(0, 0, 0, .05), 0 16px 24px rgba(0, 0, 0, .02)", 27 | high: "0 0 0 1px rgba(0, 0, 0, .03), 0 1px 3px rgba(0, 0, 0, .05), 0 16px 24px rgba(0, 0, 0, .05)", 28 | highest: "0 0 0 1px rgba(0, 0, 0, .25), 0 1px 3px rgba(0, 0, 0, .05), 0 16px 24px rgba(0, 0, 0, .05)", 29 | cart: "0 0 0 1px rgba(0, 0, 0, .05), 0 -1px 3px rgba(0, 0, 0, .05), 0 -16px 24px rgba(0, 0, 0, .05)", 30 | darkCart: "inset 0 1px 0 rgba(255, 255, 255, .1), 0 -1px 3px rgba(0, 0, 0, .4), 0 -16px 24px rgba(0, 0, 0, .5)", 31 | }, 32 | }, 33 | }, 34 | plugins: [ 35 | require('@tailwindcss/line-clamp'), 36 | ], 37 | } 38 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@apollo/client@^3.5.8": 6 | version "3.5.8" 7 | resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.5.8.tgz#7215b974c5988b6157530eb69369209210349fe0" 8 | integrity sha512-MAm05+I1ullr64VLpZwon/ISnkMuNLf6vDqgo9wiMhHYBGT4yOAbAIseRdjCHZwfSx/7AUuBgaTNOssZPIr6FQ== 9 | dependencies: 10 | "@graphql-typed-document-node/core" "^3.0.0" 11 | "@wry/context" "^0.6.0" 12 | "@wry/equality" "^0.5.0" 13 | "@wry/trie" "^0.3.0" 14 | graphql-tag "^2.12.3" 15 | hoist-non-react-statics "^3.3.2" 16 | optimism "^0.16.1" 17 | prop-types "^15.7.2" 18 | symbol-observable "^4.0.0" 19 | ts-invariant "^0.9.4" 20 | tslib "^2.3.0" 21 | zen-observable-ts "^1.2.0" 22 | 23 | "@assortment/darkmodejs@^1.2.1": 24 | version "1.2.1" 25 | resolved "https://registry.yarnpkg.com/@assortment/darkmodejs/-/darkmodejs-1.2.1.tgz#b021f6d2c5b19d22115bbbc81711adb52322e066" 26 | integrity sha512-kP8ZJKG4BluaYSAwsM3u6s4Zoa2NjUaQbKDBefhpYTyWuGxc+OeNvndsVZz4CIvCcUAMXbu9FX9HeKptfoMkOg== 27 | 28 | "@babel/code-frame@^7.0.0": 29 | version "7.16.7" 30 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" 31 | integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== 32 | dependencies: 33 | "@babel/highlight" "^7.16.7" 34 | 35 | "@babel/helper-validator-identifier@^7.16.7": 36 | version "7.16.7" 37 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" 38 | integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== 39 | 40 | "@babel/highlight@^7.16.7": 41 | version "7.16.10" 42 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" 43 | integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== 44 | dependencies: 45 | "@babel/helper-validator-identifier" "^7.16.7" 46 | chalk "^2.0.0" 47 | js-tokens "^4.0.0" 48 | 49 | "@graphql-typed-document-node/core@^3.0.0": 50 | version "3.1.1" 51 | resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052" 52 | integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== 53 | 54 | "@hashicorp/flight-icons@^2.0.1": 55 | version "2.0.2" 56 | resolved "https://registry.yarnpkg.com/@hashicorp/flight-icons/-/flight-icons-2.0.2.tgz#39707309a679aaf83eea8fb978d3a9770a74365e" 57 | integrity sha512-KfaviEGC7bnJCsXS3yx6gG4haOuHsxXgozBEmZ6p2IRBhqZtRd3X06lyLoLmS52PzNf8M8gI26y6gli8hozLsw== 58 | 59 | "@miragejs/pretender-node-polyfill@^0.1.0": 60 | version "0.1.2" 61 | resolved "https://registry.yarnpkg.com/@miragejs/pretender-node-polyfill/-/pretender-node-polyfill-0.1.2.tgz#d26b6b7483fb70cd62189d05c95d2f67153e43f2" 62 | integrity sha512-M/BexG/p05C5lFfMunxo/QcgIJnMT2vDVCd00wNqK2ImZONIlEETZwWJu1QtLxtmYlSHlCFl3JNzp0tLe7OJ5g== 63 | 64 | "@next/env@12.0.9": 65 | version "12.0.9" 66 | resolved "https://registry.yarnpkg.com/@next/env/-/env-12.0.9.tgz#4c9e9eef00226145d9629a846b8cc31878e1328c" 67 | integrity sha512-oBlkyDop0Stf7MPIzETGv5r0YT/G/weBrknoPOUTaa5qwOeGjuy6gsOVc/SBtrBkOoBmRpD+fFhQJPvmo1mS+g== 68 | 69 | "@next/swc-android-arm64@12.0.9": 70 | version "12.0.9" 71 | resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.0.9.tgz#2cdbcc1814471044ea0e057b475090d25654833c" 72 | integrity sha512-aVqgsEn5plmUH2X58sjzhHsH/6majucWTMaaBEs7hHO2+GCwCZc7zaLH4XCBMKPES9Yaja8/pYUbvZQE9DqgFw== 73 | 74 | "@next/swc-darwin-arm64@12.0.9": 75 | version "12.0.9" 76 | resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.0.9.tgz#ea200929d7116de12c6f3b13ff75f9522c2153e3" 77 | integrity sha512-uAgRKm4a2nVdyBiPPJokvmDD1saugOvxljz9ld2ih0CCg5S9vBhqaj3kPGCQBj9hSu3q+Lng2CHnQqG3ga1jzA== 78 | 79 | "@next/swc-darwin-x64@12.0.9": 80 | version "12.0.9" 81 | resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.0.9.tgz#32800a7a9aff4bfd2038b0bce3657ece8708a87b" 82 | integrity sha512-fDOs2lZIyrAdU18IxMA5orBPn9qLbOdu55gXSTNZOhyRJ8ugtbUAejsK7OL0boJy0CCHPAdVRXm01Mwk8tZ9RQ== 83 | 84 | "@next/swc-linux-arm-gnueabihf@12.0.9": 85 | version "12.0.9" 86 | resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.0.9.tgz#da012dfb69ad2abc3d4045395581b650048bdd7c" 87 | integrity sha512-/ni0p9DBvATUML9RQ1ycQuf05uOYKdzA6iI8+eRsARjpGbFVUFbge7XPzlj9g2Q9YWgoN8CSjFGnKRlyky5uHA== 88 | 89 | "@next/swc-linux-arm64-gnu@12.0.9": 90 | version "12.0.9" 91 | resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.0.9.tgz#fe704c0a1cb048ef19d4a24b2c990574c96c933b" 92 | integrity sha512-AphxilJDf95rUxJDHgM9Ww1DaYXZWqTvoKwXeej/0SgSvICcRZrLaFDrkojdXz0Rxr4igX2OdYR1S4/Hj1jWOQ== 93 | 94 | "@next/swc-linux-arm64-musl@12.0.9": 95 | version "12.0.9" 96 | resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.0.9.tgz#b2bb68940903cd64f7875979ed9907e946dc4f3e" 97 | integrity sha512-K5jbvNNzF3mRjWmPdxP5Bg87i7FHivfBj/L0KJlxpkLSC8sffBJDmB6jtMnI7wiPj9J6vmLkbGtSosln78xAlQ== 98 | 99 | "@next/swc-linux-x64-gnu@12.0.9": 100 | version "12.0.9" 101 | resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.0.9.tgz#b700ba095551d4f6e830b92d4593a3b6e73bba82" 102 | integrity sha512-bJZ9bkMkQzsY+UyWezEZ77GWQ4TzwKeXdayX3U3+aEkL8k5C6eKBXlidWdrhu0teLmaUXIyWerWrLnJzwGXdfw== 103 | 104 | "@next/swc-linux-x64-musl@12.0.9": 105 | version "12.0.9" 106 | resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.0.9.tgz#678460266f544b52f1190ef0c3494e436608591e" 107 | integrity sha512-SR9p0R+v1T32DTXPVAXZw31pmJAkSDotC6Afy+mfC0xrEL3pp95R8sGXYAAUCEPkQp0MEeUOVy2LrToe92X7hQ== 108 | 109 | "@next/swc-win32-arm64-msvc@12.0.9": 110 | version "12.0.9" 111 | resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.0.9.tgz#f70e5bd0821ca168aeef117e51ab870265ceeeb1" 112 | integrity sha512-mzQ1A8vfHhJrvEy5KJZGZWEByXthyKfWofvFaf+oo/5nJl/0Bz1ODP2ajSmbLG++77Eo2AROgbm9pkW1ucvG2A== 113 | 114 | "@next/swc-win32-ia32-msvc@12.0.9": 115 | version "12.0.9" 116 | resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.0.9.tgz#0b853793754642cde9f9099087d4a86b6a99a24d" 117 | integrity sha512-MpD2vj1zjo1u3J3wiz3pEKse19Etz+P0GL6XfQkB/9a84vJQ1JWMaWBjmIdivzZv718Il2pRSSx8hymwPfguYQ== 118 | 119 | "@next/swc-win32-x64-msvc@12.0.9": 120 | version "12.0.9" 121 | resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.0.9.tgz#f7d3b59000082cf65c84fdc61930b708aa5446e5" 122 | integrity sha512-1c/sxp/4Qz4F6rCxiYqAnrmghCOFt5hHZ9Kd+rXFW5Mqev4C4XDOUMHdBH55HgnJZqngYhOE0r/XNkCtsIojig== 123 | 124 | "@nodelib/fs.scandir@2.1.5": 125 | version "2.1.5" 126 | resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" 127 | integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== 128 | dependencies: 129 | "@nodelib/fs.stat" "2.0.5" 130 | run-parallel "^1.1.9" 131 | 132 | "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": 133 | version "2.0.5" 134 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 135 | integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 136 | 137 | "@nodelib/fs.walk@^1.2.3": 138 | version "1.2.8" 139 | resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 140 | integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== 141 | dependencies: 142 | "@nodelib/fs.scandir" "2.1.5" 143 | fastq "^1.6.0" 144 | 145 | "@tailwindcss/line-clamp@^0.3.0": 146 | version "0.3.1" 147 | resolved "https://registry.yarnpkg.com/@tailwindcss/line-clamp/-/line-clamp-0.3.1.tgz#4d8441b509b87ece84e94f28a4aa9998413ab849" 148 | integrity sha512-pNr0T8LAc3TUx/gxCfQZRe9NB2dPEo/cedPHzUGIPxqDMhgjwNm6jYxww4W5l0zAsAddxr+XfZcqttGiFDgrGg== 149 | 150 | "@types/parse-json@^4.0.0": 151 | version "4.0.0" 152 | resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" 153 | integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== 154 | 155 | "@wry/context@^0.6.0": 156 | version "0.6.1" 157 | resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.1.tgz#c3c29c0ad622adb00f6a53303c4f965ee06ebeb2" 158 | integrity sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw== 159 | dependencies: 160 | tslib "^2.3.0" 161 | 162 | "@wry/equality@^0.5.0": 163 | version "0.5.2" 164 | resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.2.tgz#72c8a7a7d884dff30b612f4f8464eba26c080e73" 165 | integrity sha512-oVMxbUXL48EV/C0/M7gLVsoK6qRHPS85x8zECofEZOVvxGmIPLA9o5Z27cc2PoAyZz1S2VoM2A7FLAnpfGlneA== 166 | dependencies: 167 | tslib "^2.3.0" 168 | 169 | "@wry/trie@^0.3.0": 170 | version "0.3.1" 171 | resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.3.1.tgz#2279b790f15032f8bcea7fc944d27988e5b3b139" 172 | integrity sha512-WwB53ikYudh9pIorgxrkHKrQZcCqNM/Q/bDzZBffEaGUKGuHrRb3zZUT9Sh2qw9yogC7SsdRmQ1ER0pqvd3bfw== 173 | dependencies: 174 | tslib "^2.3.0" 175 | 176 | acorn-node@^1.6.1: 177 | version "1.8.2" 178 | resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" 179 | integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== 180 | dependencies: 181 | acorn "^7.0.0" 182 | acorn-walk "^7.0.0" 183 | xtend "^4.0.2" 184 | 185 | acorn-walk@^7.0.0: 186 | version "7.2.0" 187 | resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" 188 | integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== 189 | 190 | acorn@^7.0.0: 191 | version "7.4.1" 192 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" 193 | integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== 194 | 195 | ansi-styles@^3.2.1: 196 | version "3.2.1" 197 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 198 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 199 | dependencies: 200 | color-convert "^1.9.0" 201 | 202 | ansi-styles@^4.1.0: 203 | version "4.3.0" 204 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 205 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 206 | dependencies: 207 | color-convert "^2.0.1" 208 | 209 | anymatch@~3.1.2: 210 | version "3.1.2" 211 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 212 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 213 | dependencies: 214 | normalize-path "^3.0.0" 215 | picomatch "^2.0.4" 216 | 217 | arg@^5.0.1: 218 | version "5.0.1" 219 | resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.1.tgz#eb0c9a8f77786cad2af8ff2b862899842d7b6adb" 220 | integrity sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA== 221 | 222 | autoprefixer@^10.4.0: 223 | version "10.4.2" 224 | resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b" 225 | integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ== 226 | dependencies: 227 | browserslist "^4.19.1" 228 | caniuse-lite "^1.0.30001297" 229 | fraction.js "^4.1.2" 230 | normalize-range "^0.1.2" 231 | picocolors "^1.0.0" 232 | postcss-value-parser "^4.2.0" 233 | 234 | axios@^0.24.0: 235 | version "0.24.0" 236 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6" 237 | integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== 238 | dependencies: 239 | follow-redirects "^1.14.4" 240 | 241 | binary-extensions@^2.0.0: 242 | version "2.2.0" 243 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 244 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 245 | 246 | braces@^3.0.1, braces@~3.0.2: 247 | version "3.0.2" 248 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 249 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 250 | dependencies: 251 | fill-range "^7.0.1" 252 | 253 | browserslist@^4.19.1: 254 | version "4.19.1" 255 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" 256 | integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== 257 | dependencies: 258 | caniuse-lite "^1.0.30001286" 259 | electron-to-chromium "^1.4.17" 260 | escalade "^3.1.1" 261 | node-releases "^2.0.1" 262 | picocolors "^1.0.0" 263 | 264 | callsites@^3.0.0: 265 | version "3.1.0" 266 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" 267 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 268 | 269 | camelcase-css@^2.0.1: 270 | version "2.0.1" 271 | resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" 272 | integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== 273 | 274 | caniuse-lite@^1.0.30001283, caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.30001297: 275 | version "1.0.30001303" 276 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001303.tgz#9b168e4f43ccfc372b86f4bc5a551d9b909c95c9" 277 | integrity sha512-/Mqc1oESndUNszJP0kx0UaQU9kEv9nNtJ7Kn8AdA0mNnH8eR1cj0kG+NbNuC1Wq/b21eA8prhKRA3bbkjONegQ== 278 | 279 | chalk@^2.0.0: 280 | version "2.4.2" 281 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 282 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 283 | dependencies: 284 | ansi-styles "^3.2.1" 285 | escape-string-regexp "^1.0.5" 286 | supports-color "^5.3.0" 287 | 288 | chalk@^4.1.2: 289 | version "4.1.2" 290 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 291 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 292 | dependencies: 293 | ansi-styles "^4.1.0" 294 | supports-color "^7.1.0" 295 | 296 | chokidar@^3.5.3: 297 | version "3.5.3" 298 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" 299 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== 300 | dependencies: 301 | anymatch "~3.1.2" 302 | braces "~3.0.2" 303 | glob-parent "~5.1.2" 304 | is-binary-path "~2.1.0" 305 | is-glob "~4.0.1" 306 | normalize-path "~3.0.0" 307 | readdirp "~3.6.0" 308 | optionalDependencies: 309 | fsevents "~2.3.2" 310 | 311 | color-convert@^1.9.0: 312 | version "1.9.3" 313 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 314 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 315 | dependencies: 316 | color-name "1.1.3" 317 | 318 | color-convert@^2.0.1: 319 | version "2.0.1" 320 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 321 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 322 | dependencies: 323 | color-name "~1.1.4" 324 | 325 | color-name@1.1.3: 326 | version "1.1.3" 327 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 328 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 329 | 330 | color-name@^1.1.4, color-name@~1.1.4: 331 | version "1.1.4" 332 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 333 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 334 | 335 | cookie@^0.4.1: 336 | version "0.4.1" 337 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" 338 | integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== 339 | 340 | cosmiconfig@^7.0.1: 341 | version "7.0.1" 342 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" 343 | integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== 344 | dependencies: 345 | "@types/parse-json" "^4.0.0" 346 | import-fresh "^3.2.1" 347 | parse-json "^5.0.0" 348 | path-type "^4.0.0" 349 | yaml "^1.10.0" 350 | 351 | cssesc@^3.0.0: 352 | version "3.0.0" 353 | resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" 354 | integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== 355 | 356 | defined@^1.0.0: 357 | version "1.0.0" 358 | resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" 359 | integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= 360 | 361 | detective@^5.2.0: 362 | version "5.2.0" 363 | resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" 364 | integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg== 365 | dependencies: 366 | acorn-node "^1.6.1" 367 | defined "^1.0.0" 368 | minimist "^1.1.1" 369 | 370 | didyoumean@^1.2.2: 371 | version "1.2.2" 372 | resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" 373 | integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== 374 | 375 | dlv@^1.1.3: 376 | version "1.1.3" 377 | resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" 378 | integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== 379 | 380 | electron-to-chromium@^1.4.17: 381 | version "1.4.54" 382 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.54.tgz#69005d39ed11542e1bcb65ec1a98e44d39527ba8" 383 | integrity sha512-jRAoneRdSxnpRHO0ANpnEUtQHXxlgfVjrLOnQSisw1ryjXJXvS0pJaR/v2B7S++/tRjgEDp4Sjn5nmgb6uTySw== 384 | 385 | error-ex@^1.3.1: 386 | version "1.3.2" 387 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 388 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== 389 | dependencies: 390 | is-arrayish "^0.2.1" 391 | 392 | escalade@^3.1.1: 393 | version "3.1.1" 394 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 395 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 396 | 397 | escape-string-regexp@^1.0.5: 398 | version "1.0.5" 399 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 400 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 401 | 402 | fake-xml-http-request@^2.1.2: 403 | version "2.1.2" 404 | resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-2.1.2.tgz#f1786720cae50bbb46273035a0173414f3e85e74" 405 | integrity sha512-HaFMBi7r+oEC9iJNpc3bvcW7Z7iLmM26hPDmlb0mFwyANSsOQAtJxbdWsXITKOzZUyMYK0zYCv3h5yDj9TsiXg== 406 | 407 | fast-glob@^3.2.11: 408 | version "3.2.11" 409 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" 410 | integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== 411 | dependencies: 412 | "@nodelib/fs.stat" "^2.0.2" 413 | "@nodelib/fs.walk" "^1.2.3" 414 | glob-parent "^5.1.2" 415 | merge2 "^1.3.0" 416 | micromatch "^4.0.4" 417 | 418 | fastq@^1.6.0: 419 | version "1.13.0" 420 | resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" 421 | integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== 422 | dependencies: 423 | reusify "^1.0.4" 424 | 425 | fill-range@^7.0.1: 426 | version "7.0.1" 427 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 428 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 429 | dependencies: 430 | to-regex-range "^5.0.1" 431 | 432 | flatted@^3.2.4: 433 | version "3.2.5" 434 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" 435 | integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== 436 | 437 | follow-redirects@^1.14.4: 438 | version "1.14.7" 439 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" 440 | integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== 441 | 442 | fraction.js@^4.1.2: 443 | version "4.1.2" 444 | resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.2.tgz#13e420a92422b6cf244dff8690ed89401029fbe8" 445 | integrity sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA== 446 | 447 | fsevents@~2.3.2: 448 | version "2.3.2" 449 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 450 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 451 | 452 | function-bind@^1.1.1: 453 | version "1.1.1" 454 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 455 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 456 | 457 | glob-parent@^5.1.2, glob-parent@~5.1.2: 458 | version "5.1.2" 459 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 460 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 461 | dependencies: 462 | is-glob "^4.0.1" 463 | 464 | glob-parent@^6.0.2: 465 | version "6.0.2" 466 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" 467 | integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== 468 | dependencies: 469 | is-glob "^4.0.3" 470 | 471 | graphql-tag@^2.12.3: 472 | version "2.12.6" 473 | resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" 474 | integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== 475 | dependencies: 476 | tslib "^2.1.0" 477 | 478 | graphql@^16.3.0: 479 | version "16.3.0" 480 | resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.3.0.tgz#a91e24d10babf9e60c706919bb182b53ccdffc05" 481 | integrity sha512-xm+ANmA16BzCT5pLjuXySbQVFwH3oJctUVdy81w1sV0vBU0KgDdBGtxQOUd5zqOBk/JayAFeG8Dlmeq74rjm/A== 482 | 483 | has-flag@^3.0.0: 484 | version "3.0.0" 485 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 486 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 487 | 488 | has-flag@^4.0.0: 489 | version "4.0.0" 490 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 491 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 492 | 493 | has@^1.0.3: 494 | version "1.0.3" 495 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 496 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 497 | dependencies: 498 | function-bind "^1.1.1" 499 | 500 | hoist-non-react-statics@^3.3.2: 501 | version "3.3.2" 502 | resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" 503 | integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== 504 | dependencies: 505 | react-is "^16.7.0" 506 | 507 | import-fresh@^3.2.1: 508 | version "3.3.0" 509 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" 510 | integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 511 | dependencies: 512 | parent-module "^1.0.0" 513 | resolve-from "^4.0.0" 514 | 515 | inflected@^2.0.4: 516 | version "2.1.0" 517 | resolved "https://registry.yarnpkg.com/inflected/-/inflected-2.1.0.tgz#2816ac17a570bbbc8303ca05bca8bf9b3f959687" 518 | integrity sha512-hAEKNxvHf2Iq3H60oMBHkB4wl5jn3TPF3+fXek/sRwAB5gP9xWs4r7aweSF95f99HFoz69pnZTcu8f0SIHV18w== 519 | 520 | is-arrayish@^0.2.1: 521 | version "0.2.1" 522 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 523 | integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= 524 | 525 | is-binary-path@~2.1.0: 526 | version "2.1.0" 527 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 528 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 529 | dependencies: 530 | binary-extensions "^2.0.0" 531 | 532 | is-core-module@^2.8.1: 533 | version "2.8.1" 534 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" 535 | integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== 536 | dependencies: 537 | has "^1.0.3" 538 | 539 | is-extglob@^2.1.1: 540 | version "2.1.1" 541 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 542 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 543 | 544 | is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: 545 | version "4.0.3" 546 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 547 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 548 | dependencies: 549 | is-extglob "^2.1.1" 550 | 551 | is-number@^7.0.0: 552 | version "7.0.0" 553 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 554 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 555 | 556 | "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: 557 | version "4.0.0" 558 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 559 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 560 | 561 | json-parse-even-better-errors@^2.3.0: 562 | version "2.3.1" 563 | resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" 564 | integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== 565 | 566 | lilconfig@^2.0.4: 567 | version "2.0.4" 568 | resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" 569 | integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== 570 | 571 | lines-and-columns@^1.1.6: 572 | version "1.2.4" 573 | resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" 574 | integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== 575 | 576 | lodash.assign@^4.2.0: 577 | version "4.2.0" 578 | resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" 579 | integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= 580 | 581 | lodash.camelcase@^4.3.0: 582 | version "4.3.0" 583 | resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" 584 | integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= 585 | 586 | lodash.clonedeep@^4.5.0: 587 | version "4.5.0" 588 | resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" 589 | integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= 590 | 591 | lodash.compact@^3.0.1: 592 | version "3.0.1" 593 | resolved "https://registry.yarnpkg.com/lodash.compact/-/lodash.compact-3.0.1.tgz#540ce3837745975807471e16b4a2ba21e7256ca5" 594 | integrity sha1-VAzjg3dFl1gHRx4WtKK6IeclbKU= 595 | 596 | lodash.find@^4.6.0: 597 | version "4.6.0" 598 | resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" 599 | integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E= 600 | 601 | lodash.flatten@^4.4.0: 602 | version "4.4.0" 603 | resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" 604 | integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= 605 | 606 | lodash.forin@^4.4.0: 607 | version "4.4.0" 608 | resolved "https://registry.yarnpkg.com/lodash.forin/-/lodash.forin-4.4.0.tgz#5d3f20ae564011fbe88381f7d98949c9c9519731" 609 | integrity sha1-XT8grlZAEfvog4H32YlJyclRlzE= 610 | 611 | lodash.get@^4.4.2: 612 | version "4.4.2" 613 | resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" 614 | integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= 615 | 616 | lodash.has@^4.5.2: 617 | version "4.5.2" 618 | resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862" 619 | integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI= 620 | 621 | lodash.invokemap@^4.6.0: 622 | version "4.6.0" 623 | resolved "https://registry.yarnpkg.com/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz#1748cda5d8b0ef8369c4eb3ec54c21feba1f2d62" 624 | integrity sha1-F0jNpdiw74NpxOs+xUwh/rofLWI= 625 | 626 | lodash.isempty@^4.4.0: 627 | version "4.4.0" 628 | resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" 629 | integrity sha1-b4bL7di+TsmHvpqvM8loTbGzHn4= 630 | 631 | lodash.isequal@^4.5.0: 632 | version "4.5.0" 633 | resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" 634 | integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= 635 | 636 | lodash.isfunction@^3.0.9: 637 | version "3.0.9" 638 | resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" 639 | integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== 640 | 641 | lodash.isinteger@^4.0.4: 642 | version "4.0.4" 643 | resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" 644 | integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= 645 | 646 | lodash.isplainobject@^4.0.6: 647 | version "4.0.6" 648 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" 649 | integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= 650 | 651 | lodash.lowerfirst@^4.3.1: 652 | version "4.3.1" 653 | resolved "https://registry.yarnpkg.com/lodash.lowerfirst/-/lodash.lowerfirst-4.3.1.tgz#de3c7b12e02c6524a0059c2f6cb7c5c52655a13d" 654 | integrity sha1-3jx7EuAsZSSgBZwvbLfFxSZVoT0= 655 | 656 | lodash.map@^4.6.0: 657 | version "4.6.0" 658 | resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" 659 | integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= 660 | 661 | lodash.mapvalues@^4.6.0: 662 | version "4.6.0" 663 | resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" 664 | integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw= 665 | 666 | lodash.pick@^4.4.0: 667 | version "4.4.0" 668 | resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" 669 | integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= 670 | 671 | lodash.snakecase@^4.1.1: 672 | version "4.1.1" 673 | resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" 674 | integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40= 675 | 676 | lodash.throttle@^4.1.1: 677 | version "4.1.1" 678 | resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" 679 | integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= 680 | 681 | lodash.uniq@^4.5.0: 682 | version "4.5.0" 683 | resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" 684 | integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= 685 | 686 | lodash.uniqby@^4.7.0: 687 | version "4.7.0" 688 | resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" 689 | integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= 690 | 691 | lodash.values@^4.3.0: 692 | version "4.3.0" 693 | resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347" 694 | integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c= 695 | 696 | loose-envify@^1.1.0, loose-envify@^1.4.0: 697 | version "1.4.0" 698 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 699 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 700 | dependencies: 701 | js-tokens "^3.0.0 || ^4.0.0" 702 | 703 | merge2@^1.3.0: 704 | version "1.4.1" 705 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 706 | integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== 707 | 708 | micromatch@^4.0.4: 709 | version "4.0.4" 710 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" 711 | integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== 712 | dependencies: 713 | braces "^3.0.1" 714 | picomatch "^2.2.3" 715 | 716 | minimist@^1.1.1: 717 | version "1.2.5" 718 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 719 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 720 | 721 | miragejs@^0.1.43: 722 | version "0.1.43" 723 | resolved "https://registry.yarnpkg.com/miragejs/-/miragejs-0.1.43.tgz#47a8546b9e3489f806073e681f380ccfe13d757d" 724 | integrity sha512-BhkyxssOZ2i4JqRjWpRnUQu9AFAKHyft8dJbqsg/N64+gCn2vw6vRteMpTKXllLjCPOA9Os8PhGRVXlXs4Ojhw== 725 | dependencies: 726 | "@miragejs/pretender-node-polyfill" "^0.1.0" 727 | inflected "^2.0.4" 728 | lodash.assign "^4.2.0" 729 | lodash.camelcase "^4.3.0" 730 | lodash.clonedeep "^4.5.0" 731 | lodash.compact "^3.0.1" 732 | lodash.find "^4.6.0" 733 | lodash.flatten "^4.4.0" 734 | lodash.forin "^4.4.0" 735 | lodash.get "^4.4.2" 736 | lodash.has "^4.5.2" 737 | lodash.invokemap "^4.6.0" 738 | lodash.isempty "^4.4.0" 739 | lodash.isequal "^4.5.0" 740 | lodash.isfunction "^3.0.9" 741 | lodash.isinteger "^4.0.4" 742 | lodash.isplainobject "^4.0.6" 743 | lodash.lowerfirst "^4.3.1" 744 | lodash.map "^4.6.0" 745 | lodash.mapvalues "^4.6.0" 746 | lodash.pick "^4.4.0" 747 | lodash.snakecase "^4.1.1" 748 | lodash.uniq "^4.5.0" 749 | lodash.uniqby "^4.7.0" 750 | lodash.values "^4.3.0" 751 | pretender "^3.4.7" 752 | 753 | nanoid@^3.1.30: 754 | version "3.2.0" 755 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" 756 | integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== 757 | 758 | next-dark-mode@^3.0.0: 759 | version "3.0.0" 760 | resolved "https://registry.yarnpkg.com/next-dark-mode/-/next-dark-mode-3.0.0.tgz#99196f799bbb03f35e0ca9688272626e2c4bd790" 761 | integrity sha512-DNiKexCzNmzPuUZ9Udumo1ZOcZ7grxg1PGm72vBmjfwSW6P4Jm2WjUqaM74jb37NRflU3PjJxhmXTuaa4dFiTQ== 762 | dependencies: 763 | "@assortment/darkmodejs" "^1.2.1" 764 | nookies "^2.5.2" 765 | 766 | next-themes@^0.0.15: 767 | version "0.0.15" 768 | resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.15.tgz#ab0cee69cd763b77d41211f631e108beab39bf7d" 769 | integrity sha512-LTmtqYi03c4gMTJmWwVK9XkHL7h0/+XrtR970Ujvtu3s0kZNeJN24aJsi4rkZOI8i19+qq6f8j+8Duwy5jqcrQ== 770 | 771 | next@latest: 772 | version "12.0.9" 773 | resolved "https://registry.yarnpkg.com/next/-/next-12.0.9.tgz#4eb3006b63bb866f5c2918ca0003e98f4259e063" 774 | integrity sha512-omfYqoR/DvbdOIJ6SS1unKJ4mGIxUPs0RPa7wr/Mft22OCKgJhuG+aI9KFYi5ZJBwoFQk1vqaMKpWz5qr+dN0Q== 775 | dependencies: 776 | "@next/env" "12.0.9" 777 | caniuse-lite "^1.0.30001283" 778 | postcss "8.4.5" 779 | styled-jsx "5.0.0" 780 | use-subscription "1.5.1" 781 | optionalDependencies: 782 | "@next/swc-android-arm64" "12.0.9" 783 | "@next/swc-darwin-arm64" "12.0.9" 784 | "@next/swc-darwin-x64" "12.0.9" 785 | "@next/swc-linux-arm-gnueabihf" "12.0.9" 786 | "@next/swc-linux-arm64-gnu" "12.0.9" 787 | "@next/swc-linux-arm64-musl" "12.0.9" 788 | "@next/swc-linux-x64-gnu" "12.0.9" 789 | "@next/swc-linux-x64-musl" "12.0.9" 790 | "@next/swc-win32-arm64-msvc" "12.0.9" 791 | "@next/swc-win32-ia32-msvc" "12.0.9" 792 | "@next/swc-win32-x64-msvc" "12.0.9" 793 | 794 | node-releases@^2.0.1: 795 | version "2.0.1" 796 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" 797 | integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== 798 | 799 | nookies@^2.5.2: 800 | version "2.5.2" 801 | resolved "https://registry.yarnpkg.com/nookies/-/nookies-2.5.2.tgz#cc55547efa982d013a21475bd0db0c02c1b35b27" 802 | integrity sha512-x0TRSaosAEonNKyCrShoUaJ5rrT5KHRNZ5DwPCuizjgrnkpE5DRf3VL7AyyQin4htict92X1EQ7ejDbaHDVdYA== 803 | dependencies: 804 | cookie "^0.4.1" 805 | set-cookie-parser "^2.4.6" 806 | 807 | normalize-path@^3.0.0, normalize-path@~3.0.0: 808 | version "3.0.0" 809 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 810 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 811 | 812 | normalize-range@^0.1.2: 813 | version "0.1.2" 814 | resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" 815 | integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= 816 | 817 | object-assign@^4.1.1: 818 | version "4.1.1" 819 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 820 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 821 | 822 | object-hash@^2.2.0: 823 | version "2.2.0" 824 | resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" 825 | integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== 826 | 827 | optimism@^0.16.1: 828 | version "0.16.1" 829 | resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.1.tgz#7c8efc1f3179f18307b887e18c15c5b7133f6e7d" 830 | integrity sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg== 831 | dependencies: 832 | "@wry/context" "^0.6.0" 833 | "@wry/trie" "^0.3.0" 834 | 835 | parent-module@^1.0.0: 836 | version "1.0.1" 837 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" 838 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 839 | dependencies: 840 | callsites "^3.0.0" 841 | 842 | parse-json@^5.0.0: 843 | version "5.2.0" 844 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" 845 | integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== 846 | dependencies: 847 | "@babel/code-frame" "^7.0.0" 848 | error-ex "^1.3.1" 849 | json-parse-even-better-errors "^2.3.0" 850 | lines-and-columns "^1.1.6" 851 | 852 | path-parse@^1.0.7: 853 | version "1.0.7" 854 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 855 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 856 | 857 | path-type@^4.0.0: 858 | version "4.0.0" 859 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" 860 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 861 | 862 | picocolors@^1.0.0: 863 | version "1.0.0" 864 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 865 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 866 | 867 | picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: 868 | version "2.3.1" 869 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 870 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 871 | 872 | postcss-js@^4.0.0: 873 | version "4.0.0" 874 | resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00" 875 | integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ== 876 | dependencies: 877 | camelcase-css "^2.0.1" 878 | 879 | postcss-load-config@^3.1.0: 880 | version "3.1.1" 881 | resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.1.tgz#2f53a17f2f543d9e63864460af42efdac0d41f87" 882 | integrity sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg== 883 | dependencies: 884 | lilconfig "^2.0.4" 885 | yaml "^1.10.2" 886 | 887 | postcss-nested@5.0.6: 888 | version "5.0.6" 889 | resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" 890 | integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA== 891 | dependencies: 892 | postcss-selector-parser "^6.0.6" 893 | 894 | postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.8: 895 | version "6.0.9" 896 | resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" 897 | integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== 898 | dependencies: 899 | cssesc "^3.0.0" 900 | util-deprecate "^1.0.2" 901 | 902 | postcss-value-parser@^4.2.0: 903 | version "4.2.0" 904 | resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" 905 | integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== 906 | 907 | postcss@8.4.5, postcss@^8.4.4: 908 | version "8.4.5" 909 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" 910 | integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== 911 | dependencies: 912 | nanoid "^3.1.30" 913 | picocolors "^1.0.0" 914 | source-map-js "^1.0.1" 915 | 916 | pretender@^3.4.7: 917 | version "3.4.7" 918 | resolved "https://registry.yarnpkg.com/pretender/-/pretender-3.4.7.tgz#34a2ae2d1fc9db440a990d50e6c0f5481d8755fc" 919 | integrity sha512-jkPAvt1BfRi0RKamweJdEcnjkeu7Es8yix3bJ+KgBC5VpG/Ln4JE3hYN6vJym4qprm8Xo5adhWpm3HCoft1dOw== 920 | dependencies: 921 | fake-xml-http-request "^2.1.2" 922 | route-recognizer "^0.3.3" 923 | 924 | prop-types@^15.7.2: 925 | version "15.8.1" 926 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" 927 | integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== 928 | dependencies: 929 | loose-envify "^1.4.0" 930 | object-assign "^4.1.1" 931 | react-is "^16.13.1" 932 | 933 | queue-microtask@^1.2.2: 934 | version "1.2.3" 935 | resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" 936 | integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== 937 | 938 | quick-lru@^5.1.1: 939 | version "5.1.1" 940 | resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" 941 | integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== 942 | 943 | react-dom@^17.0.2: 944 | version "17.0.2" 945 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" 946 | integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== 947 | dependencies: 948 | loose-envify "^1.1.0" 949 | object-assign "^4.1.1" 950 | scheduler "^0.20.2" 951 | 952 | react-is@^16.13.1, react-is@^16.7.0: 953 | version "16.13.1" 954 | resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" 955 | integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== 956 | 957 | react-number-format@^4.9.1: 958 | version "4.9.1" 959 | resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-4.9.1.tgz#62b3450b43c911f9227e770a8ea9fa606696e52e" 960 | integrity sha512-v49XqXv7SpwYZKGkghNJjoDUr6lIUozlPLrObcxre7GfcLx7qD4TCvArn3GozN/Y4FVbLyEYCwJoBCiChdBh5A== 961 | dependencies: 962 | prop-types "^15.7.2" 963 | 964 | react-scroll@^1.8.4: 965 | version "1.8.4" 966 | resolved "https://registry.yarnpkg.com/react-scroll/-/react-scroll-1.8.4.tgz#7cc882d7058d5b5aedcd362b1de13c88d64ebe4c" 967 | integrity sha512-J9rFqmdzularCXJoK2vleHVg2//y9Fs6zh7K13x7Yz3Y1kHPfQ/TTq029L09q1Gr5/5JjFLBOB2Sa3yYIqyTyQ== 968 | dependencies: 969 | lodash.throttle "^4.1.1" 970 | prop-types "^15.7.2" 971 | 972 | react@^17.0.2: 973 | version "17.0.2" 974 | resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" 975 | integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== 976 | dependencies: 977 | loose-envify "^1.1.0" 978 | object-assign "^4.1.1" 979 | 980 | readdirp@~3.6.0: 981 | version "3.6.0" 982 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 983 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 984 | dependencies: 985 | picomatch "^2.2.1" 986 | 987 | resolve-from@^4.0.0: 988 | version "4.0.0" 989 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 990 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 991 | 992 | resolve@^1.21.0: 993 | version "1.22.0" 994 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" 995 | integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== 996 | dependencies: 997 | is-core-module "^2.8.1" 998 | path-parse "^1.0.7" 999 | supports-preserve-symlinks-flag "^1.0.0" 1000 | 1001 | reusify@^1.0.4: 1002 | version "1.0.4" 1003 | resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" 1004 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 1005 | 1006 | route-recognizer@^0.3.3: 1007 | version "0.3.4" 1008 | resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3" 1009 | integrity sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g== 1010 | 1011 | run-parallel@^1.1.9: 1012 | version "1.2.0" 1013 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" 1014 | integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== 1015 | dependencies: 1016 | queue-microtask "^1.2.2" 1017 | 1018 | scheduler@^0.20.2: 1019 | version "0.20.2" 1020 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" 1021 | integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== 1022 | dependencies: 1023 | loose-envify "^1.1.0" 1024 | object-assign "^4.1.1" 1025 | 1026 | set-cookie-parser@^2.4.6: 1027 | version "2.4.8" 1028 | resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2" 1029 | integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg== 1030 | 1031 | source-map-js@^1.0.1: 1032 | version "1.0.2" 1033 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" 1034 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== 1035 | 1036 | styled-jsx@5.0.0: 1037 | version "5.0.0" 1038 | resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77" 1039 | integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== 1040 | 1041 | supports-color@^5.3.0: 1042 | version "5.5.0" 1043 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1044 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1045 | dependencies: 1046 | has-flag "^3.0.0" 1047 | 1048 | supports-color@^7.1.0: 1049 | version "7.2.0" 1050 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1051 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1052 | dependencies: 1053 | has-flag "^4.0.0" 1054 | 1055 | supports-preserve-symlinks-flag@^1.0.0: 1056 | version "1.0.0" 1057 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 1058 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 1059 | 1060 | swr@^1.1.2: 1061 | version "1.2.0" 1062 | resolved "https://registry.yarnpkg.com/swr/-/swr-1.2.0.tgz#8649f6e9131ce94bbcf7ffd65c21334da3d1ec20" 1063 | integrity sha512-C3IXeKOREn0jQ1ewXRENE7ED7jjGbFTakwB64eLACkCqkF/A0N2ckvpCTftcaSYi5yV36PzoehgVCOVRmtECcA== 1064 | 1065 | symbol-observable@^4.0.0: 1066 | version "4.0.0" 1067 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" 1068 | integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== 1069 | 1070 | tailwindcss@^3.0.0: 1071 | version "3.0.17" 1072 | resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.0.17.tgz#2c5fe6c364d76ec54644347c6f09befe0113b06f" 1073 | integrity sha512-OiHUsmOKQQEg/ocXaLIjk/kOz8EK2jF6iPuc1bQ4NsmhYl7sk70UDsGV02AJvBAAiJhinPCkDR8egT9qY+ulCw== 1074 | dependencies: 1075 | arg "^5.0.1" 1076 | chalk "^4.1.2" 1077 | chokidar "^3.5.3" 1078 | color-name "^1.1.4" 1079 | cosmiconfig "^7.0.1" 1080 | detective "^5.2.0" 1081 | didyoumean "^1.2.2" 1082 | dlv "^1.1.3" 1083 | fast-glob "^3.2.11" 1084 | glob-parent "^6.0.2" 1085 | is-glob "^4.0.3" 1086 | normalize-path "^3.0.0" 1087 | object-hash "^2.2.0" 1088 | postcss-js "^4.0.0" 1089 | postcss-load-config "^3.1.0" 1090 | postcss-nested "5.0.6" 1091 | postcss-selector-parser "^6.0.8" 1092 | postcss-value-parser "^4.2.0" 1093 | quick-lru "^5.1.1" 1094 | resolve "^1.21.0" 1095 | 1096 | to-regex-range@^5.0.1: 1097 | version "5.0.1" 1098 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1099 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1100 | dependencies: 1101 | is-number "^7.0.0" 1102 | 1103 | ts-invariant@^0.9.4: 1104 | version "0.9.4" 1105 | resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.9.4.tgz#42ac6c791aade267dd9dc65276549df5c5d71cac" 1106 | integrity sha512-63jtX/ZSwnUNi/WhXjnK8kz4cHHpYS60AnmA6ixz17l7E12a5puCWFlNpkne5Rl0J8TBPVHpGjsj4fxs8ObVLQ== 1107 | dependencies: 1108 | tslib "^2.1.0" 1109 | 1110 | tslib@^2.1.0, tslib@^2.3.0: 1111 | version "2.3.1" 1112 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" 1113 | integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== 1114 | 1115 | use-subscription@1.5.1: 1116 | version "1.5.1" 1117 | resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" 1118 | integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== 1119 | dependencies: 1120 | object-assign "^4.1.1" 1121 | 1122 | util-deprecate@^1.0.2: 1123 | version "1.0.2" 1124 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1125 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1126 | 1127 | xtend@^4.0.2: 1128 | version "4.0.2" 1129 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" 1130 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== 1131 | 1132 | yaml@^1.10.0, yaml@^1.10.2: 1133 | version "1.10.2" 1134 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" 1135 | integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== 1136 | 1137 | zen-observable-ts@^1.2.0: 1138 | version "1.2.3" 1139 | resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.2.3.tgz#c2f5ccebe812faf0cfcde547e6004f65b1a6d769" 1140 | integrity sha512-hc/TGiPkAWpByykMwDcem3SdUgA4We+0Qb36bItSuJC9xD0XVBZoFHYoadAomDSNf64CG8Ydj0Qb8Od8BUWz5g== 1141 | dependencies: 1142 | zen-observable "0.8.15" 1143 | 1144 | zen-observable@0.8.15: 1145 | version "0.8.15" 1146 | resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" 1147 | integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== 1148 | --------------------------------------------------------------------------------