├── .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 |
--------------------------------------------------------------------------------
/public/images/card-mastercard.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/images/card-visa.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |