From ac45566de56b4db7dbd540ecd9ab8f1a404143aa Mon Sep 17 00:00:00 2001
From: Dennis Garcia
Date: Sun, 29 Dec 2024 19:25:45 -0600
Subject: [PATCH] adjust for new cohort form
---
src/app/cohorts/cohorts.module.css | 74 ++++++++++++++++
src/app/cohorts/notificationForm.tsx | 127 +++++++++++++++++++++++++++
src/app/cohorts/page.tsx | 75 +++++++++++++---
3 files changed, 262 insertions(+), 14 deletions(-)
create mode 100644 src/app/cohorts/notificationForm.tsx
diff --git a/src/app/cohorts/cohorts.module.css b/src/app/cohorts/cohorts.module.css
index 4219980..c055b8f 100644
--- a/src/app/cohorts/cohorts.module.css
+++ b/src/app/cohorts/cohorts.module.css
@@ -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) {
}
diff --git a/src/app/cohorts/notificationForm.tsx b/src/app/cohorts/notificationForm.tsx
new file mode 100644
index 0000000..24bbe1c
--- /dev/null
+++ b/src/app/cohorts/notificationForm.tsx
@@ -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(null);
+
+ const captchaRef = useRef(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 (
+
+
+
+ {message?.message}
+
+
+ );
+}
diff --git a/src/app/cohorts/page.tsx b/src/app/cohorts/page.tsx
index 50c359e..7ebda66 100644
--- a/src/app/cohorts/page.tsx
+++ b/src/app/cohorts/page.tsx
@@ -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;
@@ -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 = {
@@ -62,9 +75,31 @@ const cohortData: CohortData = {
},
],
};
+
export default function CohortPage() {
const [selectedYear, setSelectedYear] = React.useState(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 Loading...
;
+ }
+
return (
<>
@@ -78,16 +113,28 @@ export default function CohortPage() {
- {/*
- //TODO: Uncomment when we find a way to handle cohort registration and notifications
*/}
+
+ {currentCohortStatusData.message}
+ {currentCohortStatusData.statusType === 'open' && (
+
+ {currentCohortStatusData.statusType === 'closed' && (
+
+ )}
+