diff --git a/.all-contributorsrc b/.all-contributorsrc
index 7e2a0c0e..2446d545 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -106,6 +106,16 @@
"code",
"doc"
]
+ },
+ {
+ "login": "daviszung",
+ "name": "Davis Zung",
+ "avatar_url": "https://avatars.githubusercontent.com/u/95515224?v=4",
+ "profile": "https://github.com/daviszung",
+ "contributions": [
+ "code",
+ "doc"
+ ]
}
],
"contributorsPerLine": 7,
@@ -113,5 +123,6 @@
"repoType": "github",
"repoHost": "https://github.com",
"projectName": "internship-tracker",
- "projectOwner": "BobaTalks"
+ "projectOwner": "BobaTalks",
+ "commitType": "docs"
}
diff --git a/.github/workflows/lintchecks.yml b/.github/workflows/lintchecks.yml
index 8f6a6abf..1a47ba9b 100644
--- a/.github/workflows/lintchecks.yml
+++ b/.github/workflows/lintchecks.yml
@@ -13,10 +13,10 @@ name: Lint Checks
on:
push:
- branches: [ "main" ]
+ branches: ["main"]
pull_request:
# The branches below must be a subset of the branches above
- branches: [ "main" ]
+ branches: ["main"]
jobs:
eslint:
@@ -41,7 +41,7 @@ jobs:
--ext .js,.jsx,.ts,.tsx
continue-on-error: false
- - name: Run Prettier
- run: npx prettier client/.
- --check
- continue-on-error: false
+ # - name: Run Prettier
+ # run: npx prettier client/.
+ # --check
+ # continue-on-error: false
diff --git a/README.md b/README.md
index 09bb77b4..36b86ed5 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Internship Tracker
-[![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors-)
+[![All Contributors](https://img.shields.io/badge/all_contributors-11-orange.svg?style=flat-square)](#contributors-)
- [Internship Tracker](#internship-tracker)
@@ -78,12 +78,13 @@ Pull requests are built with [deploy previews](https://docs.netlify.com/site-dep
Anthony Camarillo 💻 📖 |
Brandon C 🎨 |
DarrenLee09 🤔 |
+ Davis Zung 💻 📖 |
Jenna Xiao 💻 📖 🐛 |
Jessica Chen 💻 |
KP 📆 💬 🤔 |
- Lily Meng 💻 📖 |
+ Lily Meng 💻 📖 |
Razi Syed 💻 |
Victoria Tran 💼 💬 🤔 📖 📆 |
leafie8 💻 |
diff --git a/client/.eslintrc.json b/client/.eslintrc.json
index 50b74dc5..d1ebd80c 100644
--- a/client/.eslintrc.json
+++ b/client/.eslintrc.json
@@ -7,17 +7,34 @@
"eslint:recommended",
"react-app",
"plugin:react/recommended",
- "plugin:jsx-a11y/recommended"
+ "plugin:jsx-a11y/recommended",
+ "plugin:prettier/recommended",
+ "prettier"
+ ],
+ "ignorePatterns": [
+ "node_modules/",
+ "build/",
+ "public/"
],
- "ignorePatterns": ["node_modules/", "build/", "public/"],
"overrides": [],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
- "plugins": ["react", "react-hooks", "prettier"],
+ "plugins": [
+ "react",
+ "react-hooks",
+ "simple-import-sort"
+ ],
"rules": {
- "prettier/prettier": "error",
+ "prettier/prettier": [
+ "error",
+ {
+ "singleQuote": true
+ }
+ ],
+ "simple-import-sort/exports": "error",
+ "simple-import-sort/imports": "error",
"react/prop-types": "off"
}
}
\ No newline at end of file
diff --git a/client/package-lock.json b/client/package-lock.json
index 35df4b8c..7c711acf 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -27,6 +27,7 @@
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"eslint": "^8.32.0",
+ "eslint-config-prettier": "^8.8.0",
"eslint-config-react-app": "^7.0.1",
"eslint-config-recommended": "^4.1.0",
"eslint-plugin-import": "^2.27.5",
@@ -34,6 +35,7 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-simple-import-sort": "^10.0.0",
"prettier": "2.8.4"
}
},
@@ -8394,6 +8396,18 @@
"which": "bin/which"
}
},
+ "node_modules/eslint-config-prettier": {
+ "version": "8.8.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz",
+ "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==",
+ "dev": true,
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
"node_modules/eslint-config-react-app": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz",
@@ -9477,6 +9491,15 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/eslint-plugin-simple-import-sort": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz",
+ "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==",
+ "dev": true,
+ "peerDependencies": {
+ "eslint": ">=5.0.0"
+ }
+ },
"node_modules/eslint-plugin-testing-library": {
"version": "5.9.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz",
@@ -25717,6 +25740,13 @@
}
}
},
+ "eslint-config-prettier": {
+ "version": "8.8.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz",
+ "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==",
+ "dev": true,
+ "requires": {}
+ },
"eslint-config-react-app": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz",
@@ -26524,6 +26554,13 @@
"integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==",
"dev": true
},
+ "eslint-plugin-simple-import-sort": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz",
+ "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==",
+ "dev": true,
+ "requires": {}
+ },
"eslint-plugin-testing-library": {
"version": "5.9.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz",
diff --git a/client/package.json b/client/package.json
index 5e9c802d..f987671c 100644
--- a/client/package.json
+++ b/client/package.json
@@ -23,8 +23,8 @@
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
- "lint": "eslint .; prettier . --check",
- "lint:fix": "eslint . --fix & prettier . --write"
+ "lint": "eslint .",
+ "lint:fix": "eslint . --fix"
},
"browserslist": {
"production": [
@@ -43,6 +43,7 @@
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"eslint": "^8.32.0",
+ "eslint-config-prettier": "^8.8.0",
"eslint-config-react-app": "^7.0.1",
"eslint-config-recommended": "^4.1.0",
"eslint-plugin-import": "^2.27.5",
@@ -50,6 +51,7 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-simple-import-sort": "^10.0.0",
"prettier": "2.8.4"
}
}
diff --git a/client/src/App.jsx b/client/src/App.jsx
index 9f362393..a0c59855 100644
--- a/client/src/App.jsx
+++ b/client/src/App.jsx
@@ -1,10 +1,11 @@
-import React, { Suspense } from "react";
-import { BrowserRouter, Route, Routes } from "react-router-dom";
-import { CssBaseline, ThemeProvider } from "@mui/material";
-import "@fontsource/poppins";
+import '@fontsource/poppins';
-import theme from "./theme";
-import Loading from "./components/Loading";
+import { CssBaseline, ThemeProvider } from '@mui/material';
+import React, { Suspense } from 'react';
+import { BrowserRouter, Route, Routes } from 'react-router-dom';
+
+import Loading from './components/Loading';
+import theme from './theme';
const withSuspense = (Component) => (
}>
@@ -12,10 +13,10 @@ const withSuspense = (Component) => (
);
-const HomePage = React.lazy(() => import("./pages/HomePage"));
-const SearchResultsPage = React.lazy(() => import("./pages/SearchResultsPage"));
-const AboutPage = React.lazy(() => import("./pages/AboutPage"));
-const ErrorPage = React.lazy(() => import("./pages/ErrorPage"));
+const HomePage = React.lazy(() => import('./pages/HomePage'));
+const SearchResultsPage = React.lazy(() => import('./pages/SearchResultsPage'));
+const AboutPage = React.lazy(() => import('./pages/AboutPage'));
+const ErrorPage = React.lazy(() => import('./pages/ErrorPage'));
const App = () => {
return (
diff --git a/client/src/components/BackgroundShapes.jsx b/client/src/components/BackgroundShapes.jsx
index 35cb97de..ec3afa8e 100644
--- a/client/src/components/BackgroundShapes.jsx
+++ b/client/src/components/BackgroundShapes.jsx
@@ -1,9 +1,9 @@
-import { useTheme, Box } from "@mui/material";
-import React from "react";
+import { Box, useTheme } from '@mui/material';
+import React from 'react';
-import blobShape from "../assets/milk_tea_blob.svg";
-import circleShape from "../assets/milk_tea_circle.svg";
-import noodleShape from "../assets/milk_tea_noodle.svg";
+import blobShape from '../assets/milk_tea_blob.svg';
+import circleShape from '../assets/milk_tea_circle.svg';
+import noodleShape from '../assets/milk_tea_noodle.svg';
const BackgroundShapes = () => {
const theme = useTheme();
@@ -11,23 +11,23 @@ const BackgroundShapes = () => {
return (
{
{
@@ -32,18 +30,18 @@ const BobaCard = ({
@@ -52,9 +50,9 @@ const BobaCard = ({
@@ -63,18 +61,18 @@ const BobaCard = ({
{position}
-
+
@@ -85,11 +83,11 @@ const BobaCard = ({
diff --git a/client/src/components/Filter.jsx b/client/src/components/Filter.jsx
index 4061d0fc..822f6483 100644
--- a/client/src/components/Filter.jsx
+++ b/client/src/components/Filter.jsx
@@ -1,4 +1,4 @@
-import React, { useState, useContext } from "react";
+import { ArrowDropDown, Close } from '@mui/icons-material';
import {
Box,
Button,
@@ -9,9 +9,10 @@ import {
FormGroup,
Popover,
Typography,
-} from "@mui/material";
-import { ArrowDropDown, Close } from "@mui/icons-material";
-import FilterContext from "../contexts/FilterContext";
+} from '@mui/material';
+import React, { useContext, useState } from 'react';
+
+import FilterContext from '../contexts/FilterContext';
/**
* Individual filter component to be used within the FiltersBar.
@@ -95,14 +96,14 @@ const Filter = ({ filterLabel }) => {
const id = open ? allFilterData[filterLabel].filterName : undefined;
const popOverProps = {
sx: {
- backgroundColor: "grey.main",
+ backgroundColor: 'grey.main',
boxShadow:
- "0px 1px 1px rgba(0, 0, 0, 0.14), 0px 1px 2px rgba(0, 0, 0, 0.12), 0px 1px 3px rgba(0, 0, 0, 0.2)",
- marginTop: "0.5rem",
- borderRadius: "8px",
+ '0px 1px 1px rgba(0, 0, 0, 0.14), 0px 1px 2px rgba(0, 0, 0, 0.12), 0px 1px 3px rgba(0, 0, 0, 0.2)',
+ marginTop: '0.5rem',
+ borderRadius: '8px',
},
};
- const cancelButtonLabel = ["Cancel filter", "Reset filter", "Cancel changes"];
+ const cancelButtonLabel = ['Cancel filter', 'Reset filter', 'Cancel changes'];
return (
<>
diff --git a/client/src/pages/BasePage.jsx b/client/src/pages/BasePage.jsx
index d8abf5c1..2c8f4c45 100644
--- a/client/src/pages/BasePage.jsx
+++ b/client/src/pages/BasePage.jsx
@@ -1,7 +1,7 @@
-import { Grid } from "@mui/material";
-import React from "react";
+import { Grid } from '@mui/material';
+import React from 'react';
-import NavBar from "../components/Navbar";
+import NavBar from '../components/Navbar';
/**
* Base "Page" component that will wrap and return our standard page layout with
@@ -13,7 +13,7 @@ const BasePage = (props) => {
return (
diff --git a/client/src/pages/ErrorPage.jsx b/client/src/pages/ErrorPage.jsx
index e47185b2..a6da4a9f 100644
--- a/client/src/pages/ErrorPage.jsx
+++ b/client/src/pages/ErrorPage.jsx
@@ -1,8 +1,8 @@
-import React from "react";
-import { Box, Link, Stack, Typography } from "@mui/material";
+import { Box, Link, Stack, Typography } from '@mui/material';
+import React from 'react';
-import BasePage from "./BasePage";
-import BackgroundShapes from "../components/BackgroundShapes";
+import BackgroundShapes from '../components/BackgroundShapes';
+import BasePage from './BasePage';
const ErrorPage = () => {
return (
@@ -16,11 +16,11 @@ const ErrorPage = () => {
Page Not Found!
diff --git a/client/src/pages/HomePage.jsx b/client/src/pages/HomePage.jsx
index e903cc47..25608747 100644
--- a/client/src/pages/HomePage.jsx
+++ b/client/src/pages/HomePage.jsx
@@ -1,10 +1,10 @@
-import React from "react";
-import { Grid, Stack } from "@mui/material";
+import { Grid, Stack } from '@mui/material';
+import React from 'react';
-import BasePage from "./BasePage";
-import BackgroundShapes from "../components/BackgroundShapes";
-import HomePageContent from "../components/HomePageContent";
-import SearchBar from "../components/SearchBar";
+import BackgroundShapes from '../components/BackgroundShapes';
+import HomePageContent from '../components/HomePageContent';
+import SearchBar from '../components/SearchBar';
+import BasePage from './BasePage';
/**
* https://github.com/BobaTalks/internship-tracker/issues/24
diff --git a/client/src/pages/SearchResultsPage.jsx b/client/src/pages/SearchResultsPage.jsx
index 01261916..a6de21b5 100644
--- a/client/src/pages/SearchResultsPage.jsx
+++ b/client/src/pages/SearchResultsPage.jsx
@@ -1,12 +1,11 @@
-import React, { useState } from "react";
-import { Stack, Typography } from "@mui/material";
+import { Stack, Typography } from '@mui/material';
+import React, { useState } from 'react';
-import BasePage from "./BasePage";
-import FiltersBar from "../components/FiltersBar";
-import SearchBar from "../components/SearchBar";
-
-import FilterContext from "../contexts/FilterContext";
-import SearchResults from "../components/SearchResults";
+import FiltersBar from '../components/FiltersBar';
+import SearchBar from '../components/SearchBar';
+import SearchResults from '../components/SearchResults';
+import FilterContext from '../contexts/FilterContext';
+import BasePage from './BasePage';
/**
* https://github.com/BobaTalks/internship-tracker/issues/28
* This page will display all the search results. Part of this work we should include the
@@ -15,120 +14,120 @@ import SearchResults from "../components/SearchResults";
const MOCK_FILTER_DATA = {
remote: {
- filterName: "Remote",
+ filterName: 'Remote',
data: {
onsite: {
- label: "On-site",
+ label: 'On-site',
count: 4,
checked: false,
},
remote: {
- label: "Remote",
+ label: 'Remote',
count: 5,
checked: false,
},
hybrid: {
- label: "Hybrid",
+ label: 'Hybrid',
count: 12,
checked: false,
},
},
},
company: {
- filterName: "Company",
+ filterName: 'Company',
data: {
meta: {
- label: "Meta",
+ label: 'Meta',
count: 4,
checked: false,
},
amazon: {
- label: "Amazon",
+ label: 'Amazon',
count: 5,
checked: false,
},
netflix: {
- label: "Netflix",
+ label: 'Netflix',
count: 15,
checked: false,
},
google: {
- label: "Google",
+ label: 'Google',
count: 12,
checked: false,
},
apple: {
- label: "Apple",
+ label: 'Apple',
count: 2,
checked: false,
},
},
},
education: {
- filterName: "Education",
+ filterName: 'Education',
data: {
currentStudent: {
- label: "Current student",
+ label: 'Current student',
count: 4,
checked: false,
},
recentGraduate: {
- label: "Recent graduate",
+ label: 'Recent graduate',
count: 5,
checked: false,
},
},
},
semester: {
- filterName: "Semester",
+ filterName: 'Semester',
data: {
spring2023: {
- label: "Spring 2023",
+ label: 'Spring 2023',
count: 4,
checked: false,
},
summer2023: {
- label: "Summer 2023",
+ label: 'Summer 2023',
count: 5,
checked: false,
},
fall2023: {
- label: "Fall 2023",
+ label: 'Fall 2023',
count: 10,
checked: false,
},
spring2024: {
- label: "Spring 2024",
+ label: 'Spring 2024',
count: 23,
checked: false,
},
summer2024: {
- label: "Summer 2024",
+ label: 'Summer 2024',
count: 8,
checked: false,
},
},
},
datePosted: {
- filterName: "Date posted",
+ filterName: 'Date posted',
data: {
anyTime: {
- label: "Any time",
+ label: 'Any time',
count: 3,
checked: false,
},
pastDay: {
- label: "Past 24 hours",
+ label: 'Past 24 hours',
count: 2,
checked: false,
},
pastWeek: {
- label: "Past week",
+ label: 'Past week',
count: 21,
checked: false,
},
pastMonth: {
- label: "Past month",
+ label: 'Past month',
count: 12,
checked: false,
},
diff --git a/client/src/reportWebVitals.js b/client/src/reportWebVitals.js
index 9ecd33f9..532f29b0 100644
--- a/client/src/reportWebVitals.js
+++ b/client/src/reportWebVitals.js
@@ -1,6 +1,6 @@
const reportWebVitals = (onPerfEntry) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
- import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
diff --git a/client/src/setupTests.js b/client/src/setupTests.js
index 1dd407a6..8f2609b7 100644
--- a/client/src/setupTests.js
+++ b/client/src/setupTests.js
@@ -2,4 +2,4 @@
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
-import "@testing-library/jest-dom";
+import '@testing-library/jest-dom';
diff --git a/client/src/theme.js b/client/src/theme.js
index 8add1cbf..28b026f7 100644
--- a/client/src/theme.js
+++ b/client/src/theme.js
@@ -1,29 +1,29 @@
-import { createTheme, responsiveFontSizes } from "@mui/material";
+import { createTheme, responsiveFontSizes } from '@mui/material';
const COLORS = {
- HYPERLINK_BLUE: "#005EA2",
- BODY_TEXT: "#2F3032",
- LIGHT_GREY_TEXT: "#78787A",
- BACKGROUND: "#FAF0E7",
- CARD_BG: "#FFFFFF",
- NAVBAR_BG: "#F2DAC4",
- BLUEBERRY: "#021944",
- LYCHEE: "#F6A794",
- CARD_CHIPS: "#ABBFE3",
- ERROR_BUTTON: "#D21C1C",
- ERROR_BG: "#F8D7D7",
- SLIDEOUT_NOTES_BG: "#FFF5ED",
- THAI_TEA: "#E0A878",
- MILK_TEA: "#F2DAC4",
- LOGO_BROWN: "#98513A",
- OFFWHITE_GREY: "#D9D9D9",
- PAGINATION_BG: "#F9E5DC",
- SEARCHBAR_ICON_BORDER: "#DBAE9C",
- THAI_FILL_INACTIVE: "#B4AAA0",
- BOBA_POSITION: "#A9917B",
- SLIDEOUT_SUBTEXT: "#E1D4C8",
- MENTORS_BG: "#FFFDFB",
- LINKEDIN_ICON: "#377DB6",
+ HYPERLINK_BLUE: '#005EA2',
+ BODY_TEXT: '#2F3032',
+ LIGHT_GREY_TEXT: '#78787A',
+ BACKGROUND: '#FAF0E7',
+ CARD_BG: '#FFFFFF',
+ NAVBAR_BG: '#F2DAC4',
+ BLUEBERRY: '#021944',
+ LYCHEE: '#F6A794',
+ CARD_CHIPS: '#ABBFE3',
+ ERROR_BUTTON: '#D21C1C',
+ ERROR_BG: '#F8D7D7',
+ SLIDEOUT_NOTES_BG: '#FFF5ED',
+ THAI_TEA: '#E0A878',
+ MILK_TEA: '#F2DAC4',
+ LOGO_BROWN: '#98513A',
+ OFFWHITE_GREY: '#D9D9D9',
+ PAGINATION_BG: '#F9E5DC',
+ SEARCHBAR_ICON_BORDER: '#DBAE9C',
+ THAI_FILL_INACTIVE: '#B4AAA0',
+ BOBA_POSITION: '#A9917B',
+ SLIDEOUT_SUBTEXT: '#E1D4C8',
+ MENTORS_BG: '#FFFDFB',
+ LINKEDIN_ICON: '#377DB6',
};
let theme = createTheme({
@@ -70,50 +70,50 @@ let theme = createTheme({
},
typography: {
color: COLORS.BODY_TEXT,
- fontFamily: "Poppins",
- h1: { fontWeight: "bold", fontSize: "4.5rem" },
- h2: { fontWeight: "bold", fontSize: "3.5rem" },
- h3: { fontWeight: "bold", fontSize: "3rem" },
- h4: { fontWeight: "bold", fontSize: "2rem" },
- h5: { fontWeight: "bold", fontSize: "1.5rem" },
- h6: { fontWeight: "bold", fontSize: "1rem" },
- title: { fontWeight: "600", fontSize: "3.5rem", lineHeight: "5.5rem" },
- pageTitle: { fontWeight: "600", fontSize: "2rem" },
- errorMessage: { fontWeight: "600", fontSize: "1rem" },
- subtitle: { fontSize: "1.125rem" },
- body1: { fontSize: "1.125rem" },
+ fontFamily: 'Poppins',
+ h1: { fontWeight: 'bold', fontSize: '4.5rem' },
+ h2: { fontWeight: 'bold', fontSize: '3.5rem' },
+ h3: { fontWeight: 'bold', fontSize: '3rem' },
+ h4: { fontWeight: 'bold', fontSize: '2rem' },
+ h5: { fontWeight: 'bold', fontSize: '1.5rem' },
+ h6: { fontWeight: 'bold', fontSize: '1rem' },
+ title: { fontWeight: '600', fontSize: '3.5rem', lineHeight: '5.5rem' },
+ pageTitle: { fontWeight: '600', fontSize: '2rem' },
+ errorMessage: { fontWeight: '600', fontSize: '1rem' },
+ subtitle: { fontSize: '1.125rem' },
+ body1: { fontSize: '1.125rem' },
navText: {
- fontSize: ".8rem",
+ fontSize: '.8rem',
fontWeight: 600,
- textTransform: "none",
+ textTransform: 'none',
},
memberName: {
fontWeight: 600,
- textAlign: "center",
- maxWidth: "80%",
- fontSize: "1.3vw",
- marginTop: "5%",
+ textAlign: 'center',
+ maxWidth: '80%',
+ fontSize: '1.3vw',
+ marginTop: '5%',
},
memberPronouns: {
fontWeight: 600,
- fontSize: "0.9vw",
+ fontSize: '0.9vw',
},
memberPosition: {
fontWeight: 600,
- fontSize: "1.1vw",
- marginTop: "4%",
- maxWidth: "80%",
- textAlign: "center",
+ fontSize: '1.1vw',
+ marginTop: '4%',
+ maxWidth: '80%',
+ textAlign: 'center',
},
aboutBody: {
- fontSize: "0.9rem",
+ fontSize: '0.9rem',
},
},
components: {
MuiTypography: {
styleOverrides: {
root: {
- fontFamily: "Poppins",
+ fontFamily: 'Poppins',
},
},
defaultProps: {
@@ -131,42 +131,42 @@ let theme = createTheme({
MuiButton: {
variants: [
{
- props: { variant: "transparent" },
+ props: { variant: 'transparent' },
style: {
- fontSize: ".9rem",
- textTransform: "none",
- background: "none",
- borderRadius: "20px",
+ fontSize: '.9rem',
+ textTransform: 'none',
+ background: 'none',
+ borderRadius: '20px',
},
},
{
- props: { variant: "rounded", color: "primary" },
+ props: { variant: 'rounded', color: 'primary' },
style: {
- textTransform: "none",
- fontSize: ".9rem",
- borderRadius: "20px",
+ textTransform: 'none',
+ fontSize: '.9rem',
+ borderRadius: '20px',
backgroundColor: COLORS.LYCHEE,
color: COLORS.BLUEBERRY,
- "&:hover": {
+ '&:hover': {
backgroundColor: COLORS.LYCHEE,
boxShadow:
- "0px 1px 2px rgba(0, 0, 0, 0.3), 0px 1px 3px 1px rgba(0, 0, 0, 0.15)",
+ '0px 1px 2px rgba(0, 0, 0, 0.3), 0px 1px 3px 1px rgba(0, 0, 0, 0.15)',
},
},
},
{
- props: { variant: "rounded", color: "thai" },
+ props: { variant: 'rounded', color: 'thai' },
style: {
- textTransform: "none",
- fontSize: "1rem",
- borderRadius: "20px",
+ textTransform: 'none',
+ fontSize: '1rem',
+ borderRadius: '20px',
backgroundColor: COLORS.LOGO_BROWN,
- margin: ".4rem 0rem",
+ margin: '.4rem 0rem',
color: COLORS.CARD_BG,
- "&:hover": {
+ '&:hover': {
backgroundColor: COLORS.LOGO_BROWN,
boxShadow:
- "0px 1px 2px rgba(0, 0, 0, 0.3), 0px 1px 3px 1px rgba(0, 0, 0, 0.15)",
+ '0px 1px 2px rgba(0, 0, 0, 0.3), 0px 1px 3px 1px rgba(0, 0, 0, 0.15)',
},
},
},
@@ -175,8 +175,8 @@ let theme = createTheme({
MuiCard: {
styleOverrides: {
root: {
- padding: "2rem",
- borderRadius: "2rem",
+ padding: '2rem',
+ borderRadius: '2rem',
},
},
defaultProps: {
diff --git a/client/src/utils/api.js b/client/src/utils/api.js
index 45798726..7f25f2b8 100644
--- a/client/src/utils/api.js
+++ b/client/src/utils/api.js
@@ -1,6 +1,7 @@
// File to contain methods to return data from API calls
-import axios from "axios";
-import { test_url } from "./constants";
+import axios from 'axios';
+
+import { test_url } from './constants';
const url = process.env.BASE_URL || test_url;
/**
@@ -15,7 +16,7 @@ export const getSearchInternships = async (searchOptions) => {
const params = hasSearchOptions > 0 ? { ...searchOptions } : {};
const response = await axios.get(`${url}/jobs`, {
- headers: { "Content-Type": "application/json" },
+ headers: { 'Content-Type': 'application/json' },
params: params,
});
return response;
@@ -28,7 +29,7 @@ export const getSearchInternships = async (searchOptions) => {
* @return {*}
*/
export const postSaveInternship = (internshipId) => {
- const url = "";
+ const url = '';
const options = {};
return [
@@ -45,7 +46,7 @@ export const postSaveInternship = (internshipId) => {
* @return {Promise}
*/
export const getUserInternships = () => {
- const url = "";
+ const url = '';
const options = {};
return [
diff --git a/client/src/utils/constants.js b/client/src/utils/constants.js
index baf6b588..4b218334 100644
--- a/client/src/utils/constants.js
+++ b/client/src/utils/constants.js
@@ -1,4 +1,4 @@
// Store constants here for reusability across application
// temporary url for testing
-export const test_url = "http://localhost:5000";
+export const test_url = 'http://localhost:5000';
diff --git a/scraper/Dockerfile b/scraper/Dockerfile
index 02e09df7..6b229348 100644
--- a/scraper/Dockerfile
+++ b/scraper/Dockerfile
@@ -1,6 +1,6 @@
#syntax=docker/dockerfile:1
-FROM python:3.11-alpine
+FROM python:3.11-bullseye
RUN apk add firefox
diff --git a/scraper/scraper.py b/scraper/scraper.py
new file mode 100644
index 00000000..7f036490
--- /dev/null
+++ b/scraper/scraper.py
@@ -0,0 +1,103 @@
+import bs4
+import requests
+
+
+def get_internships():
+ res = requests.get(
+ "https://www.linkedin.com/jobs-guest/jobs/api/seeMoreJobPostings/search?currentJobId=3644104559&f_C=10667%2C1586%2C162479&geoId=103644278&keywords=intern%20OR%20internship&location=United%20States&refresh=true"
+ )
+ return res.text
+
+
+html = get_internships()
+
+soup = bs4.BeautifulSoup(html, "html.parser")
+
+listings: bs4.ResultSet[bs4.Tag] = soup.find_all("li")
+
+
+def get_job_title(listing: bs4.element.Tag) -> str:
+ element = listing.find("h3")
+ if element:
+ return element.text.strip()
+ else:
+ print("The target element's title was not found")
+ return ""
+
+
+def get_job_location(listing: bs4.element.Tag) -> str:
+ element = listing.find("span", "job-search-card__location")
+ if element:
+ return element.text.strip()
+ else:
+ print("The target element's location was not found")
+ return ""
+
+
+def get_job_link(listing: bs4.element.Tag) -> str | list[str]:
+ element = listing.find("a", "base-card__full-link")
+ if isinstance(element, bs4.Tag):
+ return element["href"]
+ else:
+ print("The target element's link was not found")
+ return ""
+
+
+def get_hiring_status(listing: bs4.element.Tag) -> str:
+ element = listing.find("span", "result-benefits__text")
+ if element:
+ return element.text.strip()
+ else:
+ print("The target element's hiring status was not found")
+ return ""
+
+
+def get_time_posted(listing: bs4.element.Tag) -> str:
+ element = listing.find(
+ "time", class_=["job-search-card__listdate", "job-search-card__listdate--new"]
+ )
+ if element:
+ return element.text.strip()
+ else:
+ print("The target element's time posted was not found")
+ return ""
+
+
+job_info_type = dict[str, str | list[str]]
+
+
+def get_all_info(listings_input: bs4.ResultSet[bs4.Tag]) -> list[job_info_type]:
+ results: list[job_info_type] = []
+
+ for i in listings_input:
+ job_info: job_info_type = {
+ "title": get_job_title(i),
+ "link": get_job_link(i),
+ "location": get_job_location(i),
+ "status": get_hiring_status(i),
+ "posted": get_time_posted(i),
+ }
+
+ results.append(job_info)
+
+ return results
+
+
+scraped_data = get_all_info(listings)
+print(scraped_data)
+
+# notes
+# at the moment, if the scraper fails to get a piece of information,
+# it will continue working, but give blank data
+# this was chosen as an alternative to having the whole thing stop working
+# if we see that blank data is appearing in the future, it is a sign
+# that there is either a bug in the scraper, or the way that the content
+# is listed has changed, and the scraper needs to be updated
+
+# current data:
+# job title, job location
+# job links, hiring status
+# time posted
+
+# potential stretch goals:
+# job qualifications, description, responsibilities
diff --git a/server/Dockerfile b/server/Dockerfile
index 4f79b78d..d6c3a0f1 100644
--- a/server/Dockerfile
+++ b/server/Dockerfile
@@ -1,6 +1,6 @@
#syntax=docker/dockerfile:1
-FROM python:3.11-alpine
+FROM python:3.11-bullseye
WORKDIR /usr/src/app
diff --git a/server/requirements.txt b/server/requirements.txt
index a85dcf2b..fca58d46 100644
--- a/server/requirements.txt
+++ b/server/requirements.txt
@@ -8,7 +8,9 @@ certifi==2022.12.7
cffi==1.15.1
charset-normalizer==3.1.0
click==8.1.3
+exceptiongroup==1.1.2
Flask==2.2.3
+Flask-Cors==4.0.0
Flask-JWT-Extended==4.4.4
Flask-SQLAlchemy==3.0.3
google-auth==2.17.2
diff --git a/server/webserver/__init__.py b/server/webserver/__init__.py
index 89f2363b..1eaccd9e 100644
--- a/server/webserver/__init__.py
+++ b/server/webserver/__init__.py
@@ -1,4 +1,5 @@
from flask import Flask
+from flask_cors import CORS
import os
import time
from dotenv import load_dotenv
@@ -8,6 +9,7 @@
def create_app(test_config=None):
app = Flask(__name__)
+ CORS(app, origins=["http://localhost:3000"])
if test_config:
# configure test database to keep testing data separate
diff --git a/server/webserver/models.py b/server/webserver/models.py
index 88b35a4f..b6c657de 100644
--- a/server/webserver/models.py
+++ b/server/webserver/models.py
@@ -1,5 +1,6 @@
from .extensions import db, jwt
from utils.hashing import verify_hash
+from datetime import datetime
class User(db.Model):
@@ -23,6 +24,8 @@ class Job(db.Model):
title = db.Column(db.String, nullable=False)
url = db.Column(db.String, nullable=False)
location = db.Column(db.ForeignKey("locations.id"), nullable=False)
+ status = db.Column(db.String, nullable=False)
+ createdAt = db.Column(datetime, default=datetime.utcnow, nullable=False)
class Location(db.Model):