Skip to content

Commit

Permalink
adjust for new cohort form
Browse files Browse the repository at this point in the history
  • Loading branch information
dgarcia-appdev committed Dec 30, 2024
1 parent bd32625 commit ac45566
Show file tree
Hide file tree
Showing 3 changed files with 262 additions and 14 deletions.
74 changes: 74 additions & 0 deletions src/app/cohorts/cohorts.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,80 @@
color: hsl(var(--white));
}

.notificationFormContainer {
border: 5px solid hsl(var(--light-blue));
max-width: 650px;
margin: 0 auto;
padding: 2rem;
border-radius: 2rem;
}

.notificationFormContainer button {
margin-top: 1rem;
width: 100%;
background-color: hsl(var(--light-blue));
color: hsl(var(--white));
border: none;
border-radius: 5px;
padding: 1rem;
}

.formGroup {
display: flex;
justify-content: space-between;
margin-bottom: 15px;
align-items: center;
}

.formGroup label {
flex: 1;
text-align: left;
}

.formGroup input,
.formGroup textarea,
.formGroup select {
flex: 2;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
.formGroup textarea {
resize: vertical;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.submit-btn:hover {
background-color: #0056b3;
}

.recaptcha {
display: flex;
justify-content: center;
}

.formMessage {
margin-top: 1rem;
}

.errorMessage {
color: #dc3545;
font-size: 1rem;
}

.successMessage {
color: #198754;
font-size: 1;
}

/* Mobile devices */
@media only screen and (max-width: 850px) {
}
Expand Down
127 changes: 127 additions & 0 deletions src/app/cohorts/notificationForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { useRef, useState } from 'react';
import ReCAPTCHA from 'react-google-recaptcha';
import styles from './cohorts.module.css';

class NotificationFormClass {
name: string;
email: string;
token: string;

constructor(name: string, email: string, token: string) {
this.name = name;
this.email = email;
this.token = token;
}
}

type Message = {
message: string;
type: 'error' | 'success';
};

const localEnv =
process.env.NODE_ENV === 'development' &&
process.env.NEXT_PUBLIC_APPWRITE_HASKEY === 'false';

const siteKey = process.env.NEXT_PUBLIC_RECAPTCHA_SITEKEY ?? '';

export default function NotificationForm() {
const [formData, setFormData] = useState(
new NotificationFormClass('', '', '')
);
const [message, setMessage] = useState<Message | null>(null);

const captchaRef = useRef<ReCAPTCHA>(null);

const handleChange = (event: any) => {
const { name, value } = event.target;
setFormData({ ...formData, [name]: value });
};

const handleSubmit = async (event: any) => {
event.preventDefault();
const token = localEnv ? 'localEnv' : captchaRef.current?.getValue();
if (!(token || localEnv)) {
console.log('display robot message');
setMessage({
message: 'Are you a robot? Please complete the reCAPTCHA',
type: 'error',
});
return;
}

formData.token = token ?? '';

try {
const responese = await fetch('/api/notificationForm', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
});

if (!responese.ok) {
setMessage({
message: responese.statusText,
type: 'error',
});
throw new Error(`Failed to submit form: ${responese.statusText}`);
}

setMessage({
message: 'Success! You will be notified when the next cohort opens.',
type: 'success',
});

setFormData(new NotificationFormClass('', '', ''));
} catch (error) {
console.error('error', error);
}
};

return (
<div className={styles.notificationFormContainer}>
<form onSubmit={handleSubmit} method='post'>
<div className={styles.formGroup}>
<label htmlFor='name'>Name</label>
<input
type='text'
id='name'
name='name'
required
value={formData.name}
onChange={handleChange}
/>
</div>
<div className={styles.formGroup}>
<label htmlFor='email'>Email</label>
<input
type='email'
id='email'
name='email'
required
value={formData.email}
onChange={handleChange}
/>
</div>
<div className={styles.recaptcha}>
{!localEnv && <ReCAPTCHA sitekey={siteKey} ref={captchaRef} />}
</div>
<button className='mdText' type='submit'>
Get Notified
</button>
</form>
<div
className={[
styles.formMessage,
message?.type === 'error'
? styles.errorMessage
: styles.successMessage,
].join(' ')}
>
{message?.message}
</div>
</div>
);
}
75 changes: 61 additions & 14 deletions src/app/cohorts/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
'use client';

import React from 'react';
import React, { useMemo } from 'react';
import styles from './cohorts.module.css';
import OfferingCard from '../components/offeringCard/offeringCard';
import CohortCard from '../components/cohortCard/cohortCard';
import Section from '../components/Section/section';

// TODO: Add appropriate links
import NotificationForm from './notificationForm';
import { useQuery } from '@tanstack/react-query';
import Button from '../components/button/button';
import { useGlobalState } from '../hooks/useGlobalState/useGlobalState';

interface Group {
id: number;
Expand All @@ -16,12 +17,24 @@ interface Group {
imageUrl?: string;
}

interface CohortStatus {
documentId: number;
statusType: string;
message: string;
active: boolean;
}

type CohortData = {
[year: number]: Group[];
};

const cohortStatusMessage =
'Cohorts are currently closed and registration will be announced in Discord when the next one opens.';
const defaultCohortStatusMessage = {
documentId: 0,
statusType: 'closed',
message:
'Cohorts are currently closed and registration will be announced in Discord when the next one opens.',
active: false,
} as CohortStatus;

// Data for the cohorts, add more elements to each year as needed
const cohortData: CohortData = {
Expand Down Expand Up @@ -62,9 +75,31 @@ const cohortData: CohortData = {
},
],
};

export default function CohortPage() {
const [selectedYear, setSelectedYear] = React.useState<number>(2024);

const { actionLinks } = useGlobalState();

const { data: cohortStatusResponse, isLoading } = useQuery({
queryKey: ['cohortStatus'],
queryFn: async () => {
const response = await fetch('/api/cohort', { cache: 'no-store' });
return response.json();
},
});

const currentCohortStatusData = useMemo(() => {
if (!cohortStatusResponse) {
return defaultCohortStatusMessage;
}
return cohortStatusResponse ?? defaultCohortStatusMessage;
}, [cohortStatusResponse]);

if (isLoading) {
return <h1>Loading...</h1>;
}

return (
<>
<Section isIntro classNames='bgBlue'>
Expand All @@ -78,16 +113,28 @@ export default function CohortPage() {
</p>
</Section>

{/*
//TODO: Uncomment when we find a way to handle cohort registration and notifications
<Section classNames='bgBlue'>
<h2>Cohort Information</h2>
<OfferingCard
text={cohortStatusMessage}
buttonText='Get Notified'
buttonLink='/'
/>
</Section> */}
<p>
{currentCohortStatusData.message}
{currentCohortStatusData.statusType === 'open' && (
<Button
buttonText='Apply Now'
onClick={() => {
if (!actionLinks) return;

const cohortSignupLink = actionLinks.find(
(x: any) => x.linkName === 'cohortSignup'
)?.link;
window.open(cohortSignupLink, '_blank');
}}
/>
)}
</p>
{currentCohortStatusData.statusType === 'closed' && (
<NotificationForm />
)}
</Section>

<Section classNames='bgBlue'>
<h2>Previous Cohorts</h2>
Expand Down

0 comments on commit ac45566

Please sign in to comment.