Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
49fa461
chore: add config for 2026 registration Google Sheet
DarshanCode2005 Dec 23, 2025
3875a32
feat: add Google Sheets append helper for 2026 registration
DarshanCode2005 Dec 23, 2025
d21a67e
feat: scaffold 2026 registration API route
DarshanCode2005 Dec 23, 2025
d2b312e
feat: add validation to 2026 registration API
DarshanCode2005 Dec 23, 2025
b8e4d02
feat: store 2026 registration submissions in Google Sheets
DarshanCode2005 Dec 23, 2025
5a4168a
feat: send confirmation email for 2026 registration
DarshanCode2005 Dec 23, 2025
74ad5b8
feat: add 2026 registration page scaffold
DarshanCode2005 Dec 23, 2025
ae32358
feat: add multi-step form structure for 2026 registration
DarshanCode2005 Dec 23, 2025
41caffa
feat: add form fields and client validation for registration
DarshanCode2005 Dec 23, 2025
9d84ce6
feat: connect registration form to API with success state
DarshanCode2005 Dec 23, 2025
75e8204
add googleapis package
DarshanCode2005 Dec 23, 2025
3ecfeb5
chore: add navigation and privacy notice
DarshanCode2005 Dec 23, 2025
401c61c
fix: fix the notes ci ts error
DarshanCode2005 Dec 23, 2025
058c7c5
Fix TypeScript error for 'notes' property in registration stepFour an…
DarshanCode2005 Dec 23, 2025
8199198
feat: add gradient image on the registration page
DarshanCode2005 Dec 24, 2025
b13e7a5
Merge branch 'master' into master
thulieblack Jan 6, 2026
7173ff6
Merge branch 'master' into master
thulieblack Jan 8, 2026
9701c49
Merge branch 'master' into master
AceTheCreator Jan 23, 2026
9fcf0cb
feat: add location dropdown to registration form
DarshanCode2005 Jan 24, 2026
e041ae2
refactor(ui): replace native button with Button component
DarshanCode2005 Jan 28, 2026
372abea
refactor(ui): replace native button with Button component
DarshanCode2005 Jan 28, 2026
656d9b1
refactor(ui): replace native button with Button component
DarshanCode2005 Jan 28, 2026
9004a08
refactor(ui): replace hardcoded year with dynamic current year
DarshanCode2005 Jan 28, 2026
6fc3625
refactor(ui): remove confusing UI stuff
DarshanCode2005 Jan 28, 2026
71c301c
chore(types): convert JavaScript file to TypeScript
DarshanCode2005 Jan 28, 2026
d23a1a7
chore(env): rename environment variables and remove year suffix
DarshanCode2005 Jan 28, 2026
b2b421c
chore(env): remove year suffix
DarshanCode2005 Jan 28, 2026
d67216f
chore(env): reverting back to simpler example env file
DarshanCode2005 Jan 28, 2026
b402b34
fix: move registration files to 2026 dir to restore routes
DarshanCode2005 Jan 28, 2026
bb47fa2
fix: use correct button classes
DarshanCode2005 Jan 28, 2026
e1314a3
fix: correct the folder name and final fixes
DarshanCode2005 Jan 28, 2026
c3e81fa
fix: cypress run CI tests
DarshanCode2005 Jan 29, 2026
eaa78ff
chore: remove unused content from register/2026 page
DarshanCode2005 Feb 3, 2026
32a89fb
refactor: improve email validation regex
DarshanCode2005 Feb 3, 2026
91b49c1
refactor: centralize email validation into shared utility
DarshanCode2005 Feb 3, 2026
7ebca0d
fix(a11y): add label and replace div for accessibility in stepOne
DarshanCode2005 Feb 3, 2026
a0c378b
fix(a11y): add label and replace div for accessibility in stepTwo
DarshanCode2005 Feb 3, 2026
1496624
fix(a11y): add label and replace div for accessibility in stepThree
DarshanCode2005 Feb 3, 2026
f86dcf3
fix(a11y): add label and replace div for accessibility in stepFour
DarshanCode2005 Feb 3, 2026
9d7d51c
style: increase label spacing and ensure block-level layout across st…
DarshanCode2005 Feb 3, 2026
79744a3
style: increase label spacing and ensure block-level layout across st…
DarshanCode2005 Feb 3, 2026
f346b0d
style: increase label spacing and ensure block-level layout across st…
DarshanCode2005 Feb 3, 2026
eb4f0a2
Merge branch 'master' into master
asyncapi-bot Feb 3, 2026
348cdb0
fix(types): add missing registration fields to CfpForm
DarshanCode2005 Feb 5, 2026
cf43871
fix(types): clean up stepThreetyping
DarshanCode2005 Feb 5, 2026
76720e3
feat(utils): validEmail utility
DarshanCode2005 Feb 5, 2026
3c626a5
feat(types): cleanup up stepThree Typing
DarshanCode2005 Feb 5, 2026
5333e72
feat(types): cleanup up stepTwo Typing
DarshanCode2005 Feb 5, 2026
3223f59
feat(types): cleanup up stepOne Typing
DarshanCode2005 Feb 5, 2026
7897d2b
feat(types): cleanup up stepFour Typing
DarshanCode2005 Feb 5, 2026
9eeb728
Merge branch 'master' of https://github.com/DarshanCode2005/conferenc…
DarshanCode2005 Feb 5, 2026
f2ff984
a11y: add visible focus ring styles to form inputs
DarshanCode2005 Feb 9, 2026
47ef55e
a11y: add aria-live for error announcements
DarshanCode2005 Feb 9, 2026
0066626
a11y: wrap checkboxes in fieldset for grouping
DarshanCode2005 Feb 9, 2026
afa20da
a11y: add focus management on step navigation
DarshanCode2005 Feb 9, 2026
640f953
a11y: add aria-invalid and error messages for validation
DarshanCode2005 Feb 9, 2026
d0596f6
a11y: add skip link to jump to form
DarshanCode2005 Feb 9, 2026
832c801
a11y: hide decorative confetti from screen readers
DarshanCode2005 Feb 9, 2026
11eb581
a11y: add semantic nav with aria-current for step indicators
DarshanCode2005 Feb 9, 2026
54858b1
a11y: add role=group with aria-labelledby to form sections
DarshanCode2005 Feb 9, 2026
47c38a5
a11y: add new tab indicator for external links
DarshanCode2005 Feb 9, 2026
916f328
a11y: add role=status to success message for screen readers
DarshanCode2005 Feb 9, 2026
d285128
chore(register/2026): remove the warning comment
DarshanCode2005 Feb 12, 2026
47d7f08
Merge branch 'master' into master
DarshanCode2005 Feb 12, 2026
3968777
Merge branch 'master' into master
AceTheCreator Feb 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions components/Form/Registration/stepFour.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* eslint-disable react/no-unescaped-entities */
import React, { FormEvent, useState, JSX } from 'react';
import Button from '../../Buttons/button';
import { CfpStepProps } from '../../../types/types';

