-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: landing page and cart-item storage
- Loading branch information
1 parent
c4a6044
commit 5294447
Showing
101 changed files
with
2,563 additions
and
419 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,101 @@ | ||
# Next.js Fullstack DigitalOcean Droplet VM | ||
# SwagSticker.com ![Repo Status Badge](./.github/status-maintained-badge.svg) | ||
|
||
Fullstack Next.js (App Router) deployed to DigitalOcean App Platform | ||
E-commerce store for developer laptop stickers, fully autonomous and scale-abe. Built with Jamstack and server-side rendering. | ||
|
||
## Local Development | ||
<img width="800px" style="margin:auto" src="./.github/swagsticker.com-screenshot.png" alt="SwagSticker.com website screenshot"> | ||
|
||
### Prerequisites | ||
## 🎥 Demo Video | ||
|
||
https://github.com/jadiaheno/vention-machine-cloud-test/assets/13062328/a42d55bb-0381-4d16-9ea3-24aced02e5d3 | ||
|
||
## 🎯 Project Overview | ||
|
||
<!-- TODO_README --> | ||
|
||
- designed autonomous and scalable e-commerce store | ||
- enabled both guest checkout and no-password login for seamless checkout experience (JSON-Web-Token (JWT)) | ||
- designed an accessible, responsive, and performant UI with Next.js and TailwindCSS | ||
- utilized open-source SDKs to integrate third-party APIs | ||
- reduced initial load time to 1.2secs | ||
- generated product images with OpenCV python script | ||
- optimized load times and SEO with server-side rendering | ||
- avoided complex database setup with JSON product catalog and GraphQL for easy migration to headless CMS | ||
- secured checkout payments with stripe forms and bot detection | ||
- load test, >95% success rate with <300ms response for up to XXX users peak traffic | ||
|
||
## 🛠️ Built With | ||
|
||
- **Framework**: Next.js (React), TailwindCSS | ||
- **Language**: TypeScript | ||
- **Hosting**: Vercel (w/ Amazon Route53 domain) | ||
- **Third-Party**: Stripe (payments), Printify (drop-shipping) | ||
|
||
> **Specifications:** | ||
> | ||
> - Node.js: >=v20 | ||
> - React.js: v18 | ||
> - Next.js: v14 (App Router) | ||
> - Vercel: serverless, hobby plan | ||
## 🏗️ System Diagram | ||
|
||
<!-- TODO_README --> | ||
|
||
![SwagSticker.com system diagram](./.github/swagsticker.com-system-diagram.png) | ||
|
||
## ⭐️ Features | ||
|
||
<!-- TODO_README --> | ||
|
||
- <auth feature no pass, or stay guest> | ||
- <browse the catalog, search, filter> | ||
- <add items to cart, proceed to checkout> | ||
- <use secure stripe form, place order> | ||
- <track shipping status> | ||
|
||
## 💻 Local Development | ||
|
||
📌 Note: this demo can be run locally; the production code is private for security reasons | ||
|
||
#### Prerequisites | ||
|
||
- **Node.js** installed on your machine (download [here](https://nodejs.org/en/download)) | ||
- Stripe developer account (+ API keys) | ||
- Printify developer account (+ API keys) | ||
|
||
### Installation | ||
#### Installation | ||
|
||
```sh | ||
git clone https://github.com/spencerlepine/nextjs-digitalocean-poc | ||
cd nextjs-digitalocean-poc | ||
git clone https://github.com/spencerlepine/swagsticker.com | ||
cd swagsticker.com | ||
cp .env.template .env.development | ||
npm install | ||
``` | ||
|
||
### Run Locally | ||
#### Run Locally | ||
|
||
```sh | ||
cp .env.template .env.local | ||
npm run dev | ||
# visit http://locahost:3000 | ||
``` | ||
|
||
### Production Build | ||
#### Production Build | ||
|
||
```sh | ||
cp .env.template .env.production | ||
NODE_ENV=production npm run build | ||
npm run build | ||
``` | ||
|
||
## Resources | ||
#### Local Docker Container | ||
|
||
```sh | ||
cp .env.template .env.development | ||
docker-compose -f ./docker/development docker-compose.yml up -d | ||
# visit http://locahost:3001 | ||
``` | ||
|
||
## License | ||
|
||
GNU General Public License v3.0 or later | ||
|
||
- Next.js docs: https://nextjs.org/docs/getting-started/installation | ||
- Auth0 walkthrough: https://auth0.com/docs/quickstart/webapp/nextjs/interactive | ||
See [COPYING](COPYING) to see the full text. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,4 @@ | ||
/** @type {import('next').NextConfig} */ | ||
const nextConfig = { | ||
images: { | ||
remotePatterns: [ | ||
{ | ||
protocol: 'https', | ||
hostname: 'lh3.googleusercontent.com', | ||
port: '', | ||
pathname: '/**', | ||
}, | ||
{ | ||
protocol: 'https', | ||
hostname: 's.gravatar.com', | ||
port: '', | ||
pathname: '/**', | ||
}, | ||
], | ||
} | ||
}; | ||
const nextConfig = {}; | ||
|
||
export default nextConfig; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Diff not rendered.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<xml version="1.0" encoding="UTF-8"> | ||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> | ||
<url> | ||
<loc>http://www.swagsticker.com</loc> | ||
<lastmod>2024-10-14</lastmod> | ||
</url> | ||
</urlset> | ||
</xml> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
export default function ContactForm() { | ||
return ( | ||
<div className="my-8 mx-20"> | ||
<section className="container mx-auto px-4 py-8"> | ||
<h2 className="text-3xl font-bold mb-4">Contact Us</h2> | ||
<p className="text-gray-700 mb-4">For general inquiries or customer support, please email us at:</p> | ||
<a href="mailto:[email protected]" className="text-blue-500 hover:underline"> | ||
[email protected] | ||
</a> | ||
<h3 className="text-2xl font-semibold mt-6 mb-2">Contact Form</h3> | ||
<form action="https://public.herotofu.com/v1/aae45b10-27cb-11ed-9d54-c9f9d2b00e7b" method="post" acceptCharset="UTF-8" className="space-y-4"> | ||
<div> | ||
<input name="Name" placeholder="Full name" id="name" type="text" required className="border rounded-md px-4 py-2 w-full" data-testid="contact-form-name-input" /> | ||
</div> | ||
<div> | ||
<input name="Email" placeholder="Your email" id="email" type="email" required className="border rounded-md px-4 py-2 w-full" data-testid="contact-form-email-input" /> | ||
</div> | ||
<div> | ||
<textarea | ||
placeholder="Your message goes here..." | ||
data-testid="contact-form-message-input" | ||
name="message" | ||
required | ||
className="border rounded-md px-4 py-2 w-full h-24" | ||
></textarea> | ||
</div> | ||
<div> | ||
<input type="submit" value="Send Message" className="bg-blue-500 text-white font-bold py-2 px-4 rounded-md hover:bg-blue-600" /> | ||
<div aria-hidden="true"> | ||
<input type="text" name="_gotcha" tabIndex={-1} autoComplete="off" /> | ||
</div> | ||
</div> | ||
</form> | ||
</section> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
const faqs = [ | ||
{ | ||
question: 'How long do items take to produce/ship?', | ||
answer: 'Items are typically produced and shipped within 4-8 business days.', | ||
}, | ||
{ | ||
question: 'What is your return policy?', | ||
answer: | ||
'While we do not accept returns, we understand that sometimes things don't go as planned. If you're dissatisfied with your purchase, please contact our customer support team to discuss a possible refund. We'll do our best to find a solution that works for you.', | ||
}, | ||
{ | ||
question: 'What payment methods do you accept?', | ||
answer: 'We accept all major credit cards (Visa, Mastercard, American Express, Discover), debit cards, and digital wallets like Apple Pay and Google Pay.', | ||
}, | ||
{ | ||
question: 'Do you offer international shipping?', | ||
answer: 'No, we currently only offer shipping within the United States.', | ||
}, | ||
// { | ||
// question: 'Do you offer international shipping?', | ||
// answer: | ||
// 'Yes, we offer international shipping to most countries with estimated delivery times of 2-5 business days for US orders and 10-30 business days for international orders. Please enter your shipping address during checkout for accurate rates and times.', | ||
// }, | ||
{ | ||
question: 'How can I track my order?', | ||
answer: | ||
"Once your order has shipped, you will receive a tracking number via email. You can use this number to track the status of your shipment on the shipping carrier's website. You can also find your tracking number in your order details on your account page.", | ||
}, | ||
{ | ||
question: 'What if my item is damaged or defective?', | ||
answer: | ||
'If you receive a damaged or defective item, please contact our customer support team within 14 days of receiving your order. We will review your case and initiate a refund process if applicable. We do not accept returns for damaged or defective items.', | ||
}, | ||
{ | ||
question: 'Can I cancel my order?', | ||
answer: | ||
'Unfortunately, we do not currently support order cancellations. However, we are working on adding this feature in the near future. If your order has not yet shipped, please contact our customer support team to see if there are any other options available.', | ||
}, | ||
{ | ||
question: 'How do I contact customer support?', | ||
answer: | ||
'You can contact our customer support team by email at [email address]. Our customer support hours are [hours of operation]. For general inquiries or customer support, please visit our Contact page.', | ||
}, | ||
]; | ||
|
||
export default function FAQPage() { | ||
return ( | ||
<div className="my-8 mx-20"> | ||
<div className="container mx-auto px-4 py-8"> | ||
<h1 className="text-3xl font-bold mb-4">Frequently Asked Questions</h1> | ||
<ul className="list-disc pl-4 mt-2 list-none"> | ||
{faqs.map((faq, index) => ( | ||
<li key={index} className="text-gray-700 mt-4"> | ||
<span className="font-semibold">{faq.question}</span> | ||
<p>{faq.answer}</p> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
export default async function PrivacyPage() { | ||
return ( | ||
<div className="my-8 mx-20"> | ||
<div className="container mx-auto px-4 py-8"> | ||
<h1 className="text-3xl font-bold mb-4">Privacy Policy</h1> | ||
<p className="text-gray-700 leading-loose"> | ||
This Privacy Policy describes how we collect, use, and disclose your information when you use our website and the choices you have associated with that data. | ||
</p> | ||
<h2 className="text-2xl font-semibold mt-6 mb-2">Information We Collect</h2> | ||
<ul className="list-disc pl-4 mt-2"> | ||
<li className="text-gray-700">Name and Email Address: We collect your name and email address when you directly provide it to us through a form on this site.</li> | ||
<li className="text-gray-700"> | ||
Device Information: We use Google Analytics to collect information about your device, location (approximate), IP address, and usage of this site. | ||
</li> | ||
</ul> | ||
<h2 className="text-2xl font-semibold mt-6 mb-2">How We Use Your Information</h2> | ||
<p className="text-gray-700 leading-loose">We use the information we collect to:</p> | ||
<ul className="list-disc pl-4 mt-2"> | ||
<li className="text-gray-700">Communicate with you (using your email).</li> | ||
<li className="text-gray-700">Monitor usage and make decisions about content creation (using Google Analytics data).</li> | ||
</ul> | ||
<h2 className="text-2xl font-semibold mt-6 mb-2">Contact Us</h2> | ||
<p className="text-gray-700">If you have any questions or concerns about our privacy practices, please contact us at:</p> | ||
<a href="mailto:[email protected]" className="text-blue-500 hover:underline"> | ||
[email protected] | ||
</a> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,8 @@ | ||
import Image from 'next/image'; | ||
import { getSession } from '@auth0/nextjs-auth0'; | ||
|
||
// TODO_AUTH_ACCOUNT - page | ||
export default async function AccountPage() { | ||
const { user } = (await getSession()) || {}; | ||
|
||
return ( | ||
user && ( | ||
<div> | ||
<Image src={user.picture} alt={user.name} width="100" height="100" /> | ||
<h2>{user.name}</h2> | ||
<p>{user.email}</p> | ||
<a href="/api/auth/logout">Logout</a> | ||
</div> | ||
) | ||
<div> | ||
<p>w.i.p</p> | ||
</div> | ||
); | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.