Skip to content
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

Add preliminary Apply page and application form #63

Merged
merged 23 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
13 changes: 13 additions & 0 deletions apps/site/src/app/apply/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Form from "./sections/Form/Form";
import Title from "./sections/Title/Title";

export const revalidate = 60;

export default function Apply() {
return (
<div className="flex flex-col items-center gap-10 my-32">
<Title />
<Form />
</div>
);
}
71 changes: 71 additions & 0 deletions apps/site/src/app/apply/sections/Components/DropdownSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"use client";

import { useState } from "react";
import RequiredAsterisk from "./RequiredAsterisk";

interface SelectProps {
labelStyle: string;
inputStyle: string;
name: string;
labelText: string;
values: Array<{ value: string; text: string }>;
containerClass: string;
}

interface OtherProps {
value: string;
name: string;
}

const OtherPopup = ({ value, name }: OtherProps) => {
if (value == "other") {
return (
<div className="mt-2 flex gap-2">
<label htmlFor={`${name}-other-input`} className="text-lg">
Other: <RequiredAsterisk />
</label>
<input
type="text"
name={`${name}-other-input`}
id={`${name}-other-input`}
className="border-b-2 p-1 h-6 border-black w-6/12"
required
/>
</div>
);
}
};

export default function DropdownSelect({
labelStyle,
inputStyle,
name,
labelText,
values,
containerClass,
}: SelectProps) {
const [value, setValue] = useState("");

return (
<div className={containerClass}>
<label className={`${labelStyle}`} htmlFor={name}>
{labelText} <RequiredAsterisk />
</label>
<select
Bl20052005 marked this conversation as resolved.
Show resolved Hide resolved
className={`${inputStyle}`}
Bl20052005 marked this conversation as resolved.
Show resolved Hide resolved
name={name}
id={name}
onChange={(e) => setValue(e.target.value)}
>
{values.map((item, i) => {
return (
<option key={`option-${i}`} value={item.value}>
{item.text}
</option>
);
})}
</select>
<OtherPopup value={value} name={name} />
</div>
);
}
105 changes: 105 additions & 0 deletions apps/site/src/app/apply/sections/Components/RadioSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"use client";

import { useState, useEffect, useRef, forwardRef } from "react";

interface RadioInputs {
name: string;
labelText: string;
IdentifierId: string;
values: Array<{ value: string; text: string }>;
containerClass: string;
}

interface IsChecked {
isChecked: boolean;
id: string;
}

const OtherInput = forwardRef<HTMLInputElement, IsChecked>(
({ isChecked, id }, ref) => (
<input
ref={ref}
type="text"
name={`${id}-other`}
className={
isChecked
? "border-b-2 p-1 h-6 border-black w-6/12"
: "border-b-2 p-1 h-6 border-black w-6/12 bg-transparent"
}
required={isChecked}
disabled={!isChecked}
/>
),
);
OtherInput.displayName = "OtherInput";