type ApiResponse = { success?: boolean; error?: string };

function StepFourRegistration({ setStep, setForm, data }: CfpStepProps) {
const [submitting, setSubmitting] = useState<boolean>(false);
const [disabled, setDisabled] = useState<boolean>(false);
const [error, setError] = useState<string>('');

const onSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
setSubmitting(true);
setError('');

const payload = {
fullName: data.fullName || '',
email: data.email || '',
company: data.company || '',
role: data.role || '',
preferredCity: data.preferredCity || '',
attendanceType: data.attendanceType || '',
timezone: data.timezone || '',
dietaryAccessibility: data.dietaryAccessibility || '',
updatesOptIn: Boolean(data.updatesOptIn),
sponsorDataSharing: Boolean(data.sponsorDataSharing),
notes: data.notes || '',
};

fetch('/api/registration/2026', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})
.then(async (res) => {
const body: ApiResponse = await res.json().catch(() => ({}));
if (!res.ok) {
const message = body.error || `Submission failed (${res.status})`;
throw new Error(message);
}
return body;
})
.then(() => {
setSubmitting(false);
setDisabled(true);
setStep(e, 0);
})
.catch((err: Error) => {
setSubmitting(false);
setError(err.message || 'Submission failed');
});
};

return (
<form className="mt-3" onSubmit={(e) => onSubmit(e)} aria-busy={submitting}>
<h1 id="step-four-heading" className="text-white font-bold text-4xl lg:text-3xl">Review & Submit</h1>
<p className="mt-3 text-dark-600">Review your details and submit your registration.</p>
<div className="mt-3 border w-full border-solid border-y-dark-600 divide-y" />
<div className="mt-10" role="group" aria-labelledby="step-four-heading">
<label htmlFor="notes" className="text-dark-600 text-lg">Notes</label>
<textarea
id="notes"
className="mt-3 w-full p-4 rounded-md focus:outline-none focus:ring-2 focus:ring-[#E50E99] focus:ring-offset-2 focus:ring-offset-gray-900 border border-[#E50E99]"
onChange={(e) => setForm((prev) => ({ ...prev, notes: e.target.value }))}
data-test="reg-step-four-notes"
/>

<div className="mt-6 text-dark-600 text-md">
By clicking submit, you confirm the information is correct.
</div>
<div className="mt-3 w-full flex items-center justify-between lg:flex-col-reverse lg:items-start">
<div className="mt-3 w-full flex items-center justify-end lg:flex-col-reverse lg:items-start gap-4">
{/* Back button */}
<Button
type="button"
disabled={disabled}
onClick={() => !disabled && setStep(null, 3)}
className="text-gray-500 hover:text-gray-700 transition-colors disabled:opacity-50 w-36 lg:w-full"
>
Back
</Button>

{/* Submit button */}
<Button
type="submit"
disabled={submitting || disabled}
className="text-gray-500 hover:text-gray-700 transition-colors disabled:opacity-50 w-36 lg:w-full"
test="reg-step-four-next"
>
{submitting ? 'Submitting...' : 'Submit'}
</Button>
</div>

{error && (
<div
className="text-red-400 mt-2"
role="alert"
aria-live="assertive"
>
{error}
</div>
)}
</div>
</div>
</form>
);
}

