- For use when Operation Code's logo name is between 0-1 inch in height. In most
- cases, use the Original Small Logo. The Stacked Small Logo is to be used where
- graphics needs are larger in vertical height than horizontal width with the Operation
- Code logo name still under 1 inch in height.
+ For use when Operation Code's logo name is between 0-1 inch in height. In most cases,
+ use the Original Small Logo. The Stacked Small Logo is to be used where graphics needs
+ are larger in vertical height than horizontal width with the Operation Code logo name
+ still under 1 inch in height.
diff --git a/components/ErrorDisplay/ErrorDisplay.tsx b/components/ErrorDisplay/ErrorDisplay.tsx
index f08b15978..d95a24fe3 100644
--- a/components/ErrorDisplay/ErrorDisplay.tsx
+++ b/components/ErrorDisplay/ErrorDisplay.tsx
@@ -1,5 +1,3 @@
-import Head from 'components/head';
-
export interface ErrorDisplayPropsType {
/**
* Displasy a status code instead of 'Error'.
@@ -9,20 +7,14 @@ export interface ErrorDisplayPropsType {
function ErrorDisplay({ statusCode }: ErrorDisplayPropsType) {
return (
- <>
-
-
-
-
-
-
-
{statusCode || 'Oh no'}!
-
- We're so ashamed. You definitely weren't supposed to see this...
-
-
+
+
+
{statusCode || 'Oh no'}!
+
+ We're so ashamed. You definitely weren't supposed to see this...
+
- >
+
);
}
diff --git a/components/Form/Input/__stories__/Input.stories.tsx b/components/Form/Input/__stories__/Input.stories.tsx
index 7566a3fc9..5ee1f8a75 100644
--- a/components/Form/Input/__stories__/Input.stories.tsx
+++ b/components/Form/Input/__stories__/Input.stories.tsx
@@ -53,7 +53,7 @@ export default {
(InputStory: () => ReactNode) => (
<>
- NOTE: This component's story has no context outside of Formik and will not function
+ NOTE: This component's story has no context outside of Formik and will not function
properly
diff --git a/components/Form/Select/__stories__/SelectMulti.stories.tsx b/components/Form/Select/__stories__/SelectMulti.stories.tsx
index 77fbcb644..86d465aaa 100644
--- a/components/Form/Select/__stories__/SelectMulti.stories.tsx
+++ b/components/Form/Select/__stories__/SelectMulti.stories.tsx
@@ -68,7 +68,7 @@ export default {
(SelectMultiStory: FC) => (
<>
- NOTE: This component's story has no context outside of Formik and will not function
+ NOTE: This component's story has no context outside of Formik and will not function
properly
diff --git a/components/Form/Select/__stories__/SelectSingle.stories.tsx b/components/Form/Select/__stories__/SelectSingle.stories.tsx
index 8ca8ba4bb..cee1ed015 100644
--- a/components/Form/Select/__stories__/SelectSingle.stories.tsx
+++ b/components/Form/Select/__stories__/SelectSingle.stories.tsx
@@ -82,7 +82,7 @@ export default {
(SelectSingleStory: FC) => (
<>
- NOTE: This component's story has no context outside of Formik and will not function
+ NOTE: This component's story has no context outside of Formik and will not function
properly
diff --git a/components/Forms/RegistrationForm/RegistrationForm.tsx b/components/Forms/RegistrationForm/RegistrationForm.tsx
index 2f419ea09..85bbada82 100644
--- a/components/Forms/RegistrationForm/RegistrationForm.tsx
+++ b/components/Forms/RegistrationForm/RegistrationForm.tsx
@@ -174,7 +174,7 @@ export function RegistrationForm({
href={codeOfConduct}
analyticsEventLabel="Registration CoC Checkbox Link"
>
- Operation Code's Code of Conduct.
+ Operation Code's Code of Conduct.
{' '}
*
>
@@ -194,7 +194,7 @@ export function RegistrationForm({
href={slackGuidelines}
analyticsEventLabel="Registration Slack Guidelines Checkbox Link"
>
- Operation Code's Slack Community Guidelines.
+ Operation Code's Slack Community Guidelines.
{' '}
*
>
diff --git a/components/ProgressIndicator/__stories__/ProgressIndicator.stories.tsx b/components/ProgressIndicator/__stories__/ProgressIndicator.stories.tsx
index 0937d32eb..1c213f7a1 100644
--- a/components/ProgressIndicator/__stories__/ProgressIndicator.stories.tsx
+++ b/components/ProgressIndicator/__stories__/ProgressIndicator.stories.tsx
@@ -51,15 +51,15 @@ const meta: Meta = {
/>
totalSteps
- Sets the number of "steps" are needed to fill the indicator bar. The
- totalSteps value needs to be more than, or equal to the stepNumber value.
+ Sets the number of “steps” are needed to fill the indicator bar. The totalSteps value
+ needs to be more than, or equal to the stepNumber value.
stepNumber
- Sets the number of "completed" steps and fills the indicator bar relative to
- the totalSteps value. The stepNumber value needs to be less than, or equal to the
- totalSteps value.
+ Sets the number of “completed” steps and fills the indicator bar relative to the
+ totalSteps value. The stepNumber value needs to be less than, or equal to the totalSteps
+ value.
diff --git a/components/Timeline/__tests__/__snapshots__/Timeline.test.tsx.snap b/components/Timeline/__tests__/__snapshots__/Timeline.test.tsx.snap
index b68e6d8df..4d807b946 100644
--- a/components/Timeline/__tests__/__snapshots__/Timeline.test.tsx.snap
+++ b/components/Timeline/__tests__/__snapshots__/Timeline.test.tsx.snap
@@ -78,7 +78,7 @@ exports[`Timeline > should render with no props passed passed 1`] = `
- he was inspired to pursue software engineering as a post-military occupation. He submitted an application to The Flatiron School while on active-duty, only to discover that the program did not accept the "Post-9/11 GI Bill" as payment.
+ he was inspired to pursue software engineering as a post-military occupation. He submitted an application to The Flatiron School while on active-duty, only to discover that the program did not accept the “Post-9/11 GI Bill” as payment.
- If you've already completed this step and were unexpectedly redirected here,
- something may be wrong on our end. Please email us at{' '}
+ If you've already completed this step and were unexpectedly redirected here, something
+ may be wrong on our end. Please email us at{' '}
staff@operationcode.org
{' '}
diff --git a/app/join/form/page.tsx b/app/join/form/page.tsx
new file mode 100644
index 000000000..30fa27abd
--- /dev/null
+++ b/app/join/form/page.tsx
@@ -0,0 +1,27 @@
+import { cookies } from 'next/headers';
+import { redirect } from 'next/navigation';
+import { generatePageMetadata } from 'common/utils/metadata';
+import HeroBanner from 'components/HeroBanner/HeroBanner';
+import Content from 'components/Content/Content';
+import UpdateProfileForm from 'components/Forms/UpdateProfileForm/UpdateProfileForm';
+
+export const metadata = generatePageMetadata({ title: 'Update Profile' });
+
+const pageTitle = 'Update Profile';
+
+export default async function UpdateProfile() {
+ const cookieStore = await cookies();
+ const opCodeApplicantEmail = cookieStore.get('opCodeApplicantEmail');
+
+ if (!opCodeApplicantEmail) {
+ redirect('/');
+ }
+
+ return (
+ <>
+
+
+ ]} />
+ >
+ );
+}
diff --git a/app/join/page.tsx b/app/join/page.tsx
new file mode 100644
index 000000000..16bf38546
--- /dev/null
+++ b/app/join/page.tsx
@@ -0,0 +1,14 @@
+import { generatePageMetadata } from 'common/utils/metadata';
+import JoinContent from './JoinContent';
+
+export const metadata = generatePageMetadata({ title: 'Join' });
+
+export default async function JoinPage({
+ searchParams,
+}: {
+ searchParams: Promise<{ registrationError?: string }>;
+}) {
+ const { registrationError } = await searchParams;
+
+ return ;
+}
diff --git a/app/join/success/page.tsx b/app/join/success/page.tsx
new file mode 100644
index 000000000..6f05a4b5e
--- /dev/null
+++ b/app/join/success/page.tsx
@@ -0,0 +1,32 @@
+import { SUCCESS_PAGE_MESSAGE } from 'common/constants/testIDs';
+import { generatePageMetadata } from 'common/utils/metadata';
+import LinkButton from 'components/Buttons/LinkButton/LinkButton';
+import HeroBanner from 'components/HeroBanner/HeroBanner';
+import OutboundLink from 'components/OutboundLink/OutboundLink';
+
+export const metadata = generatePageMetadata({ title: 'Successful Registration!' });
+
+const pageTitle = `Successful Registration!`;
+
+export default function JoinSuccess() {
+ return (
+
+
+ We will review your application and send an invite to our Slack team as soon as possible. If
+ you do not receive an invite within a week, please email us at{' '}
+
+ staff@operationcode.org
+
+ .
+
+
+
+ Go Home
+
+
+ );
+}
diff --git a/pages/404.tsx b/app/not-found.tsx
similarity index 74%
rename from pages/404.tsx
rename to app/not-found.tsx
index 858c68640..58ed17079 100644
--- a/pages/404.tsx
+++ b/app/not-found.tsx
@@ -1,5 +1,5 @@
import ErrorDisplay from 'components/ErrorDisplay/ErrorDisplay';
-export default function Custom404() {
+export default function NotFound() {
return ;
}
diff --git a/pages/index.tsx b/app/page.tsx
similarity index 82%
rename from pages/index.tsx
rename to app/page.tsx
index 571adbf34..4a55e1061 100644
--- a/pages/index.tsx
+++ b/app/page.tsx
@@ -1,4 +1,4 @@
-import Head from 'components/head';
+import { generatePageMetadata } from 'common/utils/metadata';
import HeroBanner from 'components/HeroBanner/HeroBanner';
import Content from 'components/Content/Content';
import JoinSection from 'components/ReusableSections/JoinSection/JoinSection';
@@ -9,11 +9,13 @@ import LinkButton from 'components/Buttons/LinkButton/LinkButton';
import { s3 } from 'common/constants/urls';
import { cx } from 'common/utils/cva';
+export const metadata = generatePageMetadata({ title: 'Home' });
+
const successStories = [
{
title: 'Ali Cipolla-Taylor, Talent Acquisition at Microsoft',
quote:
- 'I finished MSTA the last week of February, and then COVID hit. Employment was not going to happen…to anyone. I kept making calls, working on my skills, and throwing myself out there, and I got a role as a vendor at Microsoft. I’m half of the Data Privacy, Compliance, and Controls team for Talent Acquisition now. I had a lot of hard conversations with myself. I learned to lean into a support network, locally and online, through OpCode. I’m notoriously shy on the internet, but I knew that I couldn’t do this alone. Change happens when the discomfort of making the change is less than the life you’re living.',
+ "I finished MSTA the last week of February, and then COVID hit. Employment was not going to happen…to anyone. I kept making calls, working on my skills, and throwing myself out there, and I got a role as a vendor at Microsoft. I'm half of the Data Privacy, Compliance, and Controls team for Talent Acquisition now. I had a lot of hard conversations with myself. I learned to lean into a support network, locally and online, through OpCode. I'm notoriously shy on the internet, but I knew that I couldn't do this alone. Change happens when the discomfort of making the change is less than the life you're living.",
imageSource: `${s3}headshots/ali.jpg`,
},
{
@@ -33,8 +35,6 @@ const successStories = [
function Home() {
return (
-
-
- We're the largest community of military veterans, service members, and spouses
- committed to becoming software developers with the help of mentors, scholarships, and
- our tech partners.
+ We're the largest community of military veterans, service members, and spouses committed
+ to becoming software developers with the help of mentors, scholarships, and our tech
+ partners.
diff --git a/app/podcast/PodcastPlayer.tsx b/app/podcast/PodcastPlayer.tsx
new file mode 100644
index 000000000..3e594c2f6
--- /dev/null
+++ b/app/podcast/PodcastPlayer.tsx
@@ -0,0 +1,27 @@
+'use client';
+
+import dynamic from 'next/dynamic';
+
+const ReactPlayer = dynamic(() => import('react-player/lazy'), { ssr: false });
+
+interface PodcastPlayerProps {
+ url: string;
+}
+
+export default function PodcastPlayer({ url }: PodcastPlayerProps) {
+ return (
+
+ );
+}
diff --git a/pages/podcast.tsx b/app/podcast/page.tsx
similarity index 61%
rename from pages/podcast.tsx
rename to app/podcast/page.tsx
index 2030c1df7..166e2be86 100644
--- a/pages/podcast.tsx
+++ b/app/podcast/page.tsx
@@ -1,14 +1,17 @@
import axios from 'axios';
import get from 'lodash/get';
-import dynamic from 'next/dynamic';
import { parse as parseXml } from 'fast-xml-parser';
-import { ONE_DAY } from 'common/constants/unitsOfTime';
-import Head from 'components/head';
+import { generatePageMetadata } from 'common/utils/metadata';
import HeroBanner from 'components/HeroBanner/HeroBanner';
import Card from 'components/Cards/Card/Card';
import Content from 'components/Content/Content';
import Heading from 'components/Heading/Heading';
import Image from 'next/image';
+import PodcastPlayer from './PodcastPlayer';
+
+export const metadata = generatePageMetadata({ title: 'Podcast' });
+
+export const revalidate = 86400;
interface RSS {
channel: {
@@ -23,12 +26,7 @@ interface Episode {
story: string;
}
-const pageTitle = 'Podcast';
-
-const ReactPlayer = dynamic(() => import('react-player/lazy'), { ssr: false });
-
-// We have atypical error handling because there exist errors thrown on nearly every request.
-export async function getStaticProps() {
+async function getEpisodes(): Promise {
const { data } = await axios.get('https://operationcode.libsyn.com/rss');
const {
@@ -44,25 +42,24 @@ export async function getStaticProps() {
const numberOfEpisodes = get(rss, 'channel.item.length', 0);
if (numberOfEpisodes > 0) {
- const episodes = rss.channel.item.map(({ image: { href }, link, title, description }) => ({
+ return rss.channel.item.map(({ image: { href }, link, title, description }) => ({
image: href,
name: title[0],
source: link,
story: description.replace(/(
|<\/p>)/g, ''),
}));
-
- return { props: { episodes }, revalidate: ONE_DAY };
}
- // Request failed or RSS Feed is broken... Break the build!
- throw new Error('getStaticProps in /podcast failed.');
+ throw new Error('Failed to fetch podcast episodes.');
}
-function Podcast({ episodes }: { episodes: Episode[] }) {
+const pageTitle = 'Podcast';
+
+export default async function Podcast() {
+ const episodes = await getEpisodes();
+
return (
-
-
Come listen to some inspiring stories of our vets transitioning into tech!
{episodes.map(({ name, image, source, story }, index) => {
- /*
- * Some episodes have multiple parts and are named like "${Name}, part 1".
- * Some episodes are named "${Name} Interview"
- *
- * Parsing them in this manner ensures that the name of the interviewee is
- * available and used for the image alt tag.
- */
const interviewee = name.replace(/ interview/gi, '').split(',')[0];
return (
@@ -97,19 +87,7 @@ function Podcast({ episodes }: { episodes: Episode[] }) {
height={200}
/>
-
+
);
}
-
-export default Podcast;
diff --git a/pages/policy.tsx b/app/policy/page.tsx
similarity index 92%
rename from pages/policy.tsx
rename to app/policy/page.tsx
index fc06b3a57..0d6afca0a 100644
--- a/pages/policy.tsx
+++ b/app/policy/page.tsx
@@ -1,12 +1,12 @@
-import Head from 'components/head';
+import { generatePageMetadata } from 'common/utils/metadata';
import HeroBanner from 'components/HeroBanner/HeroBanner';
import { s3 } from 'common/constants/urls';
+export const metadata = generatePageMetadata({ title: 'Policy' });
+
function Policy() {
return (
-
-
-
-
- This page is designed to make a journalist's job easy in writing, blogging, or
- documenting Operation Code. Below you will find targeted information corresponding to
- common representative visitors, videos, photos, press releases, and branding details.
+ This page is designed to make a journalist's job easy in writing, blogging, or documenting
+ Operation Code. Below you will find targeted information corresponding to common
+ representative visitors, videos, photos, press releases, and branding details.
@@ -56,11 +56,11 @@ function Press() {
We have long-standing, productive partnerships with some amazing companies, and
yours could be one of them! Organizations that put our members and our open source
work on a pedastal, can look forward to receive social media blasts and the
- appreciation of America's military veterans. If you are thinking about a
+ appreciation of America's military veterans. If you are thinking about a
partnership with Operation Code, but are unsure of what to offer our members,{' '}
- let's talk.
- If you're seeking information to display in announcing the partnership,
- please see below!
+ let's talk. If
+ you're seeking information to display in announcing the partnership, please see
+ below!
@@ -70,10 +70,10 @@ function Press() {
Media Outlets
The staff at Operation Code thank you for taking your time to represent us in your
- work. If your piece has a specific theme or target, and you'd like some
- custom contributions, please join our organization to receive a Slack team invite.
- There you'll likely find many Operation Code members willing and able to
- offer personal anecdotes and first-hand interviews!
+ work. If your piece has a specific theme or target, and you'd like some custom
+ contributions, please join our organization to receive a Slack team invite. There
+ you'll likely find many Operation Code members willing and able to offer personal
+ anecdotes and first-hand interviews!
diff --git a/pages/project_rebuild.tsx b/app/project_rebuild/page.tsx
similarity index 91%
rename from pages/project_rebuild.tsx
rename to app/project_rebuild/page.tsx
index 96008cde1..b0e23e154 100644
--- a/pages/project_rebuild.tsx
+++ b/app/project_rebuild/page.tsx
@@ -1,5 +1,5 @@
import Image from 'next/image';
-import Head from 'components/head';
+import { generatePageMetadata } from 'common/utils/metadata';
import HeroBanner from 'components/HeroBanner/HeroBanner';
import Content from 'components/Content/Content';
import OutboundLink from 'components/OutboundLink/OutboundLink';
@@ -8,18 +8,11 @@ import { s3 } from 'common/constants/urls';
const pageTitle = 'Project Rebuild';
+export const metadata = generatePageMetadata({ title: pageTitle });
+
function ProjectRebuild() {
return (
-
-
In conjunction with Fresh Start Refugee Assistance Center, an Afghan-American led
- non-profit, and Globally.org’s ReUp Refugee Tech Re-Skilling Program, Operation Code
+ non-profit, and Globally.org's ReUp Refugee Tech Re-Skilling Program, Operation Code
is pleased to announce that we are expanding our Project Rebuild Refugee Tech Training
Program. Since March 2022, Operation Code launched the initial pilot cohort, with 8
Afghan refugee participants in attendance. We have expanded the cohorts to include
@@ -76,7 +69,7 @@ function ProjectRebuild() {
Fresh Start provides wraparound services such as:
- initial refugee resettlement efforts, ESL classes, driver’s education and licensing,
+ initial refugee resettlement efforts, ESL classes, driver's education and licensing,
affordable housing, mental health and cultural transition support as well as job
search assistance.
@@ -88,7 +81,7 @@ function ProjectRebuild() {
{' '}
by providing our refugee participants a scholarship to complete one certification
during the six-month cohort. Pairing a refugee with a Veteran or military spouse
- mentor to meet on a regular cadence, our two communities can continue to “rebuild” our
+ mentor to meet on a regular cadence, our two communities can continue to "rebuild" our
parallel experiences, provide a tech-focused workforce development program and help
refugees obtain high paid and meaningful work.
diff --git a/pages/scholarship/code_platoon.tsx b/app/scholarship/code_platoon/CodePlatoonContent.tsx
similarity index 90%
rename from pages/scholarship/code_platoon.tsx
rename to app/scholarship/code_platoon/CodePlatoonContent.tsx
index fab141e65..65d93a4e7 100644
--- a/pages/scholarship/code_platoon.tsx
+++ b/app/scholarship/code_platoon/CodePlatoonContent.tsx
@@ -1,11 +1,12 @@
-import Head from 'components/head';
+'use client';
+
+import { useEffect } from 'react';
import Container from 'components/Container/Container';
import HeroBanner from 'components/HeroBanner/HeroBanner';
-import { useEffect } from 'react';
const pageTitle = 'Code Platoon X Operation Code Bootcamp Scholarship';
-export default function CodePlatoonScholarshipPage() {
+export default function CodePlatoonContent() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://js.hsforms.net/forms/embed/v2.js';
@@ -33,7 +34,6 @@ export default function CodePlatoonScholarshipPage() {
return (
<>
-