export default function RadioSelect({
name,
labelText,
IdentifierId,
values,
containerClass,
}: RadioInputs) {
const [isOtherChecked, setIsOtherChecked] = useState(false);
const otherRef = useRef<HTMLInputElement>(null);

useEffect(() => {
if (isOtherChecked) {
otherRef.current?.focus();
}
}, [isOtherChecked]);

return (
<div className={containerClass}>
<p className="m-0 text-lg mb-4">
{labelText} <span className="text-[#FF2222]">*</span>
</p>
<div className="w-10/12 flex flex-col gap-2">
{values.map((item, i) => {
const keyandId = `${IdentifierId}-${i}`;
if (item.value == "other") {
Bl20052005 marked this conversation as resolved.
Show resolved Hide resolved
return (
<div key={keyandId} className="flex gap-2">
<input
id={keyandId}
type="radio"
key={`option-${i}`}
name={name}
value={item.value}
onChange={(e) =>
setIsOtherChecked(e.target.checked)
}
required
/>
<label className="text-lg" htmlFor={keyandId}>
{item.text}
</label>
<OtherInput
isChecked={isOtherChecked}
Bl20052005 marked this conversation as resolved.
Show resolved Hide resolved
id={IdentifierId}
ref={otherRef}
/>
</div>
);
}
return (
<div key={keyandId} className="flex gap-2">
<input
id={keyandId}
type="radio"
key={`option-${i}`}
name={name}
value={item.value}
onChange={() => setIsOtherChecked(false)}
required
/>
<label className="text-lg" htmlFor={keyandId}>
{item.text}
</label>
</div>
);
})}
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function RequiredAsterisk() {
return <span className="text-[#FF2222]">*</span>;
}
59 changes: 59 additions & 0 deletions apps/site/src/app/apply/sections/Components/SimpleRadio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import RequiredAsterisk from "./RequiredAsterisk";

interface TextfieldProps {
name: string;
values: Array<{
id: string;
labelText: string;
inputValue: string;
}>;
samderanova marked this conversation as resolved.
Show resolved Hide resolved
title: string;
titleClass: string;
containerClassTotal: string;
containerClassInputLabels: string;
containerClassValues: string;
labelClass: string;
isRequired: boolean;
}

export default function SimpleRadio({
name,
values,
title,
titleClass,
containerClassTotal,
containerClassInputLabels,
containerClassValues,
labelClass,
isRequired,
}: TextfieldProps) {
return (
<div className={containerClassTotal}>
<p className={titleClass}>
{`${title} `}
samderanova marked this conversation as resolved.
Show resolved Hide resolved
{isRequired && <RequiredAsterisk />}
</p>
<div className={containerClassValues}>
{values.map((value, i) => {
return (
<div
key={`${name}-${i}`}
Bl20052005 marked this conversation as resolved.
Show resolved Hide resolved
className={containerClassInputLabels}
>
<input
type="radio"
id={value.id}
name={name}
value={value.inputValue}
required={isRequired}
/>
<label htmlFor={value.id} className={labelClass}>
{value.labelText}
</label>
</div>
);
})}
</div>
</div>
);
}
39 changes: 39 additions & 0 deletions apps/site/src/app/apply/sections/Components/TextInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import RequiredAsterisk from "./RequiredAsterisk";

interface TextProps {
name: string;
labelClass: string;
labelText: string;
inputClass: string;
containerClass: string;
type: string;
placeholder: string;
isRequired: boolean;
}

export default function TextInput({
name,
labelClass,
labelText,
inputClass,
containerClass,
placeholder,
type,
isRequired,
}: TextProps) {
return (
<div className={containerClass}>
<label className={labelClass} htmlFor={name}>
{`${labelText} `} {isRequired && <RequiredAsterisk />}
Bl20052005 marked this conversation as resolved.
Show resolved Hide resolved
</label>
<input
className={inputClass}
type={type}
name={name}
id={name}
required={isRequired}
placeholder={placeholder}
/>
</div>
);
}
36 changes: 36 additions & 0 deletions apps/site/src/app/apply/sections/Components/Textfield.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import RequiredAsterisk from "./RequiredAsterisk";

interface TextfieldProps {
name: string;
labelClass: string;
labelText: string;
inputClass: string;
containerClass: string;
isRequired: boolean;
}

export default function Textfield({
name,
labelClass,
labelText,
inputClass,
containerClass,
isRequired,
}: TextfieldProps) {
return (
<div className={containerClass}>
<div className="flex flex-col w-full">
<label className={labelClass} htmlFor={name}>
{`${labelText} `}
{isRequired && <RequiredAsterisk />}
</label>
<textarea
className={inputClass}
id={name}
name={name}
required={isRequired}
/>
</div>
</div>
);
}
46 changes: 46 additions & 0 deletions apps/site/src/app/apply/sections/Form/AgeInformation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import RequiredAsterisk from "../Components/RequiredAsterisk";
import SimpleRadio from "../Components/SimpleRadio";
Bl20052005 marked this conversation as resolved.
Show resolved Hide resolved

const yesNoOptions = [
{
id: "minor-yes",
labelText: "Yes",
inputValue: "Yes",
},
{
id: "minor-no",
labelText: "No",
inputValue: "No",
},
];

export default function AgeInformation() {
return (
<div className="flex flex-col gap-5 w-11/12">
<div className="flex flex-col gap-5">
<p className="m-0 text-lg">
Because of limitations imposed by UCI, we are legally not
allowed to host minors (those under 18) for IrvineHacks
2024. By answering yes, you affirm that you are and will be
18 years or older by January 26, 2024.
</p>
<p className="text-[#FF2222] m-0 text-lg">
We will be checking ID. If you are a minor, you will be
turned away at the door.
</p>
</div>

<SimpleRadio
name="minor-check"
values={yesNoOptions}
title="Will you be 18 years or older by January 26th, 2024?"
titleClass="text-xl font-bold m-0"
containerClassTotal="flex flex-col gap-1 w-full items-center"
isRequired={true}
labelClass="font-bold text-xl"
containerClassInputLabels="flex gap-2 items-center"
containerClassValues="flex gap-5"
/>
</div>
);
}
Loading
Loading