10 | );
11 | };
12 |
13 | ModalBackground.propTypes = {
14 | onClick : PropTypes.func.isRequired,
15 | };
16 |
17 | export default ModalBackground;
--------------------------------------------------------------------------------
/src/components/Landing/Sections/Sponsors/Partners.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import LogoWrapper from "./LogoWrapper";
3 | import { defaults } from "../../../../Defaults.js";
4 | import PropTypes from "prop-types";
5 |
6 | const Partners = ({ isMobile }) => (
7 |
11 | );
12 | Partners.propTypes = {
13 | isMobile: PropTypes.bool,
14 | };
15 |
16 |
17 | export default Partners;
--------------------------------------------------------------------------------
/src/components/Landing/Sections/Sponsors/Sponsors.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import LogoWrapper from "./LogoWrapper";
3 | import { defaults } from "../../../../Defaults.js";
4 | import PropTypes from "prop-types";
5 | const Sponsors = ({ isMobile }) => (
6 |
10 | );
11 |
12 | Sponsors.propTypes = {
13 | isMobile: PropTypes.bool,
14 | };
15 |
16 | export default Sponsors;
--------------------------------------------------------------------------------
/src/components/_Landing/global_components/SectionTitle.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function SectionTitle(props: { title: string }) {
4 | const { title } = props;
5 | return (
6 |
11 | );
12 | }
13 |
14 | export default SectionTitle;
--------------------------------------------------------------------------------
/src/components/Live/Map.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { defaults } from "../../Defaults";
3 | class Map extends Component {
4 | render() {
5 | return (
6 |
7 |
8 |
Map
9 |
12 |
13 |
14 | );
15 | }
16 | }
17 | export default Map;
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/UserItem.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ListItem, ListItemText, } from "@material-ui/core";
3 | import PropTypes from "prop-types";
4 |
5 | function UserItem(props) {
6 | const { member } = props;
7 | console.log(member);
8 | return (
9 |
10 |
11 |
13 |
14 | );
15 | }
16 | UserItem.propTypes = {
17 | member: PropTypes.object,
18 | skills: PropTypes.array,
19 | };
20 |
21 | export default UserItem;
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "react"
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/src/NavBar.css:
--------------------------------------------------------------------------------
1 | .customButton {
2 | color: white !important;
3 | border: 1px solid white !important;
4 | border-color: white !important;
5 | text-decoration: none !important;
6 | transition: 1s ease !important;
7 | }
8 |
9 | .customButton:hover {
10 | background-color: #f1ba43 !important;
11 | color: black !important;
12 | border-color: black !important;
13 | transition: 1s ease;
14 | -o-transition: 1s ease;
15 | -ms-transition: 1s ease;
16 | -moz-transition: 1s ease;
17 | -webkit-transition: 1s ease;
18 | }
19 |
20 | button:focus {
21 | outline: none !important;
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/Team/TeamNames.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {Col } from "reactstrap";
3 | import Person from "./Person.jsx";
4 | import PropTypes from "prop-types";
5 |
6 | const TeamNames = ({ people, teamName }) => (
7 |
8 |
{teamName}
9 | {people.map((person) =>
10 |
13 | )}
14 |
15 | );
16 |
17 | TeamNames.propTypes = {
18 | people: PropTypes.string,
19 | teamName: PropTypes.string,
20 | };
21 |
22 | export default TeamNames;
23 |
--------------------------------------------------------------------------------
/public/assets/icons/hackru-slogan.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 | hack all knight
11 |
12 |
--------------------------------------------------------------------------------
/src/components/Dashboard/ProfileMessage.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { UncontrolledAlert } from "reactstrap";
3 | import PropTypes from "prop-types";
4 | /**
5 | * Renders an alert based on the message
6 | * @param {String} message The displayed message
7 | */
8 | const ProfileMessage = ({ message }) => (
9 | message &&
10 |
12 | {message.value}
13 |
14 | );
15 | ProfileMessage.propTypes = {
16 | message: PropTypes.object,
17 | };
18 | export default ProfileMessage;
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/tests/ModalBackground.test.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable no-unused-vars */
3 |
4 | import React from "react";
5 | import { render } from "@testing-library/react";
6 | import ModalBackground from "../pure_component/ModalBackground";
7 |
8 | describe("ModalBackground", () => {
9 | test("background runs the onClick function on click", () => {
10 | const fun = jest.fn();
11 | const {container} = render(
fun()}/>);
12 | container.querySelector("div").click();
13 | expect(fun).toHaveBeenCalledTimes(1);
14 | });
15 | });
--------------------------------------------------------------------------------
/src/components/_Landing/global_components/CardLogReg.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./CardLogReg.css";
3 |
4 | function CardLogReg(props: any) {
5 | return (
6 |
12 | {props.children}
13 |
14 | );
15 | }
16 |
17 | export default CardLogReg;
--------------------------------------------------------------------------------
/scripts/prod-deploy.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | # Mostly intended to be run from travis CI
3 | # It is expected that KEY and SECRET will be set in the environment
4 | set -e
5 | cd ../
6 | npm run-script build-prod
7 | #empty bucket, then upload
8 | aws s3 rm s3://hackru-frontend-prod --recursive
9 | aws s3 cp --recursive build s3://hackru-frontend-prod --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
10 | aws s3 cp --recursive --exclude '*' --include '*.svg' --content-type 'image/svg+xml' build s3://hackru-frontend-prod --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
11 | aws cloudfront create-invalidation --distribution-id "E1YIAV5VULIMY7" --paths "/*"
12 |
--------------------------------------------------------------------------------
/scripts/dev-deploy.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | # Mostly intended to be run from travis CI
3 | # It is expected that KEY and SECRET will be set in the environment
4 | set -e
5 | cd ../
6 | NODE_ENV=development npm run-script build-dev
7 | #empty bucket, then upload
8 | aws s3 rm s3://hackru-frontend-dev --recursive
9 | aws s3 cp --recursive build s3://hackru-frontend-dev --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
10 | aws s3 cp --recursive --exclude '*' --include '*.svg' --content-type 'image/svg+xml' build s3://hackru-frontend-dev --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
11 | aws cloudfront create-invalidation --distribution-id "E1G9Y2VX0F41B6" --paths "/*"
12 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/pure_component/GenericList.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 |
4 | import modalstyles from "../styles/ModalStyle.module.css";
5 |
6 | const GenericList = (props) => {
7 | const {entries} = props;
8 | return(
9 |
10 | {
11 | entries && entries.map((entry) =>
12 | {entry}
13 | )
14 | }
15 |
16 | );
17 | };
18 |
19 | GenericList.propTypes = {
20 | entries : PropTypes.arrayOf(PropTypes.string),
21 | };
22 |
23 | export default GenericList;
--------------------------------------------------------------------------------
/src/components/_Landing/assets/sun/sun.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./sun.css";
3 |
4 | function Sun() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
26 | export default Sun;
--------------------------------------------------------------------------------
/src/components/Team/Person.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { theme } from "../../Defaults";
3 | import PropTypes from "prop-types";
4 |
5 | const Person = ({ image, name, title }) => (
6 |
7 | {
8 | image &&
11 | }
12 |
{name}
13 | {title &&
{title} }
14 |
15 | );
16 |
17 | Person.propTypes = {
18 | image: PropTypes.string,
19 | name: PropTypes.string,
20 | title: PropTypes.string,
21 | };
22 |
23 | export default Person;
24 |
--------------------------------------------------------------------------------
/src/components/GlowButton.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Button } from "reactstrap";
3 | import { Icon } from "react-fa";
4 | import PropTypes from "prop-types";
5 |
6 | const GlowButton = ({ href, icon, text }) => (
7 | { window.location = href; }}
9 | className="live-links"
10 | style={{ color: "white" }}
11 | size="lg"
12 | outline>
13 |
15 |
16 | { text }
17 |
18 | );
19 |
20 | GlowButton.propTypes = {
21 | href: PropTypes.string,
22 | icon: PropTypes.string,
23 | text: PropTypes.string,
24 | };
25 |
26 | export default GlowButton;
27 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/tests/TeamMemberCard.test.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable no-unused-vars */
3 |
4 | import React from "react";
5 | import { render } from "@testing-library/react";
6 | import TeamMemberCard from "../pure_component/TeamMemberCard";
7 |
8 | describe("TeamMemberCard", () => {
9 |
10 | test("renders bio and user_id", () => {
11 | const user = {
12 | user_id : "John Doe",
13 | bio : "example biography",
14 | };
15 | const {queryByText} = render();
16 | expect(queryByText(/John Doe/)).toBeTruthy();
17 | expect(queryByText(/example biography/)).toBeTruthy();
18 | });
19 | });
--------------------------------------------------------------------------------
/src/components/Card.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 |
4 | // import { theme } from "../../../Defaults";
5 |
6 | function Card(props){
7 |
8 | return (
9 |
10 |
11 | {props.sideBar ?
: ""}
12 | {props.children}
13 |
14 | );
15 | }
16 | Card.propTypes = {
17 | backgroundColor: PropTypes.any,
18 | sideBar: PropTypes.any,
19 | children: PropTypes.element
20 | };
21 | export default Card;
--------------------------------------------------------------------------------
/src/components/_Landing/sections/error.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | /**
4 | * Error Section page with custom error title and message.
5 | * @param props
6 | * @returns
7 | */
8 | function Error(props: { title: string, message: string }) {
9 | const { title, message } = props;
10 | return (
11 |
12 |
13 |
14 | {title}
15 |
16 |
17 | {message}
18 |
19 |
20 |
21 | );
22 | }
23 |
24 | export default Error;
--------------------------------------------------------------------------------
/src/components/_Landing/sections/hero/hero.css:
--------------------------------------------------------------------------------
1 |
2 | .glowing-moon-container {
3 | position: absolute;
4 | top: 55%;
5 | left: 65%;
6 | transform: translate(-50%, -50%);
7 | width: 0.2rem;
8 | height: 0.2rem;
9 | border-radius: 50%;
10 | background-color: #d1e9ef;
11 | /* box-shadow: 0 0 30px 10px #d1e9ef; */
12 | }
13 |
14 | .navbar-button:hover {
15 | text-shadow:1px 1px 10px #4bbede;
16 | }
17 |
18 | /* KEYFRAMES */
19 |
20 | @keyframes animateCloud {
21 | 0% {
22 | transform: translateX(-34rem);
23 | }
24 | 100% {
25 | transform: translateX(100vw);
26 | }
27 | }
28 |
29 | /* ANIMATIONS */
30 |
31 | .cloud {
32 | will-change: transform;
33 | animation: animateCloud 400s linear infinite;
34 | }
--------------------------------------------------------------------------------
/.github/workflows/code-quality-assurance.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean node installation of the project, and test the code
2 |
3 | name: Code Quality Assurance
4 |
5 | on:
6 | push:
7 | branches: ["*", "*/*", "**", "!env/dev"]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | fail-fast: true
15 | matrix:
16 | node-version: [12.x, 14.x]
17 |
18 | steps:
19 | - uses: actions/checkout@v2
20 | - name: Test using Node ${{ matrix.node-version }}
21 | uses: actions/setup-node@v1
22 | with:
23 | node-version: ${{ matrix.node-version }}
24 | - run: npm install
25 | - run: npm run lint
26 |
--------------------------------------------------------------------------------
/src/library/WhiteTextField.jsx:
--------------------------------------------------------------------------------
1 | import { TextField, withStyles } from "@material-ui/core";
2 |
3 | const WhiteTextField = withStyles({
4 | root: {
5 | "--input-color": "white",
6 | "& labl.Mui-focused": {
7 | color: "white",
8 | },
9 | "& .MuiInput-underline:after": {
10 | borderBottomColor: "white",
11 | },
12 | "& .MuiOutlinedInput-root": {
13 | "& fieldset": {
14 | borderColor: "white",
15 | color: "white",
16 | },
17 | "&:hover fieldset": {
18 | borderColor: "white",
19 | },
20 | "&.Mui-focused fieldset": {
21 | borderColor: "white",
22 | },
23 | },
24 |
25 | },
26 |
27 | })(TextField);
28 |
29 | export default WhiteTextField;
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/pure_component/TeamMemberList.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import TeamMemberCard from "./TeamMemberCard";
4 |
5 | import modalstyles from "../styles/ModalStyle.module.css";
6 |
7 | const TeamMemberList = (props) => {
8 | const {members} = props;
9 | return(
10 |
11 | {
12 | members.map((member) => )
14 | }
15 |
16 | );
17 | };
18 |
19 | TeamMemberList.propTypes = {
20 | members : PropTypes.arrayOf(PropTypes.shape({
21 | user_id : PropTypes.string,
22 | seriousness : PropTypes.number,
23 | bio : PropTypes.string,
24 | }))
25 | };
26 |
27 | export default TeamMemberList;
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/pure_component/PureSection.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import { Typography } from "@material-ui/core";
4 | import modalstyles from "../styles/ModalStyle.module.css";
5 |
6 | const PureSection = (props) => {
7 | const {sectionHeader, children} = props;
8 | return (
9 | <>
10 |
11 |
12 |
13 | {sectionHeader}
14 |
15 |
16 | {children}
17 |
18 | >
19 | );
20 | };
21 |
22 | PureSection.propTypes = {
23 | sectionHeader : PropTypes.string.isRequired,
24 | children : PropTypes.node.isRequired,
25 | };
26 |
27 | export default PureSection;
--------------------------------------------------------------------------------
/src/components/_Landing/sections/hero/utilities.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 |
3 | export function scrollToSectionName(sectionName: string) {
4 | document.getElementById(sectionName)?.scrollIntoView({ behavior: "smooth" });
5 | }
6 |
7 | export function useUserScrolled(scroll_y_threshold: number = 0) {
8 | const [userScrolled, setUserScrolled] = useState(false);
9 |
10 | useEffect(() => {
11 | const handleScroll = () => {
12 | if (window.scrollY > scroll_y_threshold) {
13 | setUserScrolled(true);
14 | } else {
15 | setUserScrolled(false);
16 | }
17 | };
18 |
19 | window.addEventListener("scroll", handleScroll);
20 |
21 | return () => window.removeEventListener("scroll", handleScroll);
22 | }, []);
23 |
24 | return userScrolled;
25 | }
26 |
27 | export default { useUserScrolled };
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/pure_component/TeamMemberCard.jsx:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types";
2 | import React from "react";
3 |
4 | import modalstyles from "../styles/ModalStyle.module.css";
5 |
6 | const TeamMemberCard = (props) => {
7 | const {user_id, bio} = props.member;
8 | return (
9 |
10 |
11 |
12 | {user_id}
13 | {bio}
14 |
15 |
16 |
17 | );
18 | };
19 |
20 | TeamMemberCard.propTypes = {
21 | member : PropTypes.shape({
22 | user_id : PropTypes.string.isRequired,
23 | seriousness: PropTypes.number,
24 | bio: PropTypes.string.isRequired,
25 | }).isRequired,
26 | };
27 |
28 | export default TeamMemberCard;
--------------------------------------------------------------------------------
/src/components/Landing/Sections/Sponsors/SponsorItem.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import PropTypes from "prop-types";
3 |
4 | class SponsorItem extends Component {
5 | render() {
6 | return (
7 |
9 |
12 |
13 | );
14 | }
15 | }
16 |
17 | SponsorItem.propTypes = {
18 | size: PropTypes.object,
19 | href: PropTypes.string,
20 | name: PropTypes.string,
21 | baseURL: PropTypes.string,
22 | image: PropTypes.string
23 | };
24 |
25 | export default SponsorItem;
--------------------------------------------------------------------------------
/src/components/_Landing/sections/schedule/Schedule.css:
--------------------------------------------------------------------------------
1 |
2 | /* Table Header */
3 | .MainLayout-stickyElement.MainLayout-header.MainLayout-flexRow {
4 | background-color: transparent;
5 | }
6 |
7 | .MainLayout-background.MainLayout-inlineFlex.MainLayout-ordinaryHeaderBorder {
8 | background-color: transparent;
9 | }
10 |
11 | .MainLayout-stickyElement.MainLayout-leftPanel.MainLayout-dayScaleEmptyCell.MainLayout-ordinaryLeftPanelBorder {
12 | background-color: transparent;
13 | }
14 |
15 | /* Table Side Bar */
16 | .MainLayout-flexRow.MainLayout-stickyElement.MainLayout-leftPanel.MainLayout-ordinaryLeftPanelBorder {
17 | background-color: transparent;
18 | }
19 |
20 | /* Day of Week */
21 | .Cell-dayOfWeek {
22 | color: #d1e9ef !important;
23 | }
24 |
25 | /* Day of Month */
26 | .Cell-dayOfMonth {
27 | color: #d1e9ef !important;
28 |
29 | }
30 |
31 | /* Time Labels */
32 | .css-1fbp63r .Label-text {
33 | color: #d1e9ef !important;
34 | }
--------------------------------------------------------------------------------
/public/assets/background/target-thick_red.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/library/WhiteTextField.jsx:
--------------------------------------------------------------------------------
1 | // import { TextField, withStyles } from "@material-ui/core";
2 |
3 | // const WhiteTextField = withStyles({
4 | // root: {
5 | // "--input-color": "white",
6 | // "& labl.Mui-focused": {
7 | // color: "white",
8 | // },
9 | // "& .MuiInput-underline:after": {
10 | // borderBottomColor: "white",
11 | // },
12 | // "& .MuiOutlinedInput-root": {
13 | // "& fieldset": {
14 | // borderColor: "white",
15 | // color: "white",
16 | // },
17 | // "&:hover fieldset": {
18 | // borderColor: "white",
19 | // },
20 | // "&.Mui-focused fieldset": {
21 | // borderColor: "white",
22 | // },
23 | // },
24 |
25 | // },
26 |
27 | // })(TextField);
28 |
29 | // export default WhiteTextField;
--------------------------------------------------------------------------------
/public/assets/background/target-thick_green.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/public/assets/background/target-thick_yellow.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/components/Pages.jsx:
--------------------------------------------------------------------------------
1 | import LandingPage from "./Landing/Landing";
2 | import DashboardPage from "./Dashboard/Dashboard";
3 | import ProfilePage from "./Dashboard/Profile";
4 | import LoginPage from "./Login";
5 | import SignUpPage from "./Signup";
6 | import ForgotPage from "./Forgot";
7 | import ContactPage from "./Contact";
8 | import MagicPage from "./Magic";
9 | import LivePage from "./Live/Live";
10 | import SponsorshipPage from "./Sponsorship/Sponsorship";
11 | import ProjectorPage from "./Projector/Projector";
12 | import E404 from "./Errors/E404";
13 | import TeamPage from "./Team/Team";
14 | import TeamViewerPage from "./Dashboard/TeamViewer/TeamViewer";
15 | export {
16 | LandingPage,
17 | DashboardPage,
18 | ProfilePage,
19 | LoginPage,
20 | SignUpPage,
21 | MagicPage,
22 | ForgotPage,
23 | ContactPage,
24 | LivePage,
25 | TeamPage,
26 | SponsorshipPage,
27 | E404,
28 | ProjectorPage,
29 | TeamViewerPage
30 | };
31 |
--------------------------------------------------------------------------------
/.github/workflows/code-build-assurance.yml:
--------------------------------------------------------------------------------
1 | # You might ask why this workflow exists? Well apparently, the linter can pass but the build can still fail. So at some point during the review process we need to run the build. Hence, this file
2 |
3 | name: Code Build Assurance
4 |
5 | on:
6 | pull_request:
7 | branches: [env/dev, env/prod]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | fail-fast: true
15 | matrix:
16 | node-version: [12.x, 14.x]
17 |
18 | steps:
19 | - uses: actions/checkout@v2
20 | - name: Test using Node ${{ matrix.node-version }}
21 | env:
22 | NODE_OPTIONS: "--max_old_space_size=8192"
23 | uses: actions/setup-node@v1
24 | with:
25 | node-version: ${{ matrix.node-version }}
26 | - run: npm install
27 | - run: NODE_ENV=development CI=false npm run build-dev
28 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/tests/PureSection.test.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable no-unused-vars */
3 |
4 | import React from "react";
5 | import { render } from "@testing-library/react";
6 | import PureSection from "../pure_component/PureSection";
7 |
8 | describe("PureSection", () => {
9 |
10 | test("renders section header", () => {
11 | const {queryByText} = render(Child );
12 | const sectionHeader = queryByText(/Section Header/i);
13 | expect(sectionHeader.innerHTML).toBe("Section Header");
14 | });
15 |
16 | test("renders child component", () => {
17 | const child = Child Component
;
18 | const {queryByText} = render({child} );
19 | const childComponent = queryByText(/Child Component/i);
20 | expect(childComponent).toBeTruthy();
21 | });
22 | });
--------------------------------------------------------------------------------
/src/components/_Landing/Landing.css:
--------------------------------------------------------------------------------
1 | /* * {
2 | font-family: 'Titillium Web', 'Arial', sans-serif;
3 | } */
4 |
5 | .glow {
6 | /* text-shadow:1px 1px 6px #fff; */
7 | }
8 |
9 | .glow-symbol {
10 | box-shadow:1px 1px 6px #fff;
11 | }
12 |
13 | .glow-subtitle-color {
14 | box-shadow: 1px 1px 6px #4bbede;
15 | }
16 | .glow-subtitles {
17 | /* text-shadow:1px 1px 20px #f1e192; */
18 | }
19 |
20 | .transparent-black-background {
21 | background-color: rgba(0, 0, 0, 0.4);
22 | }
23 |
24 | .star {
25 | position: absolute;
26 | width: 4px;
27 | height: 4px;
28 | border-radius: 2px;
29 | background: white;
30 | }
31 |
32 | .floating {
33 | animation-name: floating;
34 |
35 | animation-iteration-count: infinite;
36 | animation-timing-function: ease-in-out;
37 | margin-left: 30px;
38 | margin-top: 5px;
39 | }
40 |
41 | @keyframes floating {
42 | 0% { transform: translate(0, 0px); }
43 | 50% { transform: translate(0, 15px); }
44 | 100% { transform: translate(0, -0px); }
45 | }
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/tests/TeamMemberList.test.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable no-unused-vars */
3 |
4 | import React from "react";
5 | import { render } from "@testing-library/react";
6 | import TeamMemberList from "../pure_component/TeamMemberList";
7 |
8 | describe("TeamMemberList", () => {
9 | test("should render unordered list containing 6 list elements", () => {
10 | const consoleErr = console.error;
11 | console.error = jest.fn();
12 | const members = Array(6).fill(0).map((it) => {
13 | return {
14 | user_id : "John Doe",
15 | seriousness : 5,
16 | bio : "example biography",
17 | };
18 | });
19 | const {container} = render();
20 | expect(container.querySelector("ul")).toBeTruthy();
21 | expect(container.querySelector("ul").querySelectorAll("li").length).toBe(6);
22 | console.error = consoleErr;
23 | });
24 | });
--------------------------------------------------------------------------------
/src/components/_Landing/assets/scripts/stars.js:
--------------------------------------------------------------------------------
1 | import { TweenMax } from "gsap/TweenMax";
2 |
3 | // Amount of stars
4 | function createStars(numberOfStars) {
5 | for (let i = 0; i < numberOfStars; i++) {
6 | placeStarRandomly();
7 | }
8 | }
9 | // Create Stars
10 | function placeStarRandomly(){
11 | const tmpStar = document.createElement("div");
12 | tmpStar.className = "star";
13 | tmpStar.style.position = "absolute";
14 | tmpStar.style.top = 98*Math.random()+"%";
15 | tmpStar.style.left = 100*Math.random()+"%";
16 | document.getElementById("starryBackground").appendChild(tmpStar);
17 | }
18 |
19 | function animateStars() {
20 | const stars = document.querySelectorAll(".star");
21 | Array.prototype.forEach.call(stars, function(el,){
22 | TweenMax.to(el, Math.random() * 0.5 + 0.5, {opacity: Math.random(), onComplete: animateStars});
23 | });
24 | }
25 |
26 |
27 | export default function initStars(numberOfStars) {
28 | createStars(numberOfStars);
29 | animateStars();
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/_Landing/global_components/SocialMediaComponent.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/jsx-no-target-blank */
2 | /* eslint-disable react/jsx-max-props-per-line */
3 | import React from "react";
4 | import { FaInstagram } from "react-icons/fa";
5 | import { FaTwitter } from "react-icons/fa";
6 | import { FaFacebookF } from "react-icons/fa";
7 | function SocialMediaComponent() {
8 |
9 | return (
10 |
15 | );
16 | }
17 |
18 |
19 | export default SocialMediaComponent;
20 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/ExploreSearchBox.jsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import Box from "@material-ui/core/Box";
3 | import TextField from "@material-ui/core/TextField";
4 | import PropTypes from "prop-types";
5 |
6 | function ExploreSearchBox(props) {
7 | return (
8 | {
17 | props.setSearchText(e.target.value);
18 | }}
19 | onKeyPress={(e) => { // Prevent page from reloading on Enter
20 | if (e.key === "Enter") {
21 | e.preventDefault();
22 | }
23 | }}
24 | >
25 |
28 |
29 | );
30 | }
31 |
32 | ExploreSearchBox.propTypes = {
33 | setSearchText: PropTypes.func
34 | };
35 |
36 | export default ExploreSearchBox;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 HackRU
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/components/Live/Links.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import GlowButton from "../GlowButton";
3 | import { liveImportantLinks } from "../../Defaults";
4 | import { ProfileType } from "../Profile";
5 |
6 | class Links extends Component {
7 | render() {
8 | let items = [];
9 | for (let i = 0; i < liveImportantLinks.length; i++) {
10 | items.push(
11 |
17 | );
18 | }
19 | return (
20 |
21 |
22 |
23 | {items}
24 |
25 |
26 |
27 | );
28 | }
29 | }
30 |
31 | Links.propTypes = {
32 | profile: ProfileType
33 | };
34 |
35 | export default Links;
36 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/tests/GenericList.test.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable no-unused-vars */
3 |
4 | import React from "react";
5 | import { render } from "@testing-library/react";
6 | import GenericList from "../pure_component/GenericList";
7 |
8 | describe("GenericList", () => {
9 | test("should be empty", () => {
10 | const {container} = render( );
11 | const list = container.querySelectorAll("li");
12 | expect(list.length).toBe(0);
13 | });
14 | test("should contains three li's", () => {
15 | const entries = ["hi", "bye", "yo"];
16 | const {container} = render();
17 | const list = container.querySelectorAll("li");
18 | expect(list.length).toBe(3);
19 | });
20 | test("should render list with proper text", () => {
21 | const entries = ["hi", "bye", "yo"];
22 | const {container} = render();
23 | const list = [...container.querySelectorAll("li")].map((node) => node.innerHTML);
24 | expect(list).toStrictEqual(entries);
25 | });
26 | });
--------------------------------------------------------------------------------
/src/components/Errors/E404.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Container, Col } from "reactstrap";
3 | import { theme } from "../../Defaults";
4 | import { Link } from "react-router-dom";
5 | class E404 extends Component {
6 | render() {
7 | return (
8 |
11 |
12 |
14 |
15 |
¯\_(ツ)_/¯, this page doesn't exist
16 |
Click here to go back to land!
18 |
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | export default E404;
27 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/about/components/AboutContent.css:
--------------------------------------------------------------------------------
1 | .imgClass{
2 | min-width: 100px;
3 | min-height: 100px;
4 | max-width: 600px;
5 | max-height: 600px;
6 | margin: 60px 20px 60px 20px;
7 | }
8 |
9 | .textStyle{
10 | color: #f1e192;
11 | font-size: 25px;
12 | font-family: "Titillium Web";
13 | text-align: center;
14 | }
15 |
16 | .text-text {
17 | text-align: center;
18 | }
19 |
20 | .rectangle-container {
21 | display: flex;
22 | justify-content: center;
23 | }
24 | .rectangle {
25 | background-color: #f0e192;
26 | width: 45%;
27 | height: 3px;
28 | margin-bottom: 10px;
29 | }
30 |
31 | @media only screen and (max-width: 1226px) {
32 |
33 | .titleClass{
34 | padding-bottom: 40px;
35 | }
36 | }
37 | /* medium screen for split card*/
38 | @media only screen and (max-width: 769px) {
39 | .HeaderText{
40 | justify-content: center;
41 | }
42 | .textStyle{
43 | font-size: 25px;
44 | }
45 | .titleClass{
46 | padding-bottom: 0px;
47 | }
48 | }
49 |
50 | /* small screen for split card*/
51 | @media only screen and (max-width: 480px) {
52 | .textStyle{
53 | font-size: 20px;
54 | }
55 |
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/src/components/Landing/Sections/FaqsCollapse.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Collapse } from "@material-ui/core";
3 | import { Icon } from "react-fa";
4 | import PropTypes from "prop-types";
5 |
6 | class FaqsCollapse extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.toggle = this.toggle.bind(this);
10 | }
11 | UNSAFE_componentWillMount() {
12 | this.setState({
13 | collapse: false
14 | });
15 | }
16 | toggle() {
17 | this.setState({ collapse: !this.state.collapse });
18 | }
19 | render() {
20 | let cat = this.props.cat;
21 |
22 | return (
23 |
24 |
{cat.title}
26 |
27 |
{cat.text}
28 |
29 | );
30 | }
31 | }
32 |
33 | FaqsCollapse.propTypes = {
34 | cat: PropTypes.object
35 | };
36 |
37 | export default FaqsCollapse;
38 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/about/about.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Error from "../error";
3 | import AboutContent from "./components/AboutContent";
4 | import useAboutConfig, { useVerifyPreset } from "./hooks/useConfigAbout";
5 |
6 | function About() {
7 | const validPreset = useVerifyPreset();
8 |
9 | const { mainComponent } = useAboutConfig();
10 | const {
11 | useSplitCards,
12 | } = mainComponent;
13 |
14 | if (!validPreset) {
15 | return ;
18 | }
19 | // probably not the most dynamic code. Instead of useSplitCards, it should be based on the presents #. derp
20 | if (useSplitCards) {
21 | return (
22 |
27 | );
28 | } else {
29 | return (
30 |
34 | );
35 | }
36 |
37 |
38 | }
39 |
40 |
41 | export default About;
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{js,jsx,ts,tsx}",
5 | ],
6 | blocklist: [
7 | "collapse",
8 | ],
9 | theme: {
10 | extend: {
11 | screens: {
12 | "xs-about": "300px",
13 | //replace this with section specific breakpoints
14 | "sm-about": "300px",
15 | "md-about": "900px",
16 | "lg-about": "1000px",
17 | "xl-about": "1440px"
18 | },
19 | colors: {
20 | "mainBg": "#1f6aa0",
21 | "endBg": "#0f3854",
22 | "text": "#f1e192",
23 | "textSubtitle": "#f1e192",
24 |
25 | "f23-darkGreen": "#133d35",
26 | "f23-mediumGreen": "#3e8169",
27 | "f23-lightGreen": "#8db67e",
28 | "f23-yellowGreen": "#f1e192"
29 | },
30 | fontSize: {
31 | "10xl": "9rem",
32 | "11xl": "10rem",
33 | "12xl": "11rem",
34 | "13xl": "12rem"
35 | },
36 | spacing: {
37 | "128": "32rem",
38 | "144": "36rem",
39 | }
40 | },
41 | },
42 | plugins: [],
43 | };
44 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import "./index.css";
2 | import React from "react"; // Required react dependencies
3 | import ReactDOM from "react-dom"; // Required react dependencies
4 | import { register, unregister } from "./serviceWorker"; // Service worker dependencies
5 | import App from "./App"; // Default app and component to be rendered
6 | import { defaults } from "./Defaults"; // The standard list of strings that we will be using throughout the application
7 | import "bootstrap/dist/css/bootstrap.min.css"; // Boostrap import
8 | /**
9 | * Application entry point. Here we render the standard root components that are standard to all pages in the website
10 | *
11 | * @param {boolean} worker Toggle the default react service worker.
12 | * We default this to false because enabling the service worker brings with it application caching, which causes production
13 | * issues during version updates. If you would like to know about this issue in depth, read through the react documentation.
14 | */
15 | function main(worker) {
16 | // Render the default title
17 | ReactDOM.render(defaults.title, document.getElementById("title"));
18 | // Render the default root object
19 | ReactDOM.render( , document.getElementById("root"));
20 | // Decide whether or not we need to enable the default serviceworker
21 | if (worker) {
22 | register();
23 | } else {
24 | unregister();
25 | }
26 | }
27 | main(false);
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/tests/ConfirmationModal.test.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable no-unused-vars */
3 |
4 | import React from "react";
5 | import { render } from "@testing-library/react";
6 | import ConfirmationModal from "../pure_component/ConfirmationModal";
7 |
8 | describe("ConfirmationModal", () => {
9 | test("Confirm button should call onConfirm", () => {
10 | const fun = jest.fn();
11 | const {queryByText} = render( fun()}
12 | onCancel={() => {}}/>);
13 | const confirmationBtn = queryByText(/Confirm/);
14 | confirmationBtn.click();
15 | expect(fun).toHaveBeenCalledTimes(1);
16 | });
17 |
18 | test("Cancel button should call onCancel", () => {
19 | const fun = jest.fn();
20 | const {queryByText} = render( {}}
21 | onCancel={() => fun()}/>);
22 | const cancelBtn = queryByText(/Cancel/);
23 | cancelBtn.click();
24 | expect(fun).toHaveBeenCalledTimes(1);
25 | });
26 |
27 | test("message is rendered", () => {
28 | const msg = "This is the example message!";
29 | const {queryByText} = render( {}}
30 | onConfirm={() => {}}
31 | message={msg}/>);
32 | expect(queryByText(/This is the example message!/)).toBeTruthy();
33 | });
34 | });
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/tests/PureModal.test.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable no-unused-vars */
3 |
4 | import React from "react";
5 | import { render } from "@testing-library/react";
6 | import PureModal from "../pure_component/PureModal";
7 |
8 | describe("PureModal", () => {
9 | test("renders header and subheader", () => {
10 | const {queryByText} = render( {}}>Child );
13 |
14 | const header = queryByText(/Header/);
15 | const subHeader = queryByText(/Subheader/);
16 | expect(header).toBeTruthy();
17 | expect(subHeader).toBeTruthy();
18 | });
19 |
20 | test("onClick called when close button is clicked", () => {
21 | const fun = jest.fn();
22 | const {container} = render( fun()}>Child );
25 |
26 | const button = container.querySelector("button")?.click();
27 | expect(fun).toHaveBeenCalledTimes(1);
28 | });
29 |
30 | test("renders child component", () => {
31 | const {queryByText} = render( {}}>Children );
34 |
35 | expect(queryByText(/Children/)).toBeTruthy();
36 | });
37 | });
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | es6: true,
5 | node: true
6 | },
7 | extends: "eslint:recommended",
8 | globals: {
9 | Atomics: "readonly",
10 | SharedArrayBuffer: "readonly",
11 | JSX: true,
12 | },
13 | parser: "babel-eslint",
14 | parserOptions: {
15 | ecmaVersion: 6,
16 | sourceType: "module",
17 | ecmaFeatures: {
18 | jsx: true,
19 | modules: true,
20 | experimentalObjectRestSpread: true
21 | }
22 | },
23 | plugins: [
24 | "react"
25 | ],
26 | extends: [
27 | "eslint:recommended",
28 | "plugin:react/recommended"
29 | ],
30 | plugins: [
31 | "react"
32 | ],
33 | rules: {
34 | "indent": [
35 | "error",
36 | 4
37 | ],
38 | "quotes": [
39 | "error",
40 | "double"
41 | ],
42 | "semi": [
43 | "error",
44 | "always"
45 | ],
46 | "no-console": "off", // Allow log statements
47 | "react/display-name": "off", // Allow anonymous components
48 | "react/jsx-max-props-per-line": 1,
49 | "react/no-string-refs": "off",
50 | "react/no-unescaped-entities": "off",
51 | },
52 | settings: {
53 | react: {
54 | version: "detect",
55 | }
56 | }
57 | };
58 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/about/config/aboutConfigAbout.ts:
--------------------------------------------------------------------------------
1 | type AboutConfigPresets = 0 | 1 | 2;
2 |
3 | interface AboutConfig {
4 | mainComponent: {
5 | sidebarVisible: boolean;
6 | horizontalBarsVisible: boolean;
7 | headerTextBubblesVisible: boolean;
8 | headerTextAlignment: "left" | "middle" | "right" | "NA";
9 | subTextAlignment: "left" | "middle" | "right" | "NA";
10 | useSplitCards: boolean;
11 | };
12 | }
13 |
14 | const aboutOriginal: AboutConfig = {
15 | mainComponent: {
16 | sidebarVisible: true,
17 | horizontalBarsVisible: true,
18 | headerTextBubblesVisible: true,
19 | headerTextAlignment: "left",
20 | subTextAlignment: "left",
21 | useSplitCards: false,
22 | },
23 | };
24 | const aboutMiddleFocus: AboutConfig = {
25 | mainComponent: {
26 | sidebarVisible: false,
27 | horizontalBarsVisible: false,
28 | headerTextBubblesVisible: true,
29 | headerTextAlignment: "middle",
30 | subTextAlignment: "middle",
31 | useSplitCards: false,
32 | },
33 | };
34 |
35 | const aboutMIT: AboutConfig = {
36 | mainComponent: {
37 | sidebarVisible: false,
38 | horizontalBarsVisible: false,
39 | headerTextBubblesVisible: false,
40 | headerTextAlignment: "NA",
41 | subTextAlignment: "NA",
42 | useSplitCards: true,
43 | },
44 | };
45 | export { aboutOriginal, aboutMiddleFocus, aboutMIT };
46 | export type { AboutConfig, AboutConfigPresets };
47 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/about/hooks/useConfigAbout.ts:
--------------------------------------------------------------------------------
1 | import { useContext } from "react";
2 | import AboutContext from "../contextAbout";
3 | import {
4 | aboutMIT,
5 | aboutMiddleFocus,
6 | aboutOriginal,
7 | AboutConfig,
8 | AboutConfigPresets,
9 | } from "../config/aboutConfigAbout";
10 |
11 | /**
12 | * Contains all the configurations for the hero components.
13 | * ORDERING OF PRESETS IS IMPORTANT
14 | */
15 |
16 | const configs = [aboutOriginal, aboutMiddleFocus, aboutMIT];
17 |
18 | /**
19 | * Verifies that the preset is valid by checking with the configs array.
20 | * @returns {boolean} Whether the preset is valid or not.
21 | */
22 | function useVerifyPreset() {
23 | const preset: AboutConfigPresets = useContext(AboutContext);
24 | return !(preset > configs.length || preset < 0 || !configs[preset]);
25 | }
26 |
27 | /**
28 | This is the hero config hook used by hero components to retrieve configuration.
29 | The configuration they receive is determined by the HeroContext provider.
30 | To change the HeroContext, you would need to go to contexts.tsx and change the value of the HeroContext.
31 | @returns {AboutConfig} The configuration for the hero component.
32 | */
33 | function useAboutConfig(): AboutConfig {
34 | if (!useVerifyPreset()) {
35 | throw new Error("Invalid preset. ");
36 | }
37 | const preset: AboutConfigPresets = useContext(AboutContext);
38 | return configs[preset];
39 | }
40 |
41 | export default useAboutConfig;
42 | export { useVerifyPreset };
43 |
--------------------------------------------------------------------------------
/src/components/Sponsorship/SponsorshipConfig.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import AboutSponsorship from "./Sections/AboutSponsorship";
3 | import SponsorshipPackages from "./Sections/SponsorshipPackages";
4 | import Testimonials from "./Sections/Testimonials";
5 | import Recap from "./Sections/Recap";
6 | import Footer from "./Sections/Footer";
7 |
8 |
9 | const sponsorshipLinks = {
10 | "About": {
11 | "url": "#about",
12 | "enabled": true,
13 | "hideLink": false,
14 | "fullHeight": false,
15 | "component": (props) =>
16 | },
17 | "Recap": {
18 | "url": "#recap",
19 | "enabled": true,
20 | "hideLink": false,
21 | "fullHeight": false,
22 | "component": (props) =>
23 | },
24 | "Testimonials": {
25 | "url": "#testimonials",
26 | "enabled": true,
27 | "hideLink": false,
28 | "fullHeight": false,
29 | "component": (props) =>
30 | },
31 | "Packages": {
32 | "url": "#packages",
33 | "enabled": true,
34 | "hideLink": false,
35 | "fullHeight": false,
36 | "component": (props) =>
37 | },
38 | "Footer": {
39 | "url": "#footer",
40 | "enabled": true,
41 | "hideLink": true,
42 | "fullHeight": false,
43 | "skew": false,
44 | "component": (props) =>
45 | },
46 |
47 | };
48 |
49 | export {
50 | sponsorshipLinks
51 | };
52 |
--------------------------------------------------------------------------------
/src/components/Dashboard/Forms/UserProfileForm/CustomAVInput.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { AvField } from "availity-reactstrap-validation";
3 | import PropTypes from "prop-types";
4 |
5 | /**
6 | * AVField wrapper object that allows for a custom input for validation
7 | * Expects props: {
8 | * name: String,
9 | * label: React Renderable,
10 | * value: String,
11 | * validate: JSON Object
12 | * }
13 | */
14 | class CustomAVInput extends Component {s
15 | UNSAFE_componentWillMount() {
16 | this.setState({
17 | width: "100%"
18 | });
19 | }
20 | componentDidMount() {
21 | this.setState({
22 | width: this.refs.avfield.offsetWidth
23 | });
24 | }
25 | render() {
26 | return (
27 |
28 |
37 |
38 | {this.props.children}
39 |
40 |
41 | );
42 | }
43 | }
44 |
45 | CustomAVInput.propTypes = {
46 | children: PropTypes.node,
47 | name: PropTypes.string,
48 | label: PropTypes.string,
49 | value: PropTypes.string,
50 | validate: PropTypes.bool,
51 | };
52 |
53 | export default CustomAVInput;
54 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | HackRU
30 |
31 |
32 |
33 |
34 | You need to enable JavaScript to view this website
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamLoading.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Grid } from "@material-ui/core";
3 | import { BounceLoader, PulseLoader } from "react-spinners";
4 | import { theme } from "../../Defaults";
5 | import PropTypes from "prop-types";
6 |
7 | /**
8 | * Render a loading screen
9 | * @param {String} Text Loading subtext
10 | */
11 | const TeamLoading = ({ text }) => (
12 |
18 |
21 | {/* style={{ display: "block", zIndex: 3, backgroundColor: theme.secondary[1], color: "white", boxShadow: "0px 0px 10px rgba(0, 0, 0, 0.5)" }} */}
22 |
24 |
25 |
L
26 |
27 |
28 |
29 |
30 |
31 |
ading
32 |
33 |
36 |
{ text }
37 |
38 |
39 |
40 | );
41 | TeamLoading.propTypes = {
42 | text: PropTypes.string,
43 | };
44 | export default TeamLoading;
45 |
--------------------------------------------------------------------------------
/src/components/Dashboard/Loading.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Grid } from "@material-ui/core";
3 | import { BounceLoader, PulseLoader } from "react-spinners";
4 | import { theme } from "../../Defaults";
5 | import PropTypes from "prop-types";
6 |
7 | /**
8 | * Render a loading screen
9 | * @param {String} Text Loading subtext
10 | */
11 | const Loading = ({ text }) => (
12 |
18 |
23 |
25 |
26 |
L
27 |
28 |
29 |
30 |
31 |
32 |
ading
33 |
34 |
37 |
{ text }
38 |
39 |
40 |
41 | );
42 | Loading.propTypes = {
43 | text: PropTypes.string,
44 | };
45 | export default Loading;
46 |
--------------------------------------------------------------------------------
/src/components/_Landing/global_components/CardAbout.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import useAboutConfig from "../sections/about/hooks/useConfigAbout";
4 | import "./CardAbout.css";
5 |
6 | const getVisiblity = (visibility: boolean) => {
7 | return visibility ? "visible" : "hidden";
8 | };
9 |
10 | function Card(props: any) {
11 | const { mainComponent } = useAboutConfig();
12 | const {
13 | sidebarVisible,
14 | useSplitCards,
15 | } = mainComponent;
16 |
17 | if (useSplitCards) {
18 | return (
19 |
24 | {props.children}
25 |
26 | );
27 | } else {
28 | return (
29 |
30 |
35 |
36 | {props.sideBar ?
37 |
: ""}
39 | {props.children}
40 |
41 | );
42 | }
43 |
44 | }
45 | Card.propTypes = {
46 | backgroundColor: PropTypes.any,
47 | sideBar: PropTypes.any,
48 | children: PropTypes.element
49 | };
50 | export default Card;
--------------------------------------------------------------------------------
/public/assets/background/circle_green.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
13 |
14 |
15 |
16 |
17 |
19 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/public/assets/background/circle_red.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
13 |
14 |
15 |
16 |
17 |
19 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/public/assets/background/circle_yellow.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
13 |
14 |
15 |
16 |
17 |
19 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/hooks/useDebounce/usDebounce.js:
--------------------------------------------------------------------------------
1 | import {useEffect, useRef} from "react";
2 |
3 | /**
4 | * returns a debounced version of fn which is throttled based on @param wait
5 | *
6 | * @param {Function} fn the function to be debounced
7 | * @param {number} wait amount of time in milliseconds to wait before can call function again
8 | * @param {boolean} immediate whether to immediately call fn when triggered (true), or to wait to call fn (false) - default true
9 | * @param {boolean} lenient default is false
10 | * @param {any[]} dependencies optional list of dependencies that, when changed, will - default []
11 | */
12 | const useDebounce = (fn, wait, immediate = true, lenient = false, dependencies = []) => {
13 | const timer = useRef(null);
14 | useEffect(() => {
15 | return () => {
16 | timer.current && clearTimeout(timer.current);
17 | timer.current = null;
18 | };
19 | }, dependencies);
20 | /**
21 | * A throttled version of the function passed in from useDebounce
22 | *
23 | * @param {...any} args the variable amount of arguments that will be passed to the debounced function once it is run
24 | */
25 | const deBouncedFn = (...args) => {
26 | const runNow = !timer.current && immediate;
27 | const later = () => {
28 | timer.current = null;
29 | !immediate && fn(...args);
30 | };
31 | if (!lenient) {
32 | timer.current && clearTimeout(timer.current);
33 | timer.current = setTimeout(later, wait);
34 | } else {
35 | !timer.current && (timer.current = setTimeout(later, wait));
36 | }
37 | runNow && fn(...args);
38 | };
39 |
40 | return {
41 | timer,
42 | deBouncedFn,
43 | };
44 | };
45 |
46 | export default useDebounce;
--------------------------------------------------------------------------------
/src/components/Dashboard/Forms/UserProfileForm/ResumeUploader.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { CustomInput, FormGroup } from "reactstrap";
3 | import { ProfileType } from "../../../Profile";
4 | import { theme } from "../../../../Defaults";
5 | import PropTypes from "prop-types";
6 |
7 | const ResumeUploader = React.memo(({ edit, profile }) => {
8 | const [labelText, setLabelText] = useState("Loading...");
9 |
10 | useEffect(() => {
11 | profile.DoesResumeExist().then((success) => {
12 | setLabelText(
13 | success ? "Resume found" : edit ? "Choose a file to upload" : "Nothing yet"
14 | );
15 | });
16 | }, []);
17 |
18 | const onUpload = async (event) => {
19 | setLabelText("Uploading resume...");
20 | // Make the upload request
21 | const res = await profile.UploadResume(event.target.files[0]);
22 | setLabelText(res.ok ? "Resume uploaded successfully." : "Failed to upload resume");
23 | };
24 |
25 | const pStyle = {
26 | color: theme.disabled[0] + "70",
27 | padding: 5,
28 | height: 35,
29 | };
30 |
31 | return (
32 |
33 |
34 | {edit ? (
35 |
42 | ) : (
43 | {labelText}
44 | )}
45 |
46 |
47 | );
48 | });
49 |
50 | ResumeUploader.propTypes = {
51 | edit: PropTypes.bool,
52 | profile: ProfileType,
53 | };
54 |
55 | export default ResumeUploader;
--------------------------------------------------------------------------------
/public/assets/background/circle_white.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
14 |
15 |
16 |
17 |
18 |
20 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/public/assets/icons/hru-text-one.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 |
11 |
17 |
18 |
19 |
22 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/components/Dashboard/Forms/UserProfileForm/majors.json:
--------------------------------------------------------------------------------
1 | {"items": ["Accounting","Aerospace Engineering","Agricultural Engineering","Applied Mathematics","Architecture","Biochemistry","Bioengineering","Bioinformatics","Biological Sciences","Biology","Biomedical Engineering","Biotechnology","Building Construction Management","Business","Business Administration","Business Analytics","Chemical Engineering","Chemistry","Civil Engineering","Cognitive Science","Communications","Computational Biology","Computational Media","Computer Engineering","Computer Science","Computer Information Systems","Computer Technologies","Computing Security","Culinary Arts","Cyber Operations","Data Science","Design","Economics","Electrical Engineering","Engineering","Engineering Management","Engineering Physics","Engineering Science","English","Film","Finance","Game Design and Development","Geophysics","Graphic Design","Human Centered Design","Human Computer Interaction","Humanities","Individualized Major","Industrial and Systems Engineering","Industrial and Operations Engineering","Industrial Engineering","Informatics","Information Science","Information Systems","Information Technology","Interaction Design","Interactive Multimedia","Interactive Telecommunications Program (ITP)","International Relations","Journalism","Linguistics","Management","Management Information Systems","Marketing","Materials Science","Mathematics","Mechanical Engineering","Mechatronics","Mechatronics Engineering","Media Arts and Sciences","Music Computing","Nanoengineering","Network Security","Neurobiology/Cognitive Science","Neuroscience","New Media Design","Operations Research Management Science","Organizational","Philosophy","Physics","Political Science","Poultry Science","Product Design","Psych","Psychology","Robotics Engineering","Robotics","Software Engineering","Statistics","Systems Design Engineering","Technology Management","Theatre and Linguistics"]}
2 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/pure_component/ConfirmationModal.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import ModalBackground from "./ModalBackground";
4 | import PureModal from "./PureModal";
5 |
6 | import modalstyles from "../styles/ModalStyle.module.css";
7 |
8 | const ConfirmationModal = (props) => {
9 | const {onConfirm, onCancel} = props;
10 | return (
11 | <>
12 |
13 |
17 |
18 | {
19 | props.message &&
{props.message}
20 | }
21 |
22 |
24 |
25 | Confirm
26 |
27 |
28 |
30 |
31 | Cancel
32 |
33 |
34 |
35 |
36 |
37 | >
38 | );
39 | };
40 |
41 | ConfirmationModal.propTypes = {
42 | onConfirm : PropTypes.func.isRequired,
43 | onCancel : PropTypes.func.isRequired,
44 | message : PropTypes.string,
45 | title : PropTypes.string,
46 | };
47 |
48 | export default ConfirmationModal;
--------------------------------------------------------------------------------
/src/components/_Landing/Default.js:
--------------------------------------------------------------------------------
1 | let computedStyle = getComputedStyle(document.body);
2 |
3 | const defaults = {
4 | volunteers: {
5 | display: true,
6 | vol_url:
7 | "https://forms.gle/Ysdpkv96v7ACY4w56",
8 | mentor_url:
9 | "https://forms.gle/5uqL314eHmZybgiR7",
10 | },
11 | mailing:
12 | "https://hackru.us3.list-manage.com/subscribe?u=457c42db47ebf530a0fc733fb&id=fb01885829",
13 |
14 | };
15 | const theme = {
16 | primary: [
17 | computedStyle.getPropertyValue("--primary-color"),
18 | computedStyle.getPropertyValue("--primary-color-alt"),
19 | ],
20 | secondary: [
21 | computedStyle.getPropertyValue("--secondary-color"),
22 | computedStyle.getPropertyValue("--secondary-color-alt"),
23 | ],
24 | accent: [
25 | computedStyle.getPropertyValue("--accent-color"),
26 | computedStyle.getPropertyValue("--accent-color-alt"),
27 | ],
28 | disabled: [computedStyle.getPropertyValue("--disabled-color")],
29 |
30 | splitCard:[
31 | computedStyle.getPropertyValue("--splitCard-color"),
32 | ],
33 | };
34 |
35 | let varList = [
36 | // Form Inputs
37 | "input-background",
38 | "input-placeholder",
39 | "input-border",
40 | "input-color",
41 | "input-border-radius",
42 | "select-background",
43 | "select-color",
44 | "select-input-background",
45 | // Hero Image
46 | "hero-width",
47 | "hero-height",
48 | "hero-border-radius",
49 | "hero-background",
50 | // Sponsors
51 | "sponsors-title-color",
52 | "sponsors-platinum-color",
53 | "sponsors-gold-color",
54 | "sponsors-silver-color",
55 | "sponsors-bronze-color",
56 | ];
57 | varList.forEach((element) => {
58 | theme[element] = computedStyle.getPropertyValue("--" + element);
59 | return element;
60 | });
61 |
62 | export {theme,defaults};
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/pure_component/PureModal.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import modalstyles from "../styles/ModalStyle.module.css";
4 | import { Typography } from "@material-ui/core";
5 | import { HighlightOff } from "@material-ui/icons";
6 |
7 | const PureModal = (props) => {
8 | const { header, children, onClick } = props;
9 | return (
10 |
11 |
12 |
13 |
15 | {header}
16 |
17 | {
18 | props.subHeader &&
19 |
21 | {props.subHeader}
22 |
23 | }
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | {children}
33 |
34 |
35 | );
36 | };
37 |
38 | PureModal.propTypes = {
39 | header : PropTypes.string.isRequired,
40 | subHeader : PropTypes.string,
41 | children : PropTypes.node.isRequired,
42 | onClick : PropTypes.func.isRequired,
43 | isPrompt : PropTypes.bool,
44 | };
45 |
46 | export default PureModal;
--------------------------------------------------------------------------------
/public/assets/background/target-thick_white.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
14 |
15 |
16 |
17 |
18 |
20 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/faq/FAQ.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import QuestionContainer from "./QuestionContainer";
3 | import cloud from "../../assets/clouds/cloud1.png";
4 | import cloud3 from "../../assets/clouds/cloud3.png";
5 | import owl from "../../assets/animals/owl-min.png";
6 | import skunk from "../../assets/animals/skunkIslandv2-min.png";
7 |
8 | function FAQ() {
9 | return (
10 |
15 |
16 |
17 |
26 |
27 |
36 |
37 |
39 |
42 |
43 |
44 | );
45 | }
46 |
47 | export default FAQ;
--------------------------------------------------------------------------------
/src/components/Dashboard/Forms/UserProfileForm/VaccineUploader.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { CustomInput, FormGroup } from "reactstrap";
3 | import { ProfileType } from "../../../Profile";
4 | import { theme } from "../../../../Defaults";
5 | import PropTypes from "prop-types";
6 |
7 |
8 | const VaccineUploader = (props) => {
9 |
10 | const [vaccineLabelText, setVaccineLabelText] = useState("Loading...");
11 |
12 | useEffect(() => {
13 | props.profile.DoesVaccineExist().then((success) => {
14 | setVaccineLabelText(
15 | success ? "Vaccine Card found" : props.edit ? "Choose a file to upload" : "Nothing yet"
16 | );
17 | });
18 | }, []);
19 |
20 | const onVaccineUpload = async (event) => {
21 | setVaccineLabelText("Uploading Vaccine Card...");
22 | const res = await props.profile.UploadVaccine(event.target.files[0]);
23 | setVaccineLabelText(res.ok ? "Vaccine Card uploaded successfully." : "Failed to upload Vaccine Card");
24 | };
25 | const pStyle = {
26 | color: theme.disabled[0] + "70",
27 | padding: 5,
28 | height: 35,
29 | };
30 |
31 | return (
32 |
33 |
34 |
35 | {props.edit ? (
36 |
43 | ) : (
44 | {vaccineLabelText}
45 | )}
46 |
47 |
48 | );
49 | };
50 |
51 | VaccineUploader.propTypes = {
52 | edit: PropTypes.bool,
53 | profile: ProfileType,
54 | checkVaccine: PropTypes.func
55 | };
56 |
57 | export default VaccineUploader;
58 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/sponsors/Sponsors.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import echo_3d from "../../assets/sponsors/echo_3d.png";
3 | import nj_transit from "../../assets/sponsors/nj_transit.png";
4 | import merck from "../../assets/sponsors/merck.png";
5 | import cloud3 from "../../assets/clouds/cloud3.png";
6 | import cloud2 from "../../assets/clouds/cloud2.png";
7 |
8 | function Sponsors() {
9 | return (
10 |
48 | );
49 | }
50 |
51 | export default Sponsors;
--------------------------------------------------------------------------------
/src/components/Landing/Sections/Sponsors/SponsorContainer.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { theme } from "../../../../Defaults.js";
3 | import SponsorItem from "./SponsorItem.jsx";
4 | import { Container, Grid } from "@material-ui/core";
5 | import PropTypes from "prop-types";
6 |
7 |
8 | const sponsor_colors = {
9 | };
10 |
11 | class SponsorContainer extends Component {
12 | render() {
13 | let { declaration } = this.props;
14 | let sponsors = [];
15 | for (let i = 0; i < declaration.children.length; i++) {
16 | sponsors.push( );
24 | }
25 | return (
26 |
29 | { this.props.showName &&
30 |
32 |
33 |
35 | {declaration.name}
36 |
37 |
38 | }
39 |
41 | {sponsors}
42 |
43 |
44 | );
45 | }
46 | }
47 |
48 | SponsorContainer.propTypes = {
49 | declaration: PropTypes.object,
50 | baseURL: PropTypes.string,
51 | showName: PropTypes.bool
52 | };
53 |
54 | export default SponsorContainer;
--------------------------------------------------------------------------------
/src/components/Dashboard/Forms/UserProfileForm/WaiverUploader.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { CustomInput, FormGroup } from "reactstrap";
3 | import { ProfileType } from "../../../Profile";
4 | import { theme } from "../../../../Defaults";
5 | import PropTypes from "prop-types";
6 |
7 |
8 | const WaiverUploader = (props) => {
9 |
10 | const [waiverLabelText, setWaiverLabelText] = useState("Loading...");
11 |
12 | useEffect(() => {
13 | props.profile.DoesWaiverExist().then((success) => {
14 | props.checkWaiver(success ? "Waiver found" : props.edit ? "Choose a file to upload" : "Nothing yet");
15 | setWaiverLabelText(
16 | success ? "Waiver found" : props.edit ? "Choose a file to upload" : "Nothing yet"
17 | );
18 | });
19 | }, []);
20 |
21 | const onWaiverUpload = async (event) => {
22 | setWaiverLabelText("Uploading waiver...");
23 | // Make the upload request
24 | const res = await props.profile.UploadWaiver(event.target.files[0]);
25 | props.checkWaiver(res.ok ? "Waiver uploaded successfully." : "Failed to upload waiver");
26 | setWaiverLabelText(res.ok ? "Waiver uploaded successfully." : "Failed to upload waiver");
27 | };
28 | const pStyle = {
29 | color: theme.disabled[0] + "70",
30 | padding: 5,
31 | height: 35,
32 | };
33 |
34 | return (
35 |
36 |
37 |
38 | {props.edit ? (
39 |
46 | ) : (
47 | {waiverLabelText}
48 | )}
49 |
50 |
51 | );
52 | };
53 |
54 | WaiverUploader.propTypes = {
55 | edit: PropTypes.bool,
56 | profile: ProfileType,
57 | checkWaiver: PropTypes.func
58 | };
59 |
60 | export default WaiverUploader;
61 |
--------------------------------------------------------------------------------
/.github/workflows/prod-deploy.yml:
--------------------------------------------------------------------------------
1 | # This workflow will automatically deploy to dev.hackru.org
2 |
3 | name: Deploy to hackru.org
4 |
5 | on:
6 | push:
7 | branches:
8 | - env/prod
9 |
10 | jobs:
11 | code-quality:
12 | runs-on: ubuntu-18.04
13 |
14 | strategy:
15 | fail-fast: true
16 | matrix:
17 | node-version: [12.x, 14.x]
18 |
19 | steps:
20 | - uses: actions/checkout@v2
21 | - name: Test using Node ${{ matrix.node-version }}
22 | uses: actions/setup-node@v1
23 | with:
24 | node-version: ${{ matrix.node-version }}
25 | - run: npm install
26 | - run: npm run lint
27 | deploy:
28 | runs-on: ubuntu-18.04
29 |
30 | strategy:
31 | fail-fast: true
32 | matrix:
33 | node-version: [12.x]
34 |
35 | steps:
36 | - uses: actions/checkout@v2
37 | - name: Test using Node ${{ matrix.node-version }}
38 | uses: actions/setup-node@v1
39 | with:
40 | node-version: ${{ matrix.node-version }}
41 | - run: npm install
42 | - run: CI=false REACT_APP_MAP_KEY=${{ secrets.MAP_KEY }} npm run build-prod
43 | - name: Empty Bucket
44 | run: aws s3 rm s3://hackru-frontend-prod --recursive
45 | env:
46 | AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
47 | AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
48 |
49 | - name: Upload to S3
50 | run:
51 | aws s3 cp --recursive build s3://hackru-frontend-prod --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers;
52 | aws s3 cp --recursive --exclude '*' --include '*.svg' --content-type 'image/svg+xml' build s3://hackru-frontend-prod --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers;
53 | aws cloudfront create-invalidation --distribution-id "E1YIAV5VULIMY7" --paths "/*"
54 | env:
55 | AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
56 | AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
57 |
--------------------------------------------------------------------------------
/.github/workflows/dev-deploy.yml:
--------------------------------------------------------------------------------
1 | # This workflow will automatically deploy to dev.hackru.org
2 |
3 | name: Deploy to dev.hackru.org
4 |
5 | on:
6 | push:
7 | branches:
8 | - env/dev
9 |
10 | jobs:
11 | code-quality:
12 | runs-on: ubuntu-latest
13 |
14 | strategy:
15 | fail-fast: true
16 | matrix:
17 | node-version: [12.x, 14.x]
18 |
19 | steps:
20 | - uses: actions/checkout@v2
21 | - name: Test using Node ${{ matrix.node-version }}
22 | uses: actions/setup-node@v1
23 | with:
24 | node-version: ${{ matrix.node-version }}
25 | - run: npm install
26 | - run: npm run lint
27 | deploy:
28 | runs-on: ubuntu-latest
29 |
30 | strategy:
31 | fail-fast: true
32 | matrix:
33 | node-version: [12.x]
34 |
35 | steps:
36 | - uses: actions/checkout@v2
37 | - name: Test using Node ${{ matrix.node-version }}
38 | uses: actions/setup-node@v1
39 | with:
40 | node-version: ${{ matrix.node-version }}
41 | - run: npm install
42 | - run: NODE_ENV=development CI=false REACT_APP_MAP_KEY=${{ secrets.MAP_KEY }} npm run build-dev
43 | - name: Empty Bucket
44 | run: aws s3 rm s3://hackru-frontend-dev --recursive
45 | env:
46 | AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
47 | AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
48 |
49 | - name: Upload to S3
50 | run:
51 | aws s3 cp --recursive build s3://hackru-frontend-dev --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers;
52 | aws s3 cp --recursive --exclude '*' --include '*.svg' --content-type 'image/svg+xml' build s3://hackru-frontend-dev --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers;
53 | aws cloudfront create-invalidation --distribution-id "E1G9Y2VX0F41B6" --paths "/*"
54 | env:
55 | AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
56 | AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
57 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/TeamInfoModal.jsx:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types";
2 | import React, { useEffect, useState, useReducer, useCallback } from "react";
3 | import { useCancellablePromise } from "../../../../hooks/CancellablePromise";
4 | import TeamLoading from "../../TeamLoading";
5 | import PureModal from "./pure_component/PureModal";
6 | import ModalBackground from "./pure_component/ModalBackground";
7 | import TeamInfoPure from "./pure_component/TeamInfoPure";
8 |
9 | const teamInfoReducer = (state, action) => {
10 | switch (action.type) {
11 | default: return {
12 | ...action.payload,
13 | };
14 | }
15 | };
16 |
17 | const initialState = {};
18 |
19 | const TeamInfoModal = (props) => {
20 | const { teamName, teamId, onClose, profile } = props;
21 | const {cancellablePromise : fetchTeamInfo } = useCancellablePromise([teamName]);
22 | const [isLoading, setLoading] = useState(true);
23 | const [teamInfoState, dispatchTeamInfo] = useReducer(teamInfoReducer, initialState);
24 |
25 | const handleTeamInfoRequest = useCallback(async (resp) => {
26 | dispatchTeamInfo({ type : "do", payload: resp.response });
27 | setLoading(false);
28 | }, []);
29 |
30 | useEffect(() => {
31 | fetchTeamInfo(profile.getTeam(teamId), handleTeamInfoRequest, async (resp) => { console.log(resp); });
32 | }, [teamName]);
33 |
34 | return (
35 | <>
36 |
37 |
39 | <>
40 | {
41 | isLoading ?
42 |
43 | :
44 | <>
45 |
46 | >
47 | }
48 | >
49 |
50 | >
51 | );
52 | };
53 |
54 | TeamInfoModal.propTypes = {
55 | teamName : PropTypes.string,
56 | teamId : PropTypes.string,
57 | profile : PropTypes.shape({
58 | getTeam: PropTypes.func,
59 | }),
60 | onClose : PropTypes.func,
61 | };
62 |
63 | export default TeamInfoModal;
--------------------------------------------------------------------------------
/public/assets/icons/hru-text.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/public/assets/icons/hru-text-dyn.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/public/assets/icons/hru-text-red.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/components/_Landing/Landing.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import "./Landing.css";
3 | // import About from "../Landing/Sections/About";
4 | import Footer from "./sections/footer/Footer";
5 | import About from "./sections/about/about";
6 | import FAQ from "./sections/faq/FAQ";
7 | import Hero from "./sections/hero/hero";
8 | import { randomizeAnimationDurations } from "./utilities";
9 | import Schedule from "./sections/schedule/Schedule";
10 | import Sponsors from "./sections/sponsors/Sponsors";
11 | import Sun from "./assets/sun/sun";
12 | import SectionTitle from "./global_components/SectionTitle";
13 | import { scrollToSectionName, useUserScrolled } from "./sections/hero/utilities";
14 | import { FaArrowDown } from "react-icons/fa";
15 |
16 | function LandingPage(props: any) {
17 | const userHasScrolled = useUserScrolled(7);
18 |
19 | useEffect(() => {
20 | randomizeAnimationDurations("floating", 5, 9);
21 | randomizeAnimationDurations("clouds", 300, 500);
22 | }, []);
23 |
24 | return (
25 |
27 |
28 |
29 |
scrollToSectionName("About")}
34 | />
35 |
36 |
37 |
39 |
40 |
41 |
42 |
43 |
45 |
46 |
47 |
48 |
52 |
53 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | );
62 | }
63 | export default LandingPage;
64 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/footer/Footer.tsx:
--------------------------------------------------------------------------------
1 | import { FaFacebookF } from "react-icons/fa";
2 | import { FaInstagram } from "react-icons/fa";
3 | import { FaTwitter } from "react-icons/fa";
4 | import { MdEmail } from "react-icons/md";
5 | import React from "react";
6 |
7 | /**
8 | * About component for the landing page
9 | */
10 | function Footer() {
11 | return (
12 |
13 |
46 |
Ⓒ HackRU 2023
47 |
48 | );
49 |
50 | }
51 | export default Footer;
52 |
--------------------------------------------------------------------------------
/src/MLHBadge.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | class MLHBadge extends Component {
4 | constructor(props) {
5 | super(props);
6 | this.handleScroll = this.handleScroll.bind(this);
7 | this.handleResize = this.handleResize.bind(this);
8 | this.state = {
9 | isVisible: true,
10 | badgeHeight: 0,
11 | };
12 | }
13 |
14 | handleResize() {
15 | let badge = document.getElementById("mlh-trust-badge");
16 | if (badge == null) {
17 | return;
18 | }
19 | this.setState({
20 | badgeHeight: parseFloat(
21 | window
22 | .getComputedStyle(badge)
23 | .getPropertyValue("height")
24 | .replace("px", "")
25 | ),
26 | });
27 | }
28 |
29 | handleScroll() {
30 | let badgeHeight = this.state.badgeHeight;
31 | let offset = window.pageYOffset;
32 | if (offset < badgeHeight) {
33 | //At top
34 | this.setState({
35 | isVisible: true,
36 | });
37 | } else if (offset > badgeHeight) {
38 | this.setState({
39 | isVisible: false,
40 | });
41 | }
42 | }
43 |
44 | componentDidMount() {
45 | window.addEventListener("scroll", this.handleScroll);
46 | window.addEventListener("resize", this.handleResize);
47 | this.handleResize();
48 | }
49 |
50 | componentWillUnmount() {
51 | window.removeEventListener("scroll", this.handleScroll);
52 | window.removeEventListener("resize", this.handleResize);
53 | }
54 |
55 | render() {
56 | return (
57 | this.state.isVisible
58 | &&
59 |
62 |
65 |
66 | );
67 | }
68 | }
69 |
70 | export default MLHBadge;
71 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/RenderRow.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ListItemSecondaryAction, IconButton, ListItemAvatar, ListItem, ListItemText, Avatar } from "@material-ui/core";
3 | import PropTypes from "prop-types";
4 | import GroupAdd from "@material-ui/icons/GroupAdd";
5 | import TeamInfoModal from "./TeamInfoModal";
6 |
7 |
8 | function RenderRow(props) {
9 |
10 | const { invitingTeam, originalTeamId } = props;
11 |
12 | const [showModal, setShowModal] = React.useState(false);
13 |
14 | async function handleClick() {
15 | await props.profile.inviteTeam(originalTeamId, invitingTeam.team_id);
16 | props.onInvite(props.index);
17 | }
18 |
19 | return (
20 | <>
21 | {
22 | showModal && setShowModal(false)}
26 | />
27 | }
28 |
30 |
31 | {invitingTeam.name ? invitingTeam.name.substring(0, 1) : ""}
32 |
33 | setShowModal(true)}
37 | />
38 |
39 |
46 |
47 |
48 |
49 |
50 | >
51 | );
52 | }
53 | RenderRow.propTypes = {
54 | invitingTeam: PropTypes.object,
55 | originalTeamId: PropTypes.string,
56 | profile: PropTypes.object,
57 | onInvite: PropTypes.func,
58 | index: PropTypes.number,
59 | };
60 |
61 | export default RenderRow;
--------------------------------------------------------------------------------
/src/components/Live/Live.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Container, Row, Col } from "reactstrap";
3 | import { theme } from "../../Defaults.js";
4 | import Map from "./Map.jsx";
5 | import Links from "./Links.jsx";
6 | import Schedule from "./Schedule.jsx";
7 | import Announcements from "./Announcements.jsx";
8 | import { ProfileType } from "../Profile";
9 |
10 | class Live extends Component {
11 | render() {
12 | return (
13 |
16 |
18 |
19 |
20 |
21 |
23 | HackRU Live
24 |
25 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | );
47 | }
48 | }
49 |
50 | Live.propTypes = {
51 | profile: ProfileType,
52 | };
53 |
54 | export default Live;
55 |
--------------------------------------------------------------------------------
/src/components/Dashboard/Section.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Collapse, Col, Button } from "reactstrap";
3 | import { Icon } from "react-fa";
4 | import PropTypes from "prop-types";
5 | /**
6 | * A collapsable section on the dashboard
7 | * It takes four props, 'children', 'isOpen' (if it is initially expanded), 'title', and 'subtitle'
8 | */
9 | class Section extends Component {
10 | /**
11 | * Set the default object state
12 | * @param {Object} props React properties
13 | */
14 | constructor(props) {
15 | super(props);
16 | this.state = {
17 | isOpen: props.isOpen
18 | };
19 | }
20 | /**
21 | * The default render method
22 | */
23 | render() {
24 | let { children, title, hideButton, hideTopStrip, ...rest } = this.props;
25 | let color = this.props.color;
26 | if (!color){
27 | color = "red";
28 | }
29 | return (
30 |
32 |
34 |
35 | { !hideTopStrip &&
36 |
37 | {title}
38 | { !hideButton &&
39 | this.setState({ isOpen: !this.state.isOpen })}>
43 |
44 |
45 | }
46 |
47 | }
48 |
49 |
50 | {children}
51 |
52 |
53 |
54 |
55 | );
56 | }
57 | }
58 | Section.propTypes = {
59 | isOpen: PropTypes.bool,
60 | children: PropTypes.any,
61 | title: PropTypes.string,
62 | color: PropTypes.string,
63 | hideButton: PropTypes.bool,
64 | hideTopStrip: PropTypes.bool
65 | };
66 | export default Section;
67 |
--------------------------------------------------------------------------------
/src/components/Dashboard/TeamViewer/TeamInfoModal/pure_component/TeamInfoPure.jsx:
--------------------------------------------------------------------------------
1 | import PropTypes from "prop-types";
2 | import React from "react";
3 |
4 | import modalstyles from "../styles/ModalStyle.module.css";
5 | import GenericList from "./GenericList";
6 | import PureSection from "./PureSection";
7 | import TeamMemberList from "./TeamMemberList";
8 |
9 | const TeamInfoPure = (props) => {
10 | const {teamInfo} = props;
11 | return (
12 |
13 |
14 |
15 | { teamInfo.desc ? <>{teamInfo.desc}> : <>> }
16 |
17 |
18 |
19 |
24 |
25 |
26 | {
27 | (teamInfo.skills && teamInfo.skills.length) ?
28 |
29 | :
30 | No Skills Listed
31 | }
32 |
33 |
34 | {
35 | (teamInfo.prizes && teamInfo.prizes.length) ?
36 |
37 | :
38 | No Prizes Listed
39 | }
40 |
41 |
42 |
43 |
44 | );
45 | };
46 |
47 | TeamInfoPure.propTypes = {
48 | teamInfo : PropTypes.shape({
49 | members : PropTypes.arrayOf(PropTypes.shape({
50 | user_id : PropTypes.string.isRequired,
51 | seriousness : PropTypes.number.isRequired,
52 | bio : PropTypes.string.isRequired,
53 | })).isRequired,
54 | skills : PropTypes.arrayOf(PropTypes.string),
55 | prizes : PropTypes.arrayOf(PropTypes.string),
56 | desc : PropTypes.string,
57 | }).isRequired,
58 | };
59 |
60 | export default TeamInfoPure;
--------------------------------------------------------------------------------
/src/library/AuthForm.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Alert } from "reactstrap";
3 | import { Grid } from "@material-ui/core";
4 | import { RingLoader } from "react-spinners";
5 | import PropTypes from "prop-types";
6 |
7 | /*
8 | The basic form that authorization pages (sign up, log in, forgot password) use
9 |
10 | Props:
11 | - children: the body of the form itself
12 | - errors: a list of possible errors when communicating with the backend
13 | - label: indicate what the user should do
14 | - loading: if the form is in a loading state, and should show a spinner
15 | - isMobile: adjust the column widths for a mobile display
16 | - onSubmit: the actual function of the form
17 | - title: the form title
18 | */
19 | const AuthForm = ({ children, errors, label, loading, isMobile, onSubmit, title }) => (
20 |
26 | { isMobile ? null : }
27 |
32 |
33 |
{ title }
34 |
{loading ? label: ""}
35 |
41 |
42 |
43 | { isMobile ? null : }
44 |
45 | );
46 |
47 | AuthForm.propTypes = {
48 | children: PropTypes.node,
49 | errors: PropTypes.array,
50 | label: PropTypes.string,
51 | loading: PropTypes.bool,
52 | isMobile: PropTypes.bool,
53 | onSubmit: PropTypes.func,
54 | title: PropTypes.string,
55 | };
56 |
57 | const renderSpinner = () => (
58 |
60 |
61 |
62 | );
63 |
64 | const renderErrors = (errors) => (
65 | errors !== ""
66 | ? (
69 | {errors}
70 | )
71 | : null
72 | );
73 |
74 | export default AuthForm;
75 |
--------------------------------------------------------------------------------
/src/components/Landing/Sections/Stats.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Grid } from "@material-ui/core";
3 | import { theme } from "../../../Defaults";
4 | import { Icon } from "react-fa";
5 | import CountUp from "react-countup";
6 | import PropTypes from "prop-types";
7 | import Card from "../../Card";
8 |
9 | function Stats(){
10 | return(
11 |
12 |
16 |
18 |
24 |
25 |
27 |
33 |
34 |
36 |
42 |
43 |
44 |
45 | );
46 |
47 | }
48 |
49 | const Stat = ({ number, text, back, accent, icon, decoration }) => (
50 |
51 | {/*
*/}
52 |
53 |
54 |
55 | {decoration}
56 |
59 | +
60 |
61 | {text}
62 |
63 |
65 |
66 |
67 | );
68 |
69 | Stat.propTypes = {
70 | number: PropTypes.string,
71 | text: PropTypes.string,
72 | back: PropTypes.string,
73 | accent: PropTypes.string,
74 | icon: PropTypes.string,
75 | decoration: PropTypes.string
76 | };
77 |
78 | export default Stats;
79 |
--------------------------------------------------------------------------------
/public/assets/icons/hru-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/components/Sponsorship/Sections/AboutSponsorship.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import PropTypes from "prop-types";
3 |
4 | class AboutSponsorship extends Component {
5 | render() {
6 | if (!this.props.isMobile) {
7 | return (
8 |
9 |
About HackRU
10 |
11 |
What is HackRU?
12 |
HackRU is a 24-hour hackathon at Rutgers University. We welcome hundreds of students to join us in building awesome software and hardware projects. Industry experts and mentors come from all over the country to create an environment that fosters an atmosphere of learning through tech talks and one-on-one guidance. We encourage beginner and advanced hackers alike to challenge themselves and expand their skills. You can learn more about HackRU by reading our articles on medium!
13 |
Why sponsor?
14 |
Sponsoring HackRU is the most powerful recruiting effort you can make for engaging with upcoming tech talent at both Rutgers University and the tech scene at large. The hackathon audience is made up of the industry's most passionate developers, entrepreneurs, and designers. Your representatives will interact directly with these talented potential hires.
15 |
16 |
17 | );
18 | } else{
19 | return (
20 |
21 |
About HackRU
22 |
23 |
What is HackRU?
24 |
HackRU is a 24-hour hackathon at Rutgers University. We welcome hundreds of students to join us in building awesome software and hardware projects. Industry experts and mentors come from all over the country to create an environment that fosters an atmosphere of learning through tech talks and one-on-one guidance. We encourage beginner and advanced hackers alike to challenge themselves and expand their skills. You can learn more about HackRU by reading our articles on medium!
25 |
Why sponsor?
26 |
Sponsoring HackRU is the most powerful recruiting effort you can make for engaging with upcoming tech talent at both Rutgers University and the tech scene at large. The hackathon audience is made up of the industry's most passionate developers, entrepreneurs, and designers. Your representatives will interact directly with these talented potential hires.
27 |
28 |
29 | );
30 | }
31 | }
32 | }
33 |
34 | AboutSponsorship.propTypes = {
35 | isMobile: PropTypes.bool,
36 | };
37 | export default AboutSponsorship;
38 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/library/AuthForm.jsx:
--------------------------------------------------------------------------------
1 | // import React from "react";
2 | // import { Alert } from "reactstrap";
3 | // import { Grid } from "@material-ui/core";
4 | // import { RingLoader } from "react-spinners";
5 | // import { theme } from "../../Default.js";
6 | // import PropTypes from "prop-types";
7 |
8 | // /*
9 | // The basic form that authorization pages (sign up, log in, forgot password) use
10 |
11 | // Props:
12 | // - children: the body of the form itself
13 | // - errors: a list of possible errors when communicating with the backend
14 | // - label: indicate what the user should do
15 | // - loading: if the form is in a loading state, and should show a spinner
16 | // - isMobile: adjust the column widths for a mobile display
17 | // - onSubmit: the actual function of the form
18 | // - title: the form title
19 | // */
20 | // const AuthForm = ({ children, errors, label, loading, isMobile, onSubmit, title }) => (
21 | //
27 | // { isMobile ? null : }
28 | //
32 | //
33 | //
{ title }
34 | //
{loading ? label: ""}
35 | //
41 | //
42 | //
43 | // { isMobile ? null : }
44 | //
45 | // );
46 |
47 | // AuthForm.propTypes = {
48 | // children: PropTypes.node,
49 | // errors: PropTypes.array,
50 | // label: PropTypes.string,
51 | // loading: PropTypes.bool,
52 | // isMobile: PropTypes.bool,
53 | // onSubmit: PropTypes.func,
54 | // title: PropTypes.string,
55 | // };
56 |
57 | // const renderSpinner = () => (
58 | //
60 | //
61 | //
62 | // );
63 |
64 | // const renderErrors = (errors) => (
65 | // errors !== ""
66 | // ? (
69 | // {errors}
70 | // )
71 | // : null
72 | // );
73 |
74 | // export default AuthForm;
75 |
--------------------------------------------------------------------------------
/src/components/Projector/Countdown.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import AnimatedGrid, { BITMAP, N } from "../AnimatedGrid";
3 | class Countdown extends Component {
4 | constructor() {
5 | super();
6 | this.getTimeString = this.getTimeString.bind(this);
7 | this.generateTemplate = this.generateTemplate.bind(this);
8 | }
9 | UNSAFE_componentWillMount() {
10 | // Ends 20th October 2019, at 11:30
11 | // JAN = 0
12 | let end = new Date(2019, 9, 20, 12, 0, 0, 0);
13 | this.oldMin = -1;
14 | this.setState({
15 | end: end,
16 | template: this.generateTemplate(this.getTimeString(end))
17 | });
18 | setInterval(() => {
19 | this.setState({
20 | template: this.generateTemplate(this.getTimeString(this.state.end))
21 | });
22 | }, 1000);
23 | }
24 | getTimeString(end) {
25 | let now = new Date();
26 | let distance = end - now;
27 | let days = Math.floor(distance / (1000 * 60 * 60 * 24));
28 | let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)) + (24 * days);
29 | let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
30 | let seconds = Math.floor((distance % (1000 * 60)) / 1000);
31 | if (hours < 0) {
32 | hours = 0;
33 | }
34 | if (minutes < 0) {
35 | minutes = 0;
36 | }
37 | if (seconds < 0) {
38 | seconds = 0;
39 | }
40 | hours = hours + "";
41 | if (hours.length === 1) {
42 | hours = "0" + hours;
43 | }
44 | if (seconds !== this.oldMin) {
45 | if (this.oldMin !== -1 && seconds === 2) {
46 | this.refs.grid.animate();
47 | }
48 | this.oldMin = seconds;
49 | }
50 | minutes = minutes + "";
51 | if (minutes.length === 1) {
52 | minutes = "0" + minutes;
53 | }
54 | seconds = seconds + "";
55 | if (seconds.length === 1) {
56 | seconds = "0" + seconds;
57 | }
58 | return hours + ":" + minutes + ":" + seconds;
59 | }
60 | generateTemplate(str) {
61 | let template = [];
62 | for (let i = 0; i < 10; i++) {
63 | template.push([]);
64 | }
65 | for (let i = 0; i < str.length; i++) {
66 | let BIT = BITMAP[str.charAt(i)];
67 | for (let j = 0; j < BIT.length; j++) {
68 | template[j].push(...BIT[j]);
69 | template[j].push(N);
70 | }
71 | }
72 | return template;
73 | }
74 | render() {
75 | return (
76 |
83 | );
84 | }
85 | }
86 | export default Countdown;
87 |
--------------------------------------------------------------------------------
/src/components/_Landing/sections/hero/MainHeroContent.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import SocialMediaComponent from "../../global_components/SocialMediaComponent";
4 |
5 | function LoginAndRegister(props: { isLoggedIn: boolean, registrationOpen: true, }) {
6 | const { isLoggedIn, registrationOpen } = props;
7 | return (
8 |
9 |
11 | {!isLoggedIn && Log In}
12 | {isLoggedIn && Dashboard}
13 |
14 |
16 | {!isLoggedIn && registrationOpen && Sign Up}
17 | {!isLoggedIn && !registrationOpen && Registration Closed }
18 | {isLoggedIn && Sign out}
19 |
20 |
21 | );
22 | }
23 |
24 | function HeroTitle() {
25 | return (
26 |
27 |
28 |
29 | HACKRU
30 |
31 |
32 |
33 | Hack All Knight
34 |
35 |
36 |
37 | Fall 2023 ● Oct 7-8
38 |
39 |
40 |
41 | );
42 | }
43 |
44 | function CenterContent({ isLoggedIn }: { isLoggedIn: boolean }) {
45 | return (
46 |
49 |
50 |
51 |
55 |
56 |
57 |
58 | );
59 | }
60 |
61 |
62 | export default CenterContent;
63 |
64 |
--------------------------------------------------------------------------------
/src/components/Projector/Projector.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Container, Row, Col } from "reactstrap";
3 | import Announcements from "../Live/Announcements";
4 | import { theme } from "../../Defaults.js";
5 | import Countdown from "./Countdown";
6 | import Schedule from "../Live/Schedule";
7 | import PropTypes from "prop-types";
8 |
9 | const Projector = () => (
10 |
13 |
15 |
16 |
17 |
18 |
19 | HackRU Ends in
20 |
22 |
23 |
24 |
25 |
27 | #HackAllKnight
28 | #HackRUF19
29 |
30 |
31 |
32 |
33 | Announcements
34 |
35 |
36 |
37 | Up Next
38 |
39 |
40 |
41 |
42 |
43 | Helpful Links
44 |
47 |
50 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | );
60 |
61 | const ProjectorLink = ({ label, target }) => (
62 |
63 | );
64 |
65 | ProjectorLink.propTypes = {
66 | label: PropTypes.string,
67 | target: PropTypes.string,
68 | };
69 |
70 | export default Projector;
71 |
--------------------------------------------------------------------------------
/src/FlyingLogo.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import PropTypes from "prop-types";
3 |
4 | /**
5 | * Alien Background Component
6 | */
7 | class FlyingLogo extends Component {
8 | constructor(props) {
9 | super(props);
10 | this._event_onResize = this._event_onResize.bind(this);
11 | this._event_onInitializeRenderer = this._event_onInitializeRenderer.bind(this);
12 | this._event_onRender = this._event_onRender.bind(this);
13 | this._event_onUpdate = this._event_onUpdate.bind(this);
14 | this.image = new Image();
15 | this.image.onload = this._event_onInitializeRenderer;
16 | this.image.src = props.url;
17 | }
18 | _event_onResize() {
19 | if (this.canvas) {
20 | this.canvas.width = window.innerWidth;
21 | this.canvas.height = window.innerHeight;
22 | }
23 | }
24 | _event_onInitializeRenderer() {
25 | this.logos = [];
26 | this.canvas = document.getElementById("drawable");
27 | window.addEventListener("resize", this._event_onResize);
28 | this._event_onResize();
29 | this.context = this.canvas.getContext("2d");
30 | this.maxCount = 500;
31 | this.counter = this.maxCount;
32 | setInterval(this._event_onUpdate, 2);
33 | setInterval(this._event_onRender, 2);
34 | }
35 | _event_onUpdate() {
36 | this.counter--;
37 | if (this.counter <= 0) {
38 | let size = Math.floor(Math.random() * 50) + 50;
39 | if (this.logos.length < 3) {
40 | this.logos.push({
41 | x: Math.floor(Math.random() * this.canvas.width) - (size / 2),
42 | y: this.canvas.height,
43 | width: size,
44 | height: size,
45 | speed: Math.floor(Math.random() * 2) + 1
46 | });
47 | }
48 | this.counter = this.maxCount;
49 | }
50 | for (let i = 0; i < this.logos.length; i++) {
51 | let alien = this.logos[i];
52 | alien.y -= alien.speed;
53 | if (alien.y < -400) {
54 | this.logos.splice(i, 1);
55 | i--;
56 | }
57 | }
58 | }
59 | _event_onRender() {
60 | if (this.context && this.context.clearRect && this.canvas) {
61 | this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
62 | for (let i = 0; i < this.logos.length; i++) {
63 | let alien = this.logos[i];
64 | this.context.drawImage(this.image, alien.x, alien.y, alien.width, alien.height);
65 | }
66 | } else {
67 | this.canvas = document.getElementById("drawable");
68 | this.context = this.canvas.getContext("2d");
69 | }
70 | }
71 | render() {
72 | return (
73 |
74 |
75 | );
76 | }
77 | }
78 |
79 | FlyingLogo.propTypes = {
80 | url: PropTypes.string,
81 | };
82 |
83 | export default FlyingLogo;
84 |
--------------------------------------------------------------------------------
/src/components/Landing/Sections/Logo.jsx:
--------------------------------------------------------------------------------
1 |
2 | import React, { Component } from "react";
3 | import { Container, Grid} from "@material-ui/core";
4 | import { theme } from "../../../Defaults";
5 | import anime from "animejs";
6 | import PropTypes from "prop-types";
7 |
8 | /**
9 | * Home component for the landing page
10 | */
11 | class Logo extends Component {
12 | constructor(props) {
13 | super(props);
14 | fetch(this.props.src).then((response) => {
15 | response.text().then((text) => {
16 | this.setState({
17 | file: text
18 | }, () => {
19 | anime({
20 | targets: "path",
21 | strokeDashoffset: (el) => {
22 | let pathLength = 0;
23 | if (el.getTotalLength) {
24 | pathLength = el.getTotalLength();
25 | el.setAttribute("stroke-dasharray", pathLength);
26 | }
27 | return [pathLength, 0];
28 | },
29 | easing: "easeInOutExpo",
30 | duration: (el) => {
31 | let defaultVal = 1000;
32 | let cns = el.className.baseVal.split(" ");
33 | for (let i = 0; i < cns.length; i++) {
34 | if (cns[i].includes("idx-")) {
35 | let idx = parseInt(cns[i].replace("idx-", ""));
36 | return idx * defaultVal;
37 | }
38 | }
39 | return defaultVal;
40 | },
41 | direction: "alternate",
42 | delay: () => { return 500; },
43 | loop: props.repeat === null ? true : props.repeat,
44 | begin: function(anim) {
45 | anime.remove(anim.targets);
46 | }
47 | });
48 | });
49 | });
50 | });
51 | }
52 | UNSAFE_componentWillMount() {
53 | this.setState({
54 | file: "",
55 | });
56 | }
57 | render() {
58 | return (
59 |
62 |
63 |
65 |
66 |
67 | );
68 | }
69 | }
70 |
71 | Logo.propTypes = {
72 | src: PropTypes.string,
73 | noCircle: PropTypes.bool,
74 | repeat: PropTypes.bool,
75 | style: PropTypes.object,
76 | color: PropTypes.string
77 | };
78 |
79 | export default Logo;
80 |
--------------------------------------------------------------------------------
/src/components/Sponsorship/Sponsorship.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Container, Row } from "reactstrap";
3 | import Main from "./Sections/Main";
4 | import { ParallaxProvider } from "react-scroll-parallax";
5 | import { theme } from "../../Defaults";
6 | import { sponsorshipLinks } from "./SponsorshipConfig";
7 | import ScrollableAnchor from "react-scrollable-anchor";
8 | import PropTypes from "prop-types";
9 |
10 | class SponsorshipPage extends Component {
11 | render() {
12 | let sectionClasses = "col-lg-10 offset-lg-1 col-xs-12 offset-xs-0 skew-left color-priority";
13 | let rows = [];
14 | let keys = Object.keys(sponsorshipLinks);
15 | for (let i = 0; i < keys.length; i++) {
16 | if (sponsorshipLinks[keys[i]].enabled) {
17 | let url = sponsorshipLinks[keys[i]].url.substring(1);
18 | let component = sponsorshipLinks[keys[i]].component({ isMobile: this.props.isMobile });
19 | // Toggle the green skewed sections
20 | let className = "";
21 | if (i !== keys.length - 1) {
22 | className = "bg-no-gradient skew-right";
23 | if (i % 2 === 0) {
24 | className = "bg-gradient-right skew-right";
25 | }
26 | } else {
27 | sectionClasses = "col-lg-12 offset-lg-0 col-xs-12 offset-xs-0 color-priority";
28 | }
29 | let style = {};
30 | if (sponsorshipLinks[keys[i]].fullHeight) {
31 | style["minHeight"] = "100vh";
32 | }
33 | rows.push((
34 |
36 |
37 |
39 |
40 |
41 | {component}
42 |
43 |
44 |
45 |
46 |
47 | ));
48 | }
49 | }
50 | return (
51 |
66 | );
67 | }
68 | }
69 |
70 | SponsorshipPage.propTypes = {
71 | isMobile: PropTypes.bool,
72 | };
73 |
74 | export default SponsorshipPage;
75 |
--------------------------------------------------------------------------------
/src/components/Landing/Sections/Sponsors/LogoWrapper.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import SponsorContainer from "./SponsorContainer.jsx";
3 | import PropTypes from "prop-types";
4 | import { BarLoader } from "react-spinners";
5 | /**
6 | * Sponsors component for the landing page
7 | */
8 | class LogoWrapper extends Component {
9 | state = {
10 | loading: "Our latest sponsorship information is loading",
11 | logos: null,
12 | }
13 | constructor(props) {
14 | super(props);
15 | fetch(props.endpoint, {
16 | method: "GET",
17 | mode: "cors"
18 | }).then(response => response.json()).then(data => {
19 | this.setState({
20 | logos: data
21 | });
22 | });
23 | }
24 | render() {
25 | let renderList = [];
26 | let childCount = 0;
27 | if (this.state.logos) {
28 | for (let i = 0; i < this.state.logos.sections.length; i++) {
29 | childCount += this.state.logos.sections[i].children.length;
30 | }
31 | let SponsorDeclaration = this.state.logos.sections;
32 | for (let i = 0; i < SponsorDeclaration.length; i++) {
33 | if (SponsorDeclaration[i]["enabled"]) {
34 | renderList.push(
35 |
40 | );
41 | }
42 | }
43 | }
44 | if (childCount > 0) {
45 | return (
46 |
47 |
48 |
{this.props.title}
50 | {renderList}
51 |
52 |
53 | );
54 | } else if (!this.state.logos) {
55 | return (
56 |
57 |
{this.props.title}
58 | {this.state.loading}
59 |
60 |
61 | );
62 | } else {
63 | return (
64 |
65 |
66 |
{this.props.title}
68 |
To be announced, check again later!
70 |
71 |
72 | );
73 | }
74 | }
75 | }
76 |
77 | LogoWrapper.propTypes = {
78 | isMobile: PropTypes.bool,
79 | endpoint: PropTypes.string,
80 | baseURL: PropTypes.string,
81 | title: PropTypes.string
82 | };
83 |
84 | export default LogoWrapper;
85 |
--------------------------------------------------------------------------------
/src/components/Landing/Sections/Sponsors/sponsors.json:
--------------------------------------------------------------------------------
1 | {
2 | "sections": [
3 | {
4 | "name": "TITLE",
5 | "color": "sponsors-title-color",
6 | "enabled": false,
7 | "size": {
8 | "width": 1000,
9 | "height": 1000
10 | },
11 | "root": "title/",
12 | "children": []
13 | },
14 | {
15 | "name": "PLATINUM",
16 | "color": "sponsors-platinum-color",
17 | "enabled": false,
18 | "size": {
19 | "width": 800,
20 | "height": 800
21 | },
22 | "root": "platinum/",
23 | "children": []
24 | },
25 | {
26 | "name": "GOLD",
27 | "color": "sponsors-gold-color",
28 | "enabled": false,
29 | "size": {
30 | "width": 600,
31 | "height": 600
32 | },
33 | "root": "gold/",
34 | "children": []
35 | },
36 | {
37 | "name": "SILVER",
38 | "color": "sponsors-silver-color",
39 | "enabled": true,
40 | "size": {
41 | "width": 300,
42 | "height": 300
43 | },
44 | "root": "silver/",
45 | "children": [
46 | {
47 | "name": "iCIMS",
48 | "image": "icims.png",
49 | "url": "https://www.icims.com/"
50 | },
51 | {
52 | "name": "Siemens",
53 | "image": "Siemens.png",
54 | "url": "https://www.siemens.com/us/en/home.html"
55 | },
56 | {
57 | "name": "Twilio",
58 | "image": "twilio.png",
59 | "url": "https://www.twilio.com/"
60 | },
61 | {
62 | "name": "iCIMS",
63 | "image": "icims.png",
64 | "url": "https://www.icims.com/"
65 | },
66 | {
67 | "name": "Siemens",
68 | "image": "Siemens.png",
69 | "url": "https://www.siemens.com/us/en/home.html"
70 | },
71 | {
72 | "name": "Twilio",
73 | "image": "twilio.png",
74 | "url": "https://www.twilio.com/"
75 | }
76 | ]
77 | },
78 | {
79 | "name": "BRONZE",
80 | "color": "sponsors-bronze-color",
81 | "enabled": true,
82 | "size": {
83 | "width": 200,
84 | "height": 200
85 | },
86 | "root": "/bronze/",
87 | "children": [
88 | {
89 | "name": "Two Six Labs",
90 | "image": "twosixlabs.png",
91 | "url": "https://www.twosixlabs.com/"
92 | },
93 | {
94 | "name": "Linode",
95 | "image": "linode.png",
96 | "url": "https://www.linode.com/"
97 | }
98 | ]
99 | }
100 | ]
101 | }
--------------------------------------------------------------------------------
/src/hooks/useDebounce/useDebounce.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | /* eslint-disable no-unused-vars */
3 | import { renderHook, cleanup } from "@testing-library/react-hooks";
4 | import useDebounce from "./usDebounce";
5 |
6 | describe("useDebounce", () => {
7 | let fun = () => {};
8 | beforeEach(() => {
9 | jest.useFakeTimers();
10 | fun = jest.fn();
11 | });
12 | afterEach(() => {
13 | fun = () => {};
14 | });
15 | test("deBouncedFn immediate = true runs function immediately", () => {
16 | const {result, rerender} = renderHook(() => useDebounce(fun, 100));
17 | const deBouncedFn = result.current.deBouncedFn;
18 | deBouncedFn();
19 | expect(fun).toHaveBeenCalledTimes(1);
20 | jest.advanceTimersByTime(101);
21 | expect(fun).toHaveBeenCalledTimes(1);
22 | });
23 | test("deBouncedFn immediate = false runs function later", () => {
24 | const {result, rerender} = renderHook(() => useDebounce(fun, 100, false));
25 | const deBouncedFn = result.current.deBouncedFn;
26 | deBouncedFn();
27 | expect(fun).toHaveBeenCalledTimes(0);
28 | jest.advanceTimersByTime(101);
29 | expect(fun).toHaveBeenCalledTimes(1);
30 | });
31 | test("both immediate = true and immediate = false ensure timer null upon run of internal function later()", () => {
32 | const {result : immediateResult} = renderHook(() => useDebounce(fun, 100));
33 | const {result : laterResult} = renderHook(() => useDebounce(fun, 100, false));
34 | immediateResult.current.deBouncedFn();
35 | laterResult.current.deBouncedFn();
36 | expect(immediateResult.current.timer.current).toBeTruthy();
37 | expect(laterResult.current.timer.current).toBeTruthy();
38 | jest.advanceTimersByTime(101);
39 | expect(immediateResult.current.timer.current).toBeFalsy();
40 | expect(laterResult.current.timer.current).toBeFalsy();
41 | });
42 | test("deBouncedFn called only once since lenient = false", () => {
43 | const {result, rerender} = renderHook(() => useDebounce(fun, 100));
44 | const deBouncedFn = result.current.deBouncedFn;
45 | deBouncedFn();
46 | expect(fun).toHaveBeenCalledTimes(1);
47 | jest.advanceTimersByTime(50);
48 | deBouncedFn();
49 | expect(fun).toHaveBeenCalledTimes(1);
50 | jest.advanceTimersByTime(50);
51 | deBouncedFn();
52 | expect(fun).toHaveBeenCalledTimes(1);
53 | });
54 | test("deBouncedFn called three times for lenient = true, i.e. does not penalize repeated calls and only throttles to ensure distance between last function run and current function run", () => {
55 | const {result, rerender} = renderHook(() => useDebounce(fun, 100, true, true));
56 | const deBouncedFn = result.current.deBouncedFn;
57 | deBouncedFn();
58 | expect(fun).toHaveBeenCalledTimes(1);
59 | jest.advanceTimersByTime(51);
60 | deBouncedFn();
61 | expect(fun).toHaveBeenCalledTimes(1);
62 | jest.advanceTimersByTime(51);
63 | deBouncedFn();
64 | expect(fun).toHaveBeenCalledTimes(2);
65 | jest.advanceTimersByTime(51);
66 | deBouncedFn();
67 | expect(fun).toHaveBeenCalledTimes(2);
68 | jest.advanceTimersByTime(51);
69 | deBouncedFn();
70 | expect(fun).toHaveBeenCalledTimes(3);
71 | });
72 | });
--------------------------------------------------------------------------------
/src/components/_Landing/sections/hero/hero.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable indent */
2 | import React from "react";
3 | import MainHeroContent from "./MainHeroContent";
4 | import "./hero.css";
5 | import Navbar from "./Navbar";
6 | import rabbit from "../../assets/animals/whale.png";
7 | import secondaryWhale from "../../assets/animals/little-whale.png";
8 | import cloud from "../../assets/clouds/cloud1.png";
9 | import cloud2 from "../../assets/clouds/cloud2.png";
10 | import cloud4 from "../../assets/clouds/cloud4.png";
11 | import cloudWhale from "../../assets/animals/cloud-whale.png";
12 | import { Profile } from "../../../Profile";
13 |
14 | function Rabbit() {
15 | return (
16 |
18 |
20 |
21 | );
22 | }
23 |
24 | function SecondaryWhale() {
25 | return (
26 |
28 |
30 |
31 | );
32 | }
33 |
34 | function Hero(props: { profile: Profile }) {
35 | const { isLoggedIn } = props.profile;
36 |
37 |
38 | return (
39 |
50 |
51 |
52 |
53 |
54 |
55 |
62 |
64 |
65 |
66 |
70 |
72 |
73 |
77 |
79 |
80 |
81 |
85 |
87 |
88 |
89 | );
90 | }
91 |
92 | Hero.prototypes = {
93 | config: null
94 | };
95 |
96 | export default Hero;
97 |
--------------------------------------------------------------------------------
/public/assets/icons/hru-logo-green.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
16 |
17 |
18 |
30 |
31 |
32 |
34 |
36 |
39 |
41 |
44 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/public/assets/icons/hru-logo-white.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
16 |
17 |
18 |
30 |
31 |
32 |
34 |
36 |
39 |
41 |
44 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hackru-frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@devexpress/dx-react-core": "^2.7.2",
7 | "@devexpress/dx-react-scheduler": "^2.7.2",
8 | "@devexpress/dx-react-scheduler-material-ui": "^2.7.2",
9 | "@emotion/react": "^11.10.5",
10 | "@emotion/styled": "^11.10.5",
11 | "@headlessui/react": "^1.7.7",
12 | "@material-ui/core": "^4.11.0",
13 | "@material-ui/icons": "^4.9.1",
14 | "@material-ui/lab": "^4.0.0-alpha.56",
15 | "@material-ui/utils": "^4.10.2",
16 | "@mui/material": "^5.11.5",
17 | "animejs": "^3.0.0",
18 | "autoprefixer": "^10.4.13",
19 | "availity-reactstrap-validation": "^2.5.0",
20 | "axios": "^0.21.1",
21 | "bootstrap": "^4.1.3",
22 | "chart.js": "^2.9.4",
23 | "font-awesome": "^4.7.0",
24 | "gsap": "^2.1.3",
25 | "material-ui-chip-input": "^1.1.0",
26 | "parallax-js": "^3.1.0",
27 | "qrcode.react": "^0.9.3",
28 | "react": "^16.6.3",
29 | "react-anime": "^3.0.3",
30 | "react-chartjs-2": "^2.7.4",
31 | "react-cookies": "^0.1.0",
32 | "react-countup": "^4.3.3",
33 | "react-dependent-script": "^1.1.0",
34 | "react-dom": "^16.6.3",
35 | "react-fa": "^5.0.0",
36 | "react-google-autocomplete": "^1.0.18",
37 | "react-icons": "^4.7.1",
38 | "react-motion": "^0.5.2",
39 | "react-particles": "^2.8.0",
40 | "react-router-dom": "^5.3.0",
41 | "react-scripts": "^3.4.3",
42 | "react-scroll-parallax": "^1.3.5",
43 | "react-scrollable-anchor": "^0.6.1",
44 | "react-select": "^2.1.2",
45 | "react-select-country-list": "^2.2.3",
46 | "react-spinners": "^0.9.0",
47 | "react-toggle": "^4.1.1",
48 | "react-window": "^1.8.5",
49 | "reactstrap": "^6.5.0",
50 | "request": "^2.88.0",
51 | "tailwindcss": "^3.2.4",
52 | "tsparticles": "^2.8.0",
53 | "typescript": "^4.9.0"
54 | },
55 | "scripts": {
56 | "tailwind-watch": "npx tailwindcss -i ./src/index.css -o ./public/tailwind-output-f23.css --watch",
57 | "start": "env-cmd development react-scripts start",
58 | "build-dev": "env-cmd build-dev react-scripts build",
59 | "build-prod": "env-cmd build-prod react-scripts build",
60 | "test": "react-scripts test",
61 | "eject": "react-scripts eject",
62 | "lint": "eslint \"src/**\"",
63 | "lint-fix": "eslint \"src/**\" --fix"
64 | },
65 | "eslintConfig": {
66 | "extends": "react-app"
67 | },
68 | "browserslist": [
69 | ">0.2%",
70 | "not dead",
71 | "not ie <= 11",
72 | "not op_mini all"
73 | ],
74 | "devDependencies": {
75 | "@testing-library/jest-dom": "^5.14.1",
76 | "@testing-library/react": "^12.0.0",
77 | "@testing-library/react-hooks": "^7.0.2",
78 | "@testing-library/user-event": "^13.2.1",
79 | "@types/react-router-dom": "^5.3.3",
80 | "babel-core": "^6.26.3",
81 | "babel-eslint": "^10.0.0",
82 | "env-cmd": "^8.0.2",
83 | "eslint": "^6.0.0",
84 | "eslint-config-standard": "^11.0.0",
85 | "eslint-config-standard-react": "^6.0.0",
86 | "eslint-plugin-import": "^2.13.0",
87 | "eslint-plugin-node": "^7.0.1",
88 | "eslint-plugin-promise": "^4.0.0",
89 | "eslint-plugin-react": "^7.10.0",
90 | "eslint-plugin-standard": "^3.1.0",
91 | "jest": "^24.9.0",
92 | "prettier": "^1.18.2",
93 | "react-test-renderer": "^17.0.2"
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/components/Landing/Sections/Sponsors/CarouselContainer.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { theme } from "../../../../Defaults.js";
3 | import { Container, Row, Col, Carousel, CarouselItem, CarouselIndicators } from "reactstrap";
4 | import PropTypes from "prop-types";
5 |
6 | class CarouselContainer extends Component {
7 | constructor(props) {
8 | super(props);
9 | console.log(this.props.declaration);
10 | this.state = {
11 | activeIndex: 0,
12 | animating: false
13 | };
14 | }
15 |
16 | next = () => {
17 | if (this.animating) return;
18 | const nextIndex = this.state.activeIndex === this.props.declaration.children.length - 1 ? 0 : this.state.activeIndex + 1;
19 | this.setState({
20 | activeIndex: nextIndex
21 | });
22 | }
23 |
24 | previous = () => {
25 | if (this.animating) return;
26 | const nextIndex = this.state.activeIndex === 0 ? this.props.declaration.children.length - 1 : this.state.activeIndex - 1;
27 | this.setState({
28 | activeIndex: nextIndex
29 | });
30 | }
31 |
32 | goToIndex = (index) => {
33 | if (this.animating) return;
34 | this.setState({
35 | activeIndex: index
36 | });
37 | }
38 |
39 | render() {
40 | let { declaration } = this.props;
41 | let sponsors = [];
42 | for (let i = 0; i < declaration.children.length; i++) {
43 | //console.log(declaration.baseURL);
44 | sponsors.push(
45 | this.setState({ animating:true })}
47 | onExited={() => this.setState({ animating:false })}
48 | key={i}>
49 |
50 |
54 |
55 | );
56 | }
57 | return (
58 |
60 | { this.props.showName &&
61 |
63 |
64 |
66 | {declaration.name}
67 |
68 |
69 |
}
70 |
75 |
78 | {sponsors}
79 |
80 |
81 | );
82 | }
83 | }
84 |
85 | CarouselContainer.propTypes = {
86 | declaration: PropTypes.object,
87 | baseURL: PropTypes.string,
88 | showName: PropTypes.bool,
89 | name: PropTypes.string
90 | };
91 |
92 | export default CarouselContainer;
93 |
--------------------------------------------------------------------------------
/public/assets/background/circle-dotted_white.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
25 |
26 |
27 |
28 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
51 |
53 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/public/assets/background/target_red.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
25 |
26 |
27 |
28 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
51 |
53 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------