-
-
Notifications
You must be signed in to change notification settings - Fork 168
feat: /volunteer and /speakers forms with Google Sheets + email #1330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
e5b6cac
c1044bc
183c450
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { SpeakerForm } from "@/components/Speaker/SpeakerForm"; | ||
|
|
||
| export function SpeakersClient() { | ||
| return ( | ||
| <div className="bg-black"> | ||
| <div className="mx-auto max-w-3xl px-4 py-16 sm:px-6 sm:py-24 lg:px-8"> | ||
| <header className="mb-10"> | ||
| <p className="mb-4 inline-block rounded-full bg-gradient-to-r from-orange-400/20 to-pink-600/20 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-orange-300"> | ||
| Speak at Codú | ||
| </p> | ||
| <h1 className="text-3xl font-extrabold tracking-tight text-white sm:text-4xl"> | ||
| Pitch a talk at a Codú meetup | ||
| </h1> | ||
| <p className="mt-4 text-lg leading-relaxed text-neutral-300"> | ||
| Codú runs regular meetups across Ireland and we're always | ||
| looking for speakers. Whether it's your first talk or your | ||
| fiftieth, we'd love to hear your pitch. Propose a talk (or up | ||
| to three) and we'll be in touch. | ||
| </p> | ||
| </header> | ||
|
|
||
| <SpeakerForm /> | ||
|
|
||
| <p className="mt-6 text-center text-sm text-neutral-400"> | ||
| Takes about 3 minutes. First-time speakers welcome — we'll help | ||
| you prep. | ||
| </p> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import type { Metadata } from "next"; | ||
| import { JsonLd } from "@/components/JsonLd"; | ||
| import { SpeakersClient } from "./_client"; | ||
|
|
||
| const PAGE_URL = "https://www.codu.co/speakers"; | ||
| const PAGE_TITLE = "Speak at Codú — Pitch a Talk for Our Meetups"; | ||
| const PAGE_DESCRIPTION = | ||
| "Pitch a talk at a Codú meetup. First-time speakers welcome. We run regular developer meetups across Ireland and are always looking for people to share what they've built, learned, or broken."; | ||
|
|
||
| export const metadata: Metadata = { | ||
| title: PAGE_TITLE, | ||
| description: PAGE_DESCRIPTION, | ||
| keywords: [ | ||
| "Codú speaker", | ||
| "tech meetup speaker Ireland", | ||
| "developer meetup Dublin", | ||
| "first time speaker", | ||
| "web development talk", | ||
| "speak at meetup Ireland", | ||
| ], | ||
| alternates: { canonical: PAGE_URL }, | ||
| robots: { index: true, follow: true }, | ||
| openGraph: { | ||
| title: "Speak at Codú", | ||
| description: PAGE_DESCRIPTION, | ||
| url: PAGE_URL, | ||
| type: "website", | ||
| }, | ||
| twitter: { | ||
| card: "summary_large_image", | ||
| title: "Speak at Codú", | ||
| description: PAGE_DESCRIPTION, | ||
| }, | ||
| }; | ||
|
|
||
| const speakerJsonLd = { | ||
| "@context": "https://schema.org", | ||
| "@type": "JobPosting", | ||
| title: "Speaker — Codú Meetups", | ||
| description: PAGE_DESCRIPTION, | ||
| employmentType: "VOLUNTEER", | ||
| hiringOrganization: { | ||
| "@type": "Organization", | ||
| name: "Codú", | ||
| sameAs: "https://www.codu.co", | ||
| logo: "https://www.codu.co/images/codu-logo.png", | ||
| }, | ||
| jobLocation: { | ||
| "@type": "Place", | ||
| address: { | ||
| "@type": "PostalAddress", | ||
| addressLocality: "Dublin", | ||
| addressCountry: "IE", | ||
| }, | ||
| }, | ||
| applicantLocationRequirements: { "@type": "Country", name: "Worldwide" }, | ||
| jobLocationType: "TELECOMMUTE", | ||
| datePosted: new Date().toISOString().split("T")[0], | ||
| url: PAGE_URL, | ||
| }; | ||
|
|
||
| export default function SpeakersPage() { | ||
| return ( | ||
| <> | ||
| <JsonLd data={speakerJsonLd} /> | ||
| <SpeakersClient /> | ||
| </> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { VolunteerForm } from "@/components/Volunteer/VolunteerForm"; | ||
|
|
||
| export function VolunteerClient() { | ||
| return ( | ||
| <div className="bg-black"> | ||
| <div className="mx-auto max-w-3xl px-4 py-16 sm:px-6 sm:py-24 lg:px-8"> | ||
| <header className="mb-10"> | ||
| <p className="mb-4 inline-block rounded-full bg-gradient-to-r from-orange-400/20 to-pink-600/20 px-3 py-1 text-xs font-semibold uppercase tracking-wide text-orange-300"> | ||
| Volunteer with Codú | ||
| </p> | ||
| <h1 className="text-3xl font-extrabold tracking-tight text-white sm:text-4xl"> | ||
| Help us build Ireland's largest web dev community | ||
| </h1> | ||
| <p className="mt-4 text-lg leading-relaxed text-neutral-300"> | ||
| Codú is Ireland's largest web dev community — thousands of | ||
| developers, regular meetups, and a newsletter across the Irish tech | ||
| ecosystem. We're opening volunteer spots for people interested | ||
| in marketing and events. | ||
| </p> | ||
| </header> | ||
|
|
||
| <VolunteerForm /> | ||
|
|
||
| <p className="mt-6 text-center text-sm text-neutral-400"> | ||
| Takes about 3 minutes. We read every application and reply within 2 | ||
| weeks. | ||
| </p> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,69 @@ | ||||||||||||||||||||||||||||
| import type { Metadata } from "next"; | ||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||||||||||||
| import { JsonLd } from "@/components/JsonLd"; | ||||||||||||||||||||||||||||
| import { VolunteerClient } from "./_client"; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const PAGE_URL = "https://www.codu.co/volunteer"; | ||||||||||||||||||||||||||||
| const PAGE_TITLE = "Volunteer with Codú — Help Build Ireland's Largest Dev Community"; | ||||||||||||||||||||||||||||
| const PAGE_DESCRIPTION = | ||||||||||||||||||||||||||||
| "Join the team behind Codú. We're recruiting volunteer marketers and event organisers to help run meetups, newsletters, partnerships, and socials across the Irish tech ecosystem."; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| export const metadata: Metadata = { | ||||||||||||||||||||||||||||
| title: PAGE_TITLE, | ||||||||||||||||||||||||||||
| description: PAGE_DESCRIPTION, | ||||||||||||||||||||||||||||
| keywords: [ | ||||||||||||||||||||||||||||
| "Codú volunteer", | ||||||||||||||||||||||||||||
| "volunteer developer community", | ||||||||||||||||||||||||||||
| "Ireland tech community", | ||||||||||||||||||||||||||||
| "web developer volunteer", | ||||||||||||||||||||||||||||
| "tech meetup organiser Ireland", | ||||||||||||||||||||||||||||
| "marketing volunteer", | ||||||||||||||||||||||||||||
| "events volunteer", | ||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||
| alternates: { canonical: PAGE_URL }, | ||||||||||||||||||||||||||||
| robots: { index: true, follow: true }, | ||||||||||||||||||||||||||||
| openGraph: { | ||||||||||||||||||||||||||||
| title: "Volunteer with Codú", | ||||||||||||||||||||||||||||
| description: PAGE_DESCRIPTION, | ||||||||||||||||||||||||||||
| url: PAGE_URL, | ||||||||||||||||||||||||||||
| type: "website", | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| twitter: { | ||||||||||||||||||||||||||||
| card: "summary_large_image", | ||||||||||||||||||||||||||||
| title: "Volunteer with Codú", | ||||||||||||||||||||||||||||
| description: PAGE_DESCRIPTION, | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const volunteerJsonLd = { | ||||||||||||||||||||||||||||
| "@context": "https://schema.org", | ||||||||||||||||||||||||||||
| "@type": "JobPosting", | ||||||||||||||||||||||||||||
| title: "Volunteer — Marketing & Events", | ||||||||||||||||||||||||||||
| description: PAGE_DESCRIPTION, | ||||||||||||||||||||||||||||
| employmentType: "VOLUNTEER", | ||||||||||||||||||||||||||||
| hiringOrganization: { | ||||||||||||||||||||||||||||
| "@type": "Organization", | ||||||||||||||||||||||||||||
| name: "Codú", | ||||||||||||||||||||||||||||
| sameAs: "https://www.codu.co", | ||||||||||||||||||||||||||||
| logo: "https://www.codu.co/images/codu-logo.png", | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| jobLocation: { | ||||||||||||||||||||||||||||
| "@type": "Place", | ||||||||||||||||||||||||||||
| address: { | ||||||||||||||||||||||||||||
| "@type": "PostalAddress", | ||||||||||||||||||||||||||||
| addressCountry: "IE", | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||
| applicantLocationRequirements: { "@type": "Country", name: "Worldwide" }, | ||||||||||||||||||||||||||||
| jobLocationType: "TELECOMMUTE", | ||||||||||||||||||||||||||||
| datePosted: new Date().toISOString().split("T")[0], | ||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's locate and read the file
find . -name "page.tsx" -path "*/volunteer/*" -type fRepository: codu-code/codu Length of output: 88 🏁 Script executed: # Get more context around lines 56-58
sed -n '50,65p' "app/(app)/volunteer/page.tsx" | cat -nRepository: codu-code/codu Length of output: 563 🌐 Web query:
💡 Result: Google's requirements for the applicantLocationRequirements property in JobPosting structured data are as follows: The property specifies the geographic location(s) from which applicants can apply, primarily for telecommuting or remote jobs. It is of type AdministrativeArea (e.g., Country, State) according to Schema.org. Key guidelines from official Google documentation: - Use it with jobLocationType: "TELECOMMUTE" for remote jobs. - At least one country is required for work-from-home jobs. - If omitted for remote jobs, Google defaults to the country in jobLocation. - Do not use for citizenship or work visa requirements (use eligibilityToWorkRequirement instead). - Can be an array for multiple locations. - Example: {"@type": "Country", "name": "USA"} It is recommended (not strictly required) for rich results eligibility, but essential for correct display of remote job restrictions to avoid validation errors in Search Console. Examples from docs: { "applicantLocationRequirements": { "@type": "Country", "name": "USA" }, "jobLocationType": "TELECOMMUTE" } Citations:
🌐 Web query:
💡 Result: The schema.org JobPosting property applicantLocationRequirements specifies the location(s) from which applicants can apply, typically for telecommute jobs. Its expected type is AdministrativeArea, which includes Country as a subtype (since Country extends AdministrativeArea). When using Country for applicantLocationRequirements, valid values are instances of the Country type. There is no fixed enumerated list of valid countries; instead, use: - Citations:
Use concrete JobPosting location metadata and a fixed posting date.
Given the address uses Proposed fix+const VOLUNTEER_POSTED_DATE = "2026-04-21";
+
const volunteerJsonLd = {
"@context": "https://schema.org",
"@type": "JobPosting",
@@
- applicantLocationRequirements: { "@type": "Country", name: "Worldwide" },
+ applicantLocationRequirements: { "@type": "Country", name: "Ireland" },
jobLocationType: "TELECOMMUTE",
- datePosted: new Date().toISOString().split("T")[0],
+ datePosted: VOLUNTEER_POSTED_DATE,
url: PAGE_URL,
};If applicants are genuinely eligible from multiple countries, enumerate those countries explicitly and ensure the visible page copy clearly states the 100% remote arrangement. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| url: PAGE_URL, | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| export default function VolunteerPage() { | ||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||
| <JsonLd data={volunteerJsonLd} /> | ||||||||||||||||||||||||||||
| <VolunteerClient /> | ||||||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.