diff --git a/env.sample b/env.sample
index 4669820..40b2873 100644
--- a/env.sample
+++ b/env.sample
@@ -1,2 +1,4 @@
HASURA_GRAPHQL_ADMIN_SECRET=
-NEXT_PUBLIC_API_URL=
\ No newline at end of file
+NEXT_PUBLIC_API_URL=
+EMAIL_REFERRALS_API_URL=
+FORM_INGEST_API_KEY=
diff --git a/src/app/api/email-referrals/route.ts b/src/app/api/email-referrals/route.ts
new file mode 100644
index 0000000..76e239d
--- /dev/null
+++ b/src/app/api/email-referrals/route.ts
@@ -0,0 +1,91 @@
+import { NextRequest, NextResponse } from "next/server";
+import { z } from "zod";
+
+const emailReferralSchema = z.object({
+ email: z.email("Valid email is required"),
+ referral: z.string().optional(),
+});
+
+export async function POST(request: NextRequest) {
+ try {
+ const body = await request.json();
+ const validationResult = emailReferralSchema.safeParse(body);
+
+ if (!validationResult.success) {
+ const errors = validationResult.error.issues.map((issue) => ({
+ field: issue.path.join("."),
+ message: issue.message,
+ }));
+
+ return NextResponse.json(
+ {
+ success: false,
+ error: "Validation failed",
+ details: errors,
+ },
+ { status: 400 }
+ );
+ }
+
+ const apiUrl = process.env.EMAIL_REFERRALS_API_URL;
+ const apiKey = process.env.FORM_INGEST_API_KEY;
+
+ if (!apiUrl || !apiKey) {
+ return NextResponse.json(
+ {
+ success: false,
+ error: "Email referral API is not configured",
+ },
+ { status: 500 }
+ );
+ }
+
+ const response = await fetch(apiUrl, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "x-form-api-key": apiKey,
+ },
+ body: JSON.stringify(validationResult.data),
+ });
+
+ const contentType = response.headers.get("content-type") || "";
+ const responseBody = contentType.includes("application/json")
+ ? await response.json()
+ : await response.text();
+
+ if (!response.ok) {
+ return NextResponse.json(
+ {
+ success: false,
+ error:
+ (typeof responseBody === "object" &&
+ responseBody &&
+ "error" in responseBody &&
+ responseBody.error) ||
+ responseBody ||
+ "Failed to submit email referral",
+ },
+ { status: response.status }
+ );
+ }
+
+ return NextResponse.json(
+ {
+ success: true,
+ data: responseBody || { ok: true },
+ },
+ { status: 200 }
+ );
+ } catch (error) {
+ console.error("Error submitting email referral:", error);
+
+ return NextResponse.json(
+ {
+ success: false,
+ error: "Failed to submit email referral",
+ },
+ { status: 500 }
+ );
+ }
+}
diff --git a/src/app/join/page.tsx b/src/app/join/page.tsx
index a5b481c..8f2f142 100644
--- a/src/app/join/page.tsx
+++ b/src/app/join/page.tsx
@@ -9,7 +9,16 @@ import CohortValueSection from "@/components/CohortValueSection";
import CohortJoinBanner from "@/components/CohortJoinBanner";
import JoinUsSection from "@/components/JoinUsSection";
-export default function Home() {
+type JoinPageProps = {
+ searchParams?: {
+ ref?: string;
+ referral?: string;
+ };
+};
+
+export default function Home({ searchParams }: JoinPageProps) {
+ const referral = searchParams?.referral ?? searchParams?.ref;
+
return (
@@ -26,7 +35,7 @@ export default function Home() {
-
+
diff --git a/src/components/JoinUs.tsx b/src/components/JoinUs.tsx
index 2854afd..26d64d1 100644
--- a/src/components/JoinUs.tsx
+++ b/src/components/JoinUs.tsx
@@ -5,7 +5,6 @@ import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useState } from "react";
import { Input } from "@/components/ui/input";
-import { Textarea } from "@/components/ui/textarea";
import {
Form,
FormControl,
@@ -14,11 +13,7 @@ import {
FormLabel,
RequiredFieldIndicator,
} from "@/components/ui/form";
-import {
- joinUsFormSchema,
- type JoinUsFormData,
- transformApplicationDataToApiFormat,
-} from "@/lib/validation";
+import { joinUsFormSchema, type JoinUsFormData } from "@/lib/validation";
import Image from "next/image";
import { trackEvent } from "fathom-client";
@@ -29,7 +24,11 @@ const joinUsImages = [
"/images/join-image-2-c.webp",
];
-export default function JoinUs() {
+type JoinUsProps = {
+ referral?: string;
+};
+
+export default function JoinUs({ referral }: JoinUsProps) {
// Deterministic image selection based on 8-minute intervals (no flash, no hydration mismatch)
const interval = Math.floor(Date.now() / (1000 * 60 * 8)); // 8 minutes
const imageSrc = joinUsImages[interval % joinUsImages.length];
@@ -39,23 +38,17 @@ export default function JoinUs() {
"idle" | "success" | "error"
>("idle");
const [errorMessage, setErrorMessage] = useState("");
-
const form = useForm({
resolver: zodResolver(joinUsFormSchema),
defaultValues: {
- name: "",
email: "",
- discordHandle: "",
- showcaseComments: "",
- showcaseUrl: "",
- introduction: "",
},
});
const onSubmit = async (data: JoinUsFormData) => {
if (isSubmitting) return; // Prevent multiple submissions
- console.log("Join Us form submitted:", data);
+ console.log("Join Us email submitted:", data);
// Reset states
setIsSubmitting(true);
@@ -63,20 +56,21 @@ export default function JoinUs() {
setErrorMessage("");
try {
- const applicationData = transformApplicationDataToApiFormat(data);
-
- const response = await fetch("/api/applications", {
+ const response = await fetch("/api/email-referrals", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
- body: JSON.stringify({ applicationData }),
+ body: JSON.stringify({
+ email: data.email,
+ ...(referral ? { referral } : {}),
+ }),
});
const result = await response.json();
if (response.ok) {
- console.log("Application submitted successfully:", result);
+ console.log("Email referral submitted successfully:", result);
setSubmissionStatus("success");
//tracking
@@ -84,10 +78,10 @@ export default function JoinUs() {
// Reset form after successful submission
form.reset();
} else {
- console.error("Failed to submit application:", result);
+ console.error("Failed to submit email referral:", result);
setSubmissionStatus("error");
setErrorMessage(
- result.error || "Failed to submit application. Please try again.",
+ result.error || "Failed to submit. Please try again.",
);
}
} catch (error) {
@@ -105,7 +99,7 @@ export default function JoinUs() {
const SuccessState = () => (
- Your Words Have Been Passed On.
+ You're On The List.
-
+
+ Watch your inbox for next steps.
+
);
@@ -184,13 +172,11 @@ export default function JoinUs() {
{submissionStatus === "success" ? (
- Thank you for your interest in joining RaidGuild!
+ Thanks for joining the cohort updates.
) : (
- Ready to embark on your journey and join the ranks? Share
- your tale with us—what epic skills await the Guild's
- discovery?
+ Drop your email to start the onboarding journey.
)}
@@ -211,103 +197,16 @@ export default function JoinUs() {
>
(
-
-
- Name
-
-
-
-
-
- )}
- />
-
- (
-
-
- Email Address
-
-
-
-
-
- )}
- />
- (
-
- Discord Username
-
-
-
-
- )}
- />
-
-
- (
-
-
- Introduce Yourself
-
-
-
-
-
- )}
- />
-
- (
-
-
- Work You're Proud Of{" "}
-
-
-
-
-
-
- )}
- />
-
- (
- Link to Your Work
+ Email Address
diff --git a/src/components/JoinUsSection.tsx b/src/components/JoinUsSection.tsx
index 08cbfb5..5dc9248 100644
--- a/src/components/JoinUsSection.tsx
+++ b/src/components/JoinUsSection.tsx
@@ -1,5 +1,9 @@
import JoinUs from "./JoinUs";
-export default function JoinUsSection() {
- return ;
+type JoinUsSectionProps = {
+ referral?: string;
+};
+
+export default function JoinUsSection({ referral }: JoinUsSectionProps) {
+ return ;
}
diff --git a/src/lib/validation.ts b/src/lib/validation.ts
index d6ae4f9..8401ea1 100644
--- a/src/lib/validation.ts
+++ b/src/lib/validation.ts
@@ -87,23 +87,9 @@ export const consultationApiSchema = z.object({
// Join Us form schema
export const joinUsFormSchema = z.object({
- name: z.string().min(2, {
- message: "Name is required.",
- }),
email: z.email({
message: "Please enter a valid email address.",
}),
- discordHandle: z.string().optional(),
- showcaseComments: z.string().min(10, {
- message:
- "Please describe the work you're proud of (at least 10 characters).",
- }),
- showcaseUrl: z.url({
- message: "Please enter a valid URL for your work.",
- }),
- introduction: z.string().min(10, {
- message: "Please provide a brief introduction (at least 10 characters).",
- }),
});
// Server-side validation schema for the API
@@ -188,26 +174,3 @@ export const transformFormDataToApiFormat = (formData: HireUsFormData) => {
};
// Helper function to transform application form data to API format
-export const transformApplicationDataToApiFormat = (
- formData: JoinUsFormData
-) => {
- return {
- contact_info: {
- data: {
- email: formData.email,
- discord: formData.discordHandle,
- },
- },
- name: formData.name,
- introduction: formData.introduction,
- comments: formData.showcaseComments,
- links: {
- data: [
- {
- type: "OTHER",
- link: formData.showcaseUrl,
- },
- ],
- },
- };
-};