export default StepFourRegistration;
83 changes: 83 additions & 0 deletions components/Form/Registration/stepOne.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* eslint-disable react/no-unescaped-entities */
import React, { JSX, useState } from 'react';
import Button from '../../Buttons/button';
import { CfpStepProps } from '../../../types/types';

import { isValidEmail } from '../../../utils/validation';

function StepOneRegistration({ setStep, setForm, data }: CfpStepProps): JSX.Element {
const [touched, setTouched] = useState(false);

const fullName = data.fullName ?? '';
const email = data.email ?? '';

const isValid = fullName.trim().length > 0 && isValidEmail(email.trim());

return (
<form
className="mt-3"
onSubmit={(e) => setStep(e, 2)}
data-test="reg-step-one"
onBlur={() => setTouched(true)}
>
<h1 id="step-one-heading" className="text-white font-bold text-4xl lg:text-3xl">Personal Info</h1>
<p className="mt-3 text-dark-600">Tell us who you are so we can prepare your ticket.</p>
<div className="mt-3 border w-full border-solid border-dark-400 divide-y" />
<div className="mt-10" role="group" aria-labelledby="step-one-heading">
<label htmlFor="fullName" className="text-dark-600 text-lg">
Full name <span aria-hidden="true">*</span>
</label>
<input
id="fullName"
required
aria-required="true"
aria-invalid={touched && fullName.trim().length === 0}
aria-describedby={touched && fullName.trim().length === 0 ? "fullName-error" : undefined}
value={fullName}
className="mt-3 w-full p-4 rounded-md focus:outline-none focus:ring-2 focus:ring-[#E50E99] focus:ring-offset-2 focus:ring-offset-gray-900 border border-[#E50E99]"
onChange={(e) => setForm((prev) => ({ ...prev, fullName: e.target.value }))}
data-test="reg-step-one-name"
/>
{touched && fullName.trim().length === 0 && (
<p id="fullName-error" className="text-red-400 text-sm mt-1" role="alert">
Full name is required
</p>
)}

<label htmlFor="email" className="text-dark-600 text-lg mt-6 block">
Email address <span aria-hidden="true">*</span>
</label>
<input
id="email"
required
type="email"
aria-required="true"
aria-invalid={touched && !isValidEmail(email.trim())}
aria-describedby={touched && !isValidEmail(email.trim()) ? "email-error" : undefined}
value={email}
className="mt-3 w-full p-4 rounded-md focus:outline-none focus:ring-2 focus:ring-[#E50E99] focus:ring-offset-2 focus:ring-offset-gray-900 border border-[#E50E99]"
onChange={(e) => setForm((prev) => ({ ...prev, email: e.target.value }))}
data-test="reg-step-one-email"
/>
{touched && !isValidEmail(email.trim()) && (
<p id="email-error" className="text-red-400 text-sm mt-1" role="alert">
Please enter a valid email address
</p>
)}

<div className="mt-6">
<Button
type="submit"
className="bg-tetiary-pink p-3 rounded-md text-white mt-6 float-right w-36 lg:w-full lg:mt-8"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @TenzDelek Sir, already it uses button component, if there is anything else required in this section then do let me know.

disabled={!isValid}
test="reg-step-one-next"
>
Next
</Button>
</div>
</div>
</form>
);
}

