-
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.
Merge pull request #78 from Etherna/feature/EWEB-90-antihill-page
Feature/eweb 90 antihill page
- Loading branch information
Showing
17 changed files
with
1,961 additions
and
1,992 deletions.
There are no files selected for viewing
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
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
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 |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { defineEndpoint } from "@directus/extensions" | ||
import mailchimp from "@mailchimp/mailchimp_marketing" | ||
import axios, { isAxiosError } from "axios" | ||
|
||
require("dotenv").config() | ||
|
||
export default defineEndpoint({ | ||
id: "subscribe", | ||
handler(router, context) { | ||
router.post("/:list", async (req, res) => { | ||
try { | ||
mailchimp.setConfig({ | ||
apiKey: process.env.MAILCHIMP_TOKEN, | ||
server: process.env.MAILCHIMP_SERVER, | ||
}) | ||
|
||
const submission = req.body as { | ||
email: string | ||
fname: string | ||
lname?: string | ||
mailchimpTags?: string | ||
} | ||
|
||
const listId = req.params.list | ||
const tags = (submission.mailchimpTags ?? "") | ||
.split(",") | ||
.map((tag) => tag.trim()) | ||
.filter((tag) => tag) | ||
const email = submission.email | ||
|
||
const member = { | ||
email_address: email, | ||
status: "pending", | ||
tags, | ||
merge_fields: { | ||
FNAME: submission.fname, | ||
LNAME: submission.lname ?? "", | ||
}, | ||
} satisfies mailchimp.lists.AddListMemberBody | ||
|
||
const url = `https://${process.env.MAILCHIMP_SERVER}.api.mailchimp.com/3.0/lists/${listId}/members` | ||
const resp = await axios.post( | ||
url, | ||
{ | ||
email_address: email, | ||
status: "pending", | ||
tags, | ||
merge_fields: { | ||
FNAME: submission.fname, | ||
LNAME: submission.lname ?? "", | ||
}, | ||
}, | ||
{ | ||
headers: { | ||
Authorization: `Bearer ${process.env.MAILCHIMP_TOKEN}`, | ||
"Content-Type": "application/json", | ||
}, | ||
}, | ||
) | ||
|
||
res.json({ status: "ok", code: "DONE" }) | ||
} catch (err) { | ||
if (isAxiosError(err) && err.response?.data.title === "Member Exists") { | ||
res.status(200).json({ status: "ok", code: "EXIST" }) | ||
return | ||
} | ||
|
||
const error = isAxiosError(err) ? err.response?.data : err | ||
console.error(error) | ||
|
||
res.status(400).json({ status: "error", error }) | ||
} | ||
}) | ||
}, | ||
}) |
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,5 +1,5 @@ | ||
{ | ||
"_variables": { | ||
"lastUpdateCheck": 1725632250401 | ||
"lastUpdateCheck": 1730650544720 | ||
} | ||
} |
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,4 +1,6 @@ | ||
PUBLIC_SITE_URL="http://localhost:3000" | ||
PUBLIC_DIRECTUS_URL="http://localhost:8055" | ||
PUBLIC_MAILCHIMP_AUDIENCE_ID="xxxxxxxxx" | ||
PUBLIC_MAILCHIMP_PRODUCT_AUDIENCE_ID="xxxxxxxxx" | ||
ANALYTICS_URL="https://analytics.etherna.test" | ||
ANALYTICS_SITE_ID="1" |
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
126 changes: 126 additions & 0 deletions
126
apps/web/src/components/landing/product-subscription-form.tsx
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,126 @@ | ||
import { useState } from "react" | ||
import { useTranslation } from "react-i18next" | ||
import axios from "axios" | ||
|
||
import { SpinnerLight } from "@/components/assets/animated" | ||
|
||
import { Alert } from "@/components/common/alert" | ||
import { Button } from "@/components/common/button" | ||
import { cn } from "@/utils/classnames" | ||
import { userLocale } from "@/utils/lang" | ||
import { routes } from "@/utils/routes" | ||
import { validateEmail } from "@/utils/validation" | ||
|
||
import type { InputHTMLAttributes } from "react" | ||
|
||
export function ProductSubscriptionForm() { | ||
const [firstName, setFirstName] = useState("") | ||
const [email, setEmail] = useState("") | ||
const [isSubmitting, setIsSubmitting] = useState(false) | ||
const [error, setError] = useState<string>() | ||
const [isSuccess, setIsSuccess] = useState(false) | ||
const { t } = useTranslation("landing") | ||
|
||
const sendFormRequest = async () => { | ||
setIsSubmitting(true) | ||
|
||
try { | ||
// fields validation | ||
if (firstName.length < 2) { | ||
setIsSubmitting(false) | ||
setError(t("subcribeErrorName")) | ||
return | ||
} | ||
if (email.length === 0 || !validateEmail(email)) { | ||
setIsSubmitting(false) | ||
setError(t("subcribeErrorEmail")) | ||
return | ||
} | ||
|
||
const audienceId = import.meta.env.PUBLIC_MAILCHIMP_PRODUCT_AUDIENCE_ID | ||
const apiEndpoint = `${import.meta.env.PUBLIC_DIRECTUS_URL}/subscribe/${audienceId}` | ||
await axios.post(apiEndpoint, { | ||
email, | ||
fname: firstName, | ||
mailchimpTags: `anthill,website,${userLocale()}`, | ||
}) | ||
|
||
sessionStorage.setItem("subscriber:email", email) | ||
|
||
setError(undefined) | ||
setIsSubmitting(false) | ||
setIsSuccess(true) | ||
setEmail("") | ||
setFirstName("") | ||
} catch (err) { | ||
console.error(err) | ||
setError(t("subcribeErrorDescription")) | ||
setIsSubmitting(false) | ||
} | ||
} | ||
|
||
return ( | ||
<> | ||
<form className="flex w-full flex-col gap-4"> | ||
<NewsletterFormField | ||
type="text" | ||
className="w-full rounded-md lg:max-w-full" | ||
placeholder={t("namePlaceholder")} | ||
autoComplete="name" | ||
value={firstName} | ||
onChange={e => setFirstName(e.target.value)} | ||
/> | ||
<NewsletterFormField | ||
type="email" | ||
className="w-full rounded-md lg:max-w-full" | ||
placeholder={t("emailPlaceholder")} | ||
autoComplete="email" | ||
inputMode="email" | ||
value={email} | ||
onChange={e => setEmail(e.target.value)} | ||
/> | ||
|
||
<Button | ||
className="h-10 w-full justify-center text-center" | ||
type="primary" | ||
disabled={isSubmitting} | ||
onClick={sendFormRequest} | ||
> | ||
{isSubmitting && <SpinnerLight className="mr-2 h-6 w-6" />} | ||
Subscribe | ||
</Button> | ||
</form> | ||
|
||
{error && ( | ||
<div className="my-4 w-full max-w-4xl"> | ||
<Alert type="danger" title={t("subcribeErrorTitle")} onClose={() => setError(undefined)}> | ||
{error} | ||
</Alert> | ||
</div> | ||
)} | ||
|
||
{isSuccess && ( | ||
<div className="my-4 w-full max-w-4xl"> | ||
<Alert type="success" title="Almost done!"> | ||
Thank you for your submission. Please check your inbox for a confirmation email. | ||
</Alert> | ||
</div> | ||
)} | ||
</> | ||
) | ||
} | ||
|
||
function NewsletterFormField({ className, ...props }: InputHTMLAttributes<HTMLInputElement>) { | ||
return ( | ||
<input | ||
{...props} | ||
className={cn( | ||
"z-0 w-full rounded-none border border-gray-300 bg-transparent px-4 py-3 transition duration-200 ", | ||
"text-sm placeholder:text-sm placeholder:text-gray-500", | ||
"focus:z-10 focus:border-primary-500 focus:bg-white focus:outline-none", | ||
"lg:-mr-px lg:max-w-64 lg:border-b lg:focus:border-b", | ||
className | ||
)} | ||
/> | ||
) | ||
} |
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,60 @@ | ||
--- | ||
import { Image as AstroImg } from "astro:assets" | ||
import gatewayImg from "@/assets/anthill.png" | ||
import Layout from "@/astro/layout/layout.astro" | ||
import { ProductSubscriptionForm } from "@/components/landing/product-subscription-form" | ||
--- | ||
|
||
<Layout title="Etherna Gateway" description="A game changer for cloud storage" lang="en"> | ||
<div class="container flex flex-col items-center gap-y-12 py-12 md:flex-row-reverse"> | ||
<AstroImg src={gatewayImg} alt="Etherna Gateway" class="w-full max-w-64 xl:max-w-80" /> | ||
<div class="flex flex-1 flex-col items-center md:items-start"> | ||
<h1 class="text-3xl font-extrabold text-gradient md:text-4xl lg:text-5xl">Etherna Anthill</h1> | ||
<p | ||
class="max-w-screen-sm text-center text-base font-medium text-gray-500 md:text-left lg:text-lg" | ||
> | ||
A drop-in replacement for AWS S3, Cloudflare R2 or any other cloud object storage | ||
available... And of course, it's decentralized! | ||
</p> | ||
</div> | ||
</div> | ||
|
||
<div class="bg-white py-20"> | ||
<ul class="container grid grid-cols-1 gap-4 xs:grid-cols-2 sm:grid-cols-3 sm:gap-8"> | ||
<li class="flex flex-col"> | ||
<h3 class="mb-1 text-base">DDOS resistant</h3> | ||
<p class="text-sm text-gray-400"> | ||
A decentralized storage is a resistent one, as it is not a single point of failure | ||
</p> | ||
</li> | ||
<li class="flex flex-col"> | ||
<h3 class="mb-1 text-base">Best compatibility</h3> | ||
<p class="text-sm text-gray-400"> | ||
Anthill is compatible with any S3-compatible client, making it easy to integrate | ||
</p> | ||
</li> | ||
<li class="flex flex-col"> | ||
<h3 class="mb-1 text-base">Fast</h3> | ||
<p class="text-sm text-gray-400"> | ||
Data is retrieved from the nearest node, reducing latency and increasing speed | ||
</p> | ||
</li> | ||
</ul> | ||
</div> | ||
|
||
<div class="bg-gradient-to-b from-white to-gray-200 py-20"> | ||
<div class="container flex flex-col items-center text-center"> | ||
<h2>Subscribe for future updates</h2> | ||
<p class="max-w-sm text-sm text-gray-500"> | ||
Anthill is still under development. Subscribe to our newsletter to get updates on our | ||
progress. | ||
</p> | ||
|
||
<div class="mt-12 w-full max-w-sm md:mt-20"> | ||
<ProductSubscriptionForm client:idle /> | ||
</div> | ||
</div> | ||
</div> | ||
</Layout> |
Oops, something went wrong.