export default StepOneRegistration;
107 changes: 107 additions & 0 deletions components/Form/Registration/stepThree.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/* eslint-disable react/no-unescaped-entities */
import React, { JSX, useState } from 'react';
import Button from '../../Buttons/button';
import { CfpStepProps } from '../../../types/types';

function StepThreeRegistration({ setStep, setForm, data }: CfpStepProps): JSX.Element {

const dietary = data.dietaryAccessibility || '';
const updatesOptIn = !!data.updatesOptIn;
const sponsorDataSharing = !!data.sponsorDataSharing;
const notes = data.notes || '';

const [localUpdates, setLocalUpdates] = useState(updatesOptIn);
const [localSponsor, setLocalSponsor] = useState(sponsorDataSharing);

return (
<form className="mt-3" onSubmit={(e) => setStep(e, 4)} data-test="reg-step-three">
<h1 id="step-three-heading" className="text-white font-bold text-4xl lg:text-3xl">Consents & Notes</h1>
<p className="mt-3 text-dark-600">Tell us any dietary or accessibility needs and consent preferences.</p>
<div className="mt-3 border w-full border-solid border-dark-400 divide-y" />
<div className="mt-10" role="group" aria-labelledby="step-three-heading">
<label htmlFor="dietaryAccessibility" className="text-dark-600 text-lg">Dietary / Accessibility needs</label>
<textarea
id="dietaryAccessibility"
className="mt-3 w-full p-4 rounded-md focus:outline-none focus:ring-2 focus:ring-[#E50E99] focus:ring-offset-2 focus:ring-offset-gray-900 border border-[#E50E99]"
value={dietary}
onChange={(e) => setForm((prev) => ({ ...prev, dietaryAccessibility: e.target.value }))}
data-test="reg-step-three-dietary"
/>

<fieldset className="mt-5 border-0 p-0">
<legend className="text-dark-600 text-lg mb-3">Communication Preferences</legend>

<div className="text-dark-600">
<label className="inline-flex items-center">
<input
type="checkbox"
id="updatesOptIn"
checked={localUpdates}
onChange={(e) => {
setLocalUpdates(e.target.checked);
setForm((prev) => ({ ...prev, updatesOptIn: e.target.checked }));
}}
data-test="reg-step-three-updates"
className="mr-2 focus:ring-2 focus:ring-[#E50E99]"
/>
Receive occasional updates about the event
</label>
</div>

<div className="mt-3 text-dark-600">
<label className="inline-flex items-center">
<input
type="checkbox"
id="sponsorDataSharing"
checked={localSponsor}
onChange={(e) => {
setLocalSponsor(e.target.checked);
setForm((prev) => ({ ...prev, sponsorDataSharing: e.target.checked }));
}}
data-test="reg-step-three-sponsor"
className="mr-2 focus:ring-2 focus:ring-[#E50E99]"
/>
Share my contact with sponsors (optional)
</label>
</div>
</fieldset>

<div className="mt-3 text-sm text-dark-600">
We process your data according to our <a href="/privacy" className="underline">Privacy Policy</a>. By submitting you agree to the <a href="https://github.com/asyncapi/community/blob/master/CODE_OF_CONDUCT.md" target="_blank" rel="noreferrer" className="underline" aria-label="Code of Conduct (opens in new tab)">Code of Conduct<span className="sr-only"> (opens in new tab)</span></a> and Privacy Policy.
</div>

<label htmlFor="notes" className="text-dark-600 text-lg mt-6 block">Notes (optional)</label>
<textarea
id="notes"
className="mt-3 w-full p-4 rounded-md focus:outline-none focus:ring-2 focus:ring-[#E50E99] focus:ring-offset-2 focus:ring-offset-gray-900 border border-[#E50E99]"
value={notes}
onChange={(e) => setForm((prev) => ({ ...prev, notes: e.target.value }))}
data-test="reg-step-three-notes"
/>

<div className="mt-3 flex items-center justify-end gap-6 lg:flex-col-reverse lg:w-full lg:items-stretch">
{/* Back */}
<Button
type="button"
onClick={() => setStep(null, 2)}
className="text-gray-500 hover:text-gray-700 transition-colors lg:text-center w-36 lg:w-full"
>
Back
</Button>

{/* Next */}
<Button
type="submit"
className="text-gray-500 hover:text-gray-700 transition-colors lg:text-center w-36 lg:w-full"
test="reg-step-three-next"
>
Next
</Button>
</div>

</div>
</form>
);
}

export default StepThreeRegistration;
Loading