├── .env_example ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode └── settings.json ├── DEPLOYS.md ├── README.md ├── deploy.sh ├── jsconfig.json ├── package-lock.json ├── package.json ├── public ├── blog │ ├── anchorfm-logo.png │ ├── default.png │ ├── podcast.png │ └── video.png ├── favicon-bw.ico ├── favicon.ico ├── illustrations │ ├── calendar.png │ ├── coffee-chat.png │ ├── computer.png │ ├── get-involved.png │ ├── hero-full.png │ ├── hero.png │ ├── more-events.png │ └── wise-girls.png ├── index.html ├── logos │ ├── se-logo-transparent.png │ ├── se-logo-trimmed-transparent-bw.png │ ├── se-logo-trimmed-transparent.png │ ├── se-logo-trimmed.png │ ├── se-logo.png │ └── wise-logo.png ├── manifest.json └── profiles │ ├── aaron.jpg │ ├── atif.jpg │ ├── danny.jpg │ ├── elisa.jpg │ ├── mayank.jpg │ ├── molly.jpg │ └── yash.jpg ├── sesoc.code-workspace └── src ├── App.jsx ├── App.scss ├── App.test.jsx ├── components ├── BlogPostsGroup.jsx ├── BlogSocialLinks.jsx ├── ComingSoon.jsx ├── EventCalendar.jsx ├── EventList.jsx ├── Footer.jsx ├── Meetings.jsx ├── NavigationBar.jsx ├── NewsList.jsx ├── Platform.jsx ├── ProfilePhotoGroup.jsx ├── PromptActionButtons.jsx └── styles │ ├── BlogPostsGroup.scss │ ├── BlogSocialLinks.scss │ ├── EventCalendar.scss │ ├── EventList.scss │ ├── Footer.scss │ ├── Meetings.scss │ ├── NavigationBar.scss │ ├── NewsList.scss │ ├── ProfilePhotoGroup.scss │ ├── PromptActionButtons.scss │ └── ReactBigCalendar.scss ├── containers ├── About.jsx ├── Blog.jsx ├── Events.jsx ├── GetInvolved.jsx ├── Home.jsx ├── Sponsors.jsx ├── Wise.jsx └── styles │ ├── Events.scss │ ├── GetInvolved.scss │ ├── Home.scss │ └── Wise.scss ├── content └── BlogContent.js ├── index.css ├── index.js ├── modules └── gcal.js ├── serviceWorker.js └── styles └── _colors.scss /.env_example: -------------------------------------------------------------------------------- 1 | REACT_APP_GOOGLE_CALENDAR_ID='CALENDAR_ID_GOES_HERE' 2 | REACT_APP_GOOGLE_CALENDAR_API_KEY='API_KEY_GOES_HERE' 3 | 4 | REACT_APP_GOOGLE_CALENDAR_ID_WISE='CALENDAR_ID_GOES_HERE' 5 | REACT_APP_GOOGLE_CALENDAR_API_KEY_WISE='API_KEY_GOES_HERE' -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/** 2 | public/** 3 | build/** 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | es6: true, 5 | }, 6 | parser: "babel-eslint", 7 | parserOptions: { 8 | sourceType: "module", 9 | }, 10 | settings: { 11 | react: { 12 | createClass: "createReactClass", 13 | pragma: "React", 14 | version: "detect", 15 | flowVersion: "0.53", 16 | }, 17 | linkComponents: [ 18 | { name: "Link", linkAttribute: "to" }, 19 | { name: "OutboundLink", linkAttribute: "to" }, 20 | ], 21 | }, 22 | rules: { 23 | "no-console": "warn", 24 | "no-param-reassign": "error", 25 | "react/jsx-key": ["off"], 26 | }, 27 | // Use prettier for code formatting and eslint soley for linting 28 | extends: ["eslint:recommended", "plugin:react/recommended", "prettier"], 29 | }; 30 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: SE Soc CI 5 | on: 6 | pull_request: 7 | 8 | jobs: 9 | lint: 10 | name: Lint 11 | 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [12.x] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm ci 25 | - run: npm run ci_format 26 | env: 27 | CI: true 28 | build: 29 | name: Build App 30 | 31 | runs-on: ubuntu-latest 32 | 33 | strategy: 34 | matrix: 35 | node-version: [12.x] 36 | 37 | steps: 38 | - uses: actions/checkout@v2 39 | - name: Use Node.js ${{ matrix.node-version }} 40 | uses: actions/setup-node@v1 41 | with: 42 | node-version: ${{ matrix.node-version }} 43 | - run: npm ci 44 | - run: npm run build --if-present 45 | env: 46 | CI: true 47 | test: 48 | name: Run Tests 49 | 50 | runs-on: ubuntu-latest 51 | 52 | strategy: 53 | matrix: 54 | node-version: [12.x] 55 | 56 | steps: 57 | - uses: actions/checkout@v2 58 | - name: Use Node.js ${{ matrix.node-version }} 59 | uses: actions/setup-node@v1 60 | with: 61 | node-version: ${{ matrix.node-version }} 62 | - run: npm ci 63 | - run: npm test 64 | env: 65 | CI: true 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | #firebase stuff 13 | #.firebaserc 14 | #firebase.json 15 | 16 | # misc 17 | **/.DS_Store 18 | .env 19 | .env.local 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add all file/file extensions to be ignored by prettier here 2 | *.md 3 | *.html 4 | src/assets/* 5 | package-lock.json 6 | jsconfig.json 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 2, 4 | "semi": false, 5 | "singleQuote": true, 6 | "jsxBracketSameLine": false, 7 | "arrowParens": "always", 8 | "bracketSpacing": true 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnPaste": true, 3 | "editor.formatOnType": true 4 | } 5 | -------------------------------------------------------------------------------- /DEPLOYS.md: -------------------------------------------------------------------------------- 1 | # Some important information about Deploying to CSC servers # 2 | - CSC uses Apache 3 | - the .htaccess in sesoc/www folder is needed. Please don't clear the directory, otherwise you need to make a new .htaccess file within sesoc/www with the following contents: 4 | ``` 5 | Options -MultiViews 6 | RewriteEngine On 7 | RewriteCond %{REQUEST_FILENAME} !-f 8 | RewriteRule ^ index.html [QSA,L] 9 | ``` 10 | 11 | # Steps to Deploy (if not using the deploy.sh script) # 12 | 1. login to any CSC server 13 | 2. cd to the sesoc's subdirectory in users 14 | 3. ```become_club sesoc``` 15 | 4. ```cd public-website``` 16 | 5. ```./deploy.sh``` (and follow any instructions given) 17 | 6. done! 18 | 19 | 20 | # Steps to Deploy (if not using the deploy.sh script) # 21 | 1. login to any CSC server 22 | 2. cd to the sesoc's subdirectory in users 23 | 3. ```become_club sesoc``` 24 | 4. ```cd public-website``` 25 | 5. ```git pull``` (may need to login with github credentials) 26 | 6. ```npm install``` 27 | 7. ```npm run build``` 28 | 8. ```cp -r build/* ../www``` 29 | 9. done! 30 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | git pull 3 | npm install 4 | npm run build 5 | cp -r build/* ../www 6 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "src", 5 | "strictNullChecks": true, 6 | "noUnusedLocals": true, 7 | "noImplicitThis": true, 8 | "noFallthroughCasesInSwitch": true, 9 | "allowUnreachableCode": false 10 | }, 11 | "include": ["src", "jsconfig.json"] 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "public-website", 4 | "homepage": "https://sesoc.uwaterloo.ca/", 5 | "version": "0.1.0", 6 | "scripts": { 7 | "build": "react-scripts build", 8 | "ci_format": "prettier-eslint --list-different --log-level error $PWD/\"**/*.js\" $PWD/\"**/*.jsx\" && eslint \"**/*.js\" \"**/*.jsx\" && prettier-package-json --list-different --tab-width 2 ./package.json", 9 | "eject": "react-scripts eject", 10 | "format": "prettier-eslint $PWD/\"**/*.js\" $PWD/\"**/*.jsx\" --write && eslint \"**/*.js\" \"**/*.jsx\" --fix && prettier-package-json --write --tab-width 2 ./package.json", 11 | "lint": "eslint \"**/*.js\" \"**/*.jsx\" --fix", 12 | "start": "react-scripts start", 13 | "test": "react-scripts test" 14 | }, 15 | "dependencies": { 16 | "ajv": "^6.10.0", 17 | "bootstrap": "^4.5.0", 18 | "lodash": "^4.17.19", 19 | "node-sass": "^4.14.1", 20 | "react": "next", 21 | "react-big-calendar": "^0.24.6", 22 | "react-bootstrap": "^1.0.0-beta.9", 23 | "react-dom": "next", 24 | "react-router-dom": "^5.2.0", 25 | "react-scripts": "4.0.2", 26 | "url": "^0.11.0" 27 | }, 28 | "devDependencies": { 29 | "axios": "^0.21.1", 30 | "eslint-config-prettier": "^7.2.0", 31 | "moment": "^2.26.0", 32 | "prettier-eslint": "^12.0.0", 33 | "prettier-eslint-cli": "^5.0.0", 34 | "prettier-package-json": "2.1.3" 35 | }, 36 | "browserslist": [ 37 | ">0.2%", 38 | "not dead", 39 | "not ie <= 11", 40 | "not op_mini all" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /public/blog/anchorfm-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/blog/anchorfm-logo.png -------------------------------------------------------------------------------- /public/blog/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/blog/default.png -------------------------------------------------------------------------------- /public/blog/podcast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/blog/podcast.png -------------------------------------------------------------------------------- /public/blog/video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/blog/video.png -------------------------------------------------------------------------------- /public/favicon-bw.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/favicon-bw.ico -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/favicon.ico -------------------------------------------------------------------------------- /public/illustrations/calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/calendar.png -------------------------------------------------------------------------------- /public/illustrations/coffee-chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/coffee-chat.png -------------------------------------------------------------------------------- /public/illustrations/computer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/computer.png -------------------------------------------------------------------------------- /public/illustrations/get-involved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/get-involved.png -------------------------------------------------------------------------------- /public/illustrations/hero-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/hero-full.png -------------------------------------------------------------------------------- /public/illustrations/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/hero.png -------------------------------------------------------------------------------- /public/illustrations/more-events.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/more-events.png -------------------------------------------------------------------------------- /public/illustrations/wise-girls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/illustrations/wise-girls.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 31 | SE Soc 32 | 33 | 34 | 35 | 38 |
39 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /public/logos/se-logo-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo-transparent.png -------------------------------------------------------------------------------- /public/logos/se-logo-trimmed-transparent-bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo-trimmed-transparent-bw.png -------------------------------------------------------------------------------- /public/logos/se-logo-trimmed-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo-trimmed-transparent.png -------------------------------------------------------------------------------- /public/logos/se-logo-trimmed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo-trimmed.png -------------------------------------------------------------------------------- /public/logos/se-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/se-logo.png -------------------------------------------------------------------------------- /public/logos/wise-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/logos/wise-logo.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "SE Society", 3 | "name": "University of Waterloo Software Engineering Society", 4 | "icons": [{ 5 | "src": "favicon-bw.ico", 6 | "sizes": "64x64 32x32 24x24 16x16", 7 | "type": "image/x-icon" 8 | }], 9 | "start_url": ".", 10 | "display": "standalone", 11 | "theme_color": "#000000", 12 | "background_color": "#ffffff" 13 | } -------------------------------------------------------------------------------- /public/profiles/aaron.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/aaron.jpg -------------------------------------------------------------------------------- /public/profiles/atif.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/atif.jpg -------------------------------------------------------------------------------- /public/profiles/danny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/danny.jpg -------------------------------------------------------------------------------- /public/profiles/elisa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/elisa.jpg -------------------------------------------------------------------------------- /public/profiles/mayank.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/mayank.jpg -------------------------------------------------------------------------------- /public/profiles/molly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/molly.jpg -------------------------------------------------------------------------------- /public/profiles/yash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SESoc/public-website/bf8c93affc531b2cc9d3b94ab7d5d9e3ab599c8b/public/profiles/yash.jpg -------------------------------------------------------------------------------- /sesoc.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "eslint.workingDirectories": [ 9 | { 10 | "mode": "auto" 11 | } 12 | ], 13 | "files.trimTrailingWhitespace": true, 14 | "files.insertFinalNewline": true, 15 | "editor.tabSize": 2, 16 | "editor.defaultFormatter": "esbenp.prettier-vscode", 17 | "editor.formatOnSave": true, 18 | "[javascript, javascriptreact]": { 19 | "editor.defaultFormatter": "esbenp.prettier-vscode", 20 | "editor.formatOnSave": true 21 | }, 22 | "files.exclude": { 23 | "css": true, 24 | "scss": true, 25 | "ejs": true, 26 | "node_modules": true, 27 | "**/.DS_Store": true 28 | }, 29 | "css.validate": false, 30 | "files.autoSave": "onFocusChange" 31 | }, 32 | "extensions": { 33 | "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom' 3 | 4 | import Home from 'containers/Home' 5 | import Events from 'containers/Events' 6 | import About from 'containers/About' 7 | import GetInvolved from 'containers/GetInvolved' 8 | import Blog from 'containers/Blog' 9 | import Wise from 'containers/Wise' 10 | import NavigationBar from 'components/NavigationBar' 11 | import 'App.scss' 12 | 13 | class App extends Component { 14 | render() { 15 | return ( 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 | ) 30 | } 31 | } 32 | 33 | export default App 34 | -------------------------------------------------------------------------------- /src/App.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/colors'; 2 | 3 | :root { 4 | --color-eng: #{$color-eng}; 5 | --color-math: #{$color-math}; 6 | } 7 | 8 | .App { 9 | text-align: center; 10 | } 11 | 12 | .App-logo { 13 | animation: App-logo-spin infinite 20s linear; 14 | height: 40vmin; 15 | } 16 | 17 | .App-header { 18 | background-color: #282c34; 19 | min-height: 100vh; 20 | display: flex; 21 | flex-direction: column; 22 | align-items: center; 23 | justify-content: center; 24 | font-size: calc(10px + 2vmin); 25 | color: white; 26 | } 27 | 28 | .App-link { 29 | color: #61dafb; 30 | } 31 | 32 | @keyframes App-logo-spin { 33 | from { 34 | transform: rotate(0deg); 35 | } 36 | to { 37 | transform: rotate(360deg); 38 | } 39 | } 40 | 41 | /* Navbar styling */ 42 | 43 | a { 44 | margin-top: 0em; 45 | color: $color-eng; 46 | } 47 | 48 | .primary-nav { 49 | float: right; 50 | margin-left: auto; 51 | margin-right: 0; 52 | text-align: right; 53 | } 54 | 55 | /* Site-wide styling */ 56 | 57 | h1 { 58 | color: $color-primary; 59 | font-family: 'Poppins', sans-serif; 60 | font-weight: 700; 61 | } 62 | 63 | h2 { 64 | font-family: 'Poppins', sans-serif; 65 | font-weight: 500; 66 | } 67 | 68 | h3 { 69 | font-family: 'Poppins', sans-serif; 70 | font-weight: 400; 71 | } 72 | 73 | p { 74 | color: $color-primary; 75 | font-family: 'Poppins', sans-serif; 76 | font-weight: 400; 77 | } 78 | 79 | .center { 80 | text-align: center; 81 | } 82 | 83 | .container { 84 | margin-top: 0px; 85 | width: 100%; 86 | overflow: hidden; 87 | } 88 | 89 | /* 90 | `footer-to-bottom` wraps the body and footer for each page. 91 | It spaces the two containers out so that the footer is pushed 92 | to the bottom of the view if the body contents do not fill up 93 | the whole view. Otherwise, the footer will rest below the 94 | body content. 95 | */ 96 | 97 | .footer-to-bottom { 98 | display: flex; 99 | min-height: calc(100vh - 60.59px); /* Total view height - navbar height */ 100 | flex-direction: column; 101 | justify-content: space-between; 102 | } 103 | 104 | a:hover { 105 | color: $color-math-light; 106 | } 107 | -------------------------------------------------------------------------------- /src/App.test.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import React from 'react' 3 | import ReactDOM from 'react-dom' 4 | import App from './App' 5 | 6 | it('renders without crashing', () => { 7 | const div = document.createElement('div') 8 | ReactDOM.render(, div) 9 | ReactDOM.unmountComponentAtNode(div) 10 | }) 11 | -------------------------------------------------------------------------------- /src/components/BlogPostsGroup.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import url from 'url' 3 | import PropTypes from 'prop-types' 4 | import { Card, Col, Row } from 'react-bootstrap' 5 | import BlogSocialLinks from 'components/BlogSocialLinks' 6 | import { BLOG_TYPES, BLOG_ICONS_MAP } from 'content/BlogContent' 7 | import 'components/styles/BlogPostsGroup.scss' 8 | 9 | const getDefaultImage = (type) => 10 | url.resolve(process.env.PUBLIC_URL, `/blog/${BLOG_ICONS_MAP.get(type)}`) 11 | 12 | const BlogTile = ({ color, type, title, image, links }) => { 13 | const imgSrc = image || getDefaultImage(type) 14 | const defaultLink = links.find( 15 | (link) => link.type === 'default' || link.type === 'spotify', 16 | ) 17 | 18 | return ( 19 | 20 | 21 |
22 | 23 |
24 | 25 |
26 |
27 | 28 | {title} 29 | 30 |
31 |
32 | ) 33 | } 34 | 35 | BlogTile.propTypes = { 36 | color: PropTypes.string.isRequired, 37 | type: PropTypes.oneOf(Object.values(BLOG_TYPES)), 38 | title: PropTypes.string.isRequired, 39 | image: PropTypes.string, 40 | links: PropTypes.arrayOf( 41 | PropTypes.shape({ 42 | type: PropTypes.string, 43 | link: PropTypes.oneOf(['default', PropTypes.string]), 44 | }), 45 | ).isRequired, 46 | } 47 | 48 | BlogTile.defaultProps = { 49 | image: null, 50 | } 51 | 52 | const BlogTileRow = ({ blogPosts, color }) => { 53 | if (!blogPosts) return null 54 | return ( 55 | 56 | {blogPosts.map((blog) => ( 57 | 58 | ))} 59 | 60 | ) 61 | } 62 | 63 | BlogTileRow.propTypes = { 64 | blogPosts: PropTypes.arrayOf(PropTypes.object).isRequired, 65 | color: PropTypes.string.isRequired, 66 | } 67 | 68 | class BlogPostsGroup extends Component { 69 | render() { 70 | const { blogPosts, month, color } = this.props 71 | 72 | return ( 73 | 74 | 75 |

{month}

76 | 77 | 78 | 79 | 80 |
81 | ) 82 | } 83 | } 84 | 85 | BlogPostsGroup.propTypes = { 86 | blogPosts: PropTypes.arrayOf(PropTypes.object).isRequired, 87 | month: PropTypes.string.isRequired, 88 | color: PropTypes.string.isRequired, 89 | } 90 | 91 | export default BlogPostsGroup 92 | -------------------------------------------------------------------------------- /src/components/BlogSocialLinks.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import url from 'url' 3 | import PropTypes from 'prop-types' 4 | import 'components/styles/BlogSocialLinks.scss' 5 | 6 | const anchorLogoSrc = url.resolve( 7 | process.env.PUBLIC_URL, 8 | '/blog/anchorfm-logo.png', 9 | ) 10 | 11 | export const LINK_ICON_MAP = { 12 | default: , 13 | spotify: , 14 | apple: , 15 | anchor: Anchor Logo, 16 | rss: , 17 | } 18 | 19 | const BlogSocialLinks = ({ type, links }) => { 20 | if (type === 'Podcast') { 21 | const linksToRender = links.filter(({ type }) => type !== 'default') 22 | return ( 23 |
24 |
25 | {linksToRender.map(({ type, link }) => ( 26 | 27 | {LINK_ICON_MAP[type]} 28 | 29 | ))} 30 |
31 |
32 | ) 33 | } 34 | 35 | const [{ link, type: linkType }] = links 36 | return ( 37 | 42 | ) 43 | } 44 | 45 | BlogSocialLinks.propTypes = { 46 | links: PropTypes.arrayOf( 47 | PropTypes.shape({ 48 | type: PropTypes.string, 49 | link: PropTypes.oneOf(['default', 'spotify', 'apple', 'anchor', 'rss']), 50 | }), 51 | ).isRequired, 52 | type: PropTypes.string.isRequired, 53 | } 54 | 55 | export default BlogSocialLinks 56 | -------------------------------------------------------------------------------- /src/components/ComingSoon.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import url from 'url' 3 | 4 | const logo = url.resolve(process.env.PUBLIC_URL, '/logos/se-logo-trimmed.png') 5 | 6 | class ComingSoon extends Component { 7 | render() { 8 | return ( 9 |
10 |
11 | logo 12 |

Coming soon.

13 |
14 |
15 | ) 16 | } 17 | } 18 | 19 | export default ComingSoon 20 | -------------------------------------------------------------------------------- /src/components/EventCalendar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Row, Col, Button } from 'react-bootstrap' 4 | import { Calendar, momentLocalizer } from 'react-big-calendar' 5 | import Toolbar from 'react-big-calendar/lib/Toolbar' 6 | import Moment from 'moment' 7 | import 'components/styles/ReactBigCalendar.scss' 8 | import 'components/styles/EventCalendar.scss' 9 | 10 | const localizer = momentLocalizer(Moment) 11 | 12 | class CalendarToolbar extends Toolbar { 13 | render() { 14 | let { 15 | localizer: { messages }, 16 | label, 17 | } = this.props 18 | 19 | return ( 20 |
21 | 22 | 23 | 30 | 31 | 32 |
33 | 40 |
{label}
41 | 48 |
49 | 50 | {this.viewNamesGroup(messages)} 51 |
52 |
53 | ) 54 | } 55 | 56 | navigate = (action) => { 57 | this.props.onNavigate(action) 58 | } 59 | 60 | view = (view) => { 61 | this.props.onView(view) 62 | } 63 | 64 | viewNamesGroup(messages) { 65 | let viewNames = this.props.views 66 | 67 | if (viewNames.length > 1) { 68 | return viewNames.map((name) => ( 69 | 77 | )) 78 | } 79 | } 80 | } 81 | 82 | CalendarToolbar.propTypes = { 83 | view: PropTypes.string.isRequired, 84 | views: PropTypes.arrayOf(PropTypes.string).isRequired, 85 | label: PropTypes.node.isRequired, 86 | localizer: PropTypes.object, 87 | onNavigate: PropTypes.func.isRequired, 88 | onView: PropTypes.func.isRequired, 89 | } 90 | 91 | const CalendarEventWrapper = ({ event, children }) => ( 92 | 93 | {children} 94 | 95 | ) 96 | 97 | CalendarEventWrapper.propTypes = { 98 | event: PropTypes.objectOf({ 99 | link: PropTypes.string.isRequired, 100 | }), 101 | children: PropTypes.node.isRequired, 102 | } 103 | 104 | const EventCalendar = (props) => { 105 | return ( 106 | { 109 | event.start = Moment(event.start).toDate() 110 | event.end = Moment(event.end).toDate() 111 | return event 112 | })} 113 | components={{ 114 | eventWrapper: CalendarEventWrapper, 115 | toolbar: CalendarToolbar, 116 | }} 117 | startAccessor="start" 118 | endAccessor="end" 119 | views={['month', 'day']} 120 | defaultDate={Moment().toDate()} 121 | /> 122 | ) 123 | } 124 | 125 | EventCalendar.propTypes = { 126 | events: PropTypes.arrayOf(PropTypes.object).isRequired, 127 | } 128 | 129 | export default EventCalendar 130 | -------------------------------------------------------------------------------- /src/components/EventList.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import PropTypes from 'prop-types' 3 | import url from 'url' 4 | import 'components/styles/EventList.scss' 5 | 6 | const moreEvents = url.resolve( 7 | process.env.PUBLIC_URL, 8 | '/illustrations/more-events.png', 9 | ) 10 | 11 | const Event = (props) => ( 12 |
13 |

14 | {props.event.dateLabel} 15 |
16 | 17 | 18 | {' '} 19 | {props.event.title} 20 | 21 | 22 |

23 |
27 |
28 | ) 29 | 30 | Event.propTypes = { 31 | event: PropTypes.object.isRequired, 32 | } 33 | 34 | class EventList extends Component { 35 | render() { 36 | return ( 37 |
38 |

Upcoming Events

39 | {this.props.upcomingEvents && this.props.upcomingEvents.length ? ( 40 |
41 | 42 | 43 | {this.props.upcomingEvents.map((event, index) => ( 44 | 45 | 48 | 49 | ))} 50 | 51 |
46 | 47 |
52 |
53 | ) : ( 54 |
55 | More events coming soon. 60 |
61 | )} 62 |
63 | ) 64 | } 65 | } 66 | 67 | EventList.propTypes = { 68 | upcomingEvents: PropTypes.arrayOf(PropTypes.object).isRequired, 69 | } 70 | 71 | export default EventList 72 | -------------------------------------------------------------------------------- /src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import PropTypes from 'prop-types' 3 | import 'components/styles/Footer.scss' 4 | 5 | class Footer extends Component { 6 | render() { 7 | return ( 8 |
9 | Have any questions? You can reach us on the{' '} 10 | 16 | SE Society Facebook Page 17 | 18 | , or by email{' '} 19 | 25 | se-soc@uwaterloo.ca 26 | 27 | . 28 |
29 | ) 30 | } 31 | } 32 | 33 | Footer.propTypes = { 34 | color: PropTypes.string.isRequired, 35 | } 36 | 37 | export default Footer 38 | -------------------------------------------------------------------------------- /src/components/Meetings.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Row, Col, Button } from 'react-bootstrap' 4 | import 'components/styles/Meetings.scss' 5 | 6 | const Meeting = (props) => ( 7 | 8 | 9 |

10 | {props.meeting.title} 11 |

12 |

{props.meeting.date}

13 |

{props.meeting.time}

14 |

{props.meeting.location}

15 | 16 | {props.meeting.link ? ( 17 | 18 | 24 | 25 | ) : ( 26 | 27 |

The meeting agenda will be posted soon! Stay tuned.

28 | 29 | )} 30 |
31 | ) 32 | 33 | Meeting.propTypes = { 34 | meeting: PropTypes.object.isRequired, 35 | } 36 | 37 | class Meetings extends Component { 38 | render() { 39 | return ( 40 |
41 | {this.props.meetings.map((meeting) => ( 42 | 43 | ))} 44 | 45 | 46 |

47 | Take a look at our past initiatives by reading our previous 48 | meeting notes. 49 |

50 | 51 | 52 | 60 | 61 |
62 |
63 | ) 64 | } 65 | } 66 | 67 | Meetings.propTypes = { 68 | meetings: PropTypes.arrayOf(PropTypes.object).isRequired, 69 | archiveLink: PropTypes.string.isRequired, 70 | } 71 | 72 | export default Meetings 73 | -------------------------------------------------------------------------------- /src/components/NavigationBar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import url from 'url' 3 | import { Container, Nav, Navbar } from 'react-bootstrap' 4 | import { Link, NavLink, useLocation } from 'react-router-dom' 5 | import 'components/styles/NavigationBar.scss' 6 | 7 | const logo = url.resolve( 8 | process.env.PUBLIC_URL, 9 | '/logos/se-logo-trimmed-transparent-bw.png', 10 | ) 11 | 12 | const NavigationBar = () => { 13 | let location = useLocation() 14 | let color = '' 15 | switch (location.pathname) { 16 | case '/': 17 | color = '#F0EDF1' 18 | break 19 | default: 20 | color = 'transparent' 21 | break 22 | } 23 | 24 | return ( 25 | 26 | 27 | 28 | SE Society 34 | 35 | 101 | 102 | ) 103 | } 104 | 105 | // Props from withRouter HOC 106 | NavigationBar.propTypes = {} 107 | 108 | export default NavigationBar 109 | -------------------------------------------------------------------------------- /src/components/NewsList.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import 'components/styles/NewsList.scss' 4 | 5 | const NewsContent = (props) => { 6 | const numEntries = props.numEntries ? props.numEntries : props.articles.length 7 | 8 | return props.articles.slice(0, numEntries).map((article) => ( 9 | 10 | 11 | 12 |

{article.title}

13 |

{article.description}

14 |
15 | 16 | 17 | )) 18 | } 19 | 20 | const NewsList = (props) => ( 21 |
22 |

news

23 | 24 |
25 | ) 26 | 27 | NewsList.propTypes = { 28 | articles: PropTypes.arrayOf({ 29 | link: PropTypes.string.isRequired, 30 | title: PropTypes.string.isRequired, 31 | description: PropTypes.string.isRequired, 32 | }), 33 | numEntries: PropTypes.number, 34 | } 35 | 36 | export default NewsList 37 | -------------------------------------------------------------------------------- /src/components/Platform.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import React, { Component } from 'react' 3 | import PropTypes from 'prop-types' 4 | 5 | function Points(props) { 6 | const listItems = props.points.map((point) => ( 7 |
  • 8 |

    {point}

    9 |
  • 10 | )) 11 | return ( 12 |
    13 |

    Goals:

    14 |
      {listItems}
    15 |
    16 | ) 17 | } 18 | 19 | function Picture(props) { 20 | return ( 21 |
    22 |
    23 |
    24 | {`${props.name}'s 29 |
    30 |
    31 |
    32 | ) 33 | } 34 | 35 | function Achievements(props) { 36 | if (props.achievements) { 37 | const listItems = props.achievements.map((achievement) => ( 38 |
  • 39 |

    {achievement}

    40 |
  • 41 | )) 42 | return ( 43 |
    44 |

    Achievements:

    45 |
      {listItems}
    46 |
    47 | ) 48 | } else { 49 | return
    50 | } 51 | } 52 | 53 | class Platform extends Component { 54 | render() { 55 | return ( 56 |
    57 |

    58 | {'Candidates for ' + this.props.platform.candidacy} 59 |

    60 | 61 |
    62 |
    63 |

    {this.props.platform.name}

    64 | 68 |
    69 | 70 |
    71 |

    {this.props.platform.platform}

    72 |
    73 | 74 | 75 | 76 |
    77 |
    78 | ) 79 | } 80 | } 81 | 82 | Platform.propTypes = { 83 | platform: PropTypes.shape({ 84 | name: PropTypes.string.isRequired, 85 | candidacy: PropTypes.string.isRequired, 86 | platform: PropTypes.string.isRequired, 87 | quote: PropTypes.string.isRequired, 88 | points: PropTypes.arrayOf(PropTypes.string.isRequired), 89 | contacts: PropTypes.shape({ 90 | facebook: PropTypes.string, 91 | email: PropTypes.string, 92 | }), 93 | image: PropTypes.string.isRequired, 94 | achievements: PropTypes.arrayOf(PropTypes.string), 95 | }), 96 | } 97 | 98 | export default Platform 99 | -------------------------------------------------------------------------------- /src/components/ProfilePhotoGroup.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Card, Col, Row } from 'react-bootstrap' 4 | import 'components/styles/ProfilePhotoGroup.scss' 5 | 6 | const Image = (props) => ( 7 | 8 | 9 | 13 | 14 | {props.person.name} 15 |
    16 | {props.person.year} 17 |
    18 | {props.person.position} 19 |
    20 |
    21 | 22 |
    23 | 24 | ) 25 | 26 | Image.propTypes = { 27 | color: PropTypes.string.isRequired, 28 | person: PropTypes.object.isRequired, 29 | } 30 | 31 | const ImageRow = (props) => { 32 | const listItems = props.people 33 | ? props.people.map((person) => ( 34 | 35 | )) 36 | : null 37 | return listItems 38 | } 39 | 40 | class ProfilePhotoGroup extends Component { 41 | render() { 42 | const execs = this.props.execs 43 | const reps = this.props.reps 44 | const soc = this.props.soc 45 | const color = this.props.color 46 | return ( 47 |
    48 | {reps && reps.length ? ( 49 | <> 50 |

    {soc}

    51 |
    Execs
    52 | 53 | ) : ( 54 |

    {soc} Execs

    55 | )} 56 | 57 | 58 | 59 | {reps && reps.length ?
    Reps
    : null} 60 | {reps && reps.length ? ( 61 | 62 | 63 | 64 | ) : null} 65 |
    66 | ) 67 | } 68 | } 69 | 70 | ProfilePhotoGroup.propTypes = { 71 | soc: PropTypes.string.isRequired, 72 | execs: PropTypes.arrayOf(PropTypes.object).isRequired, 73 | reps: PropTypes.arrayOf(PropTypes.object).isRequired, 74 | color: PropTypes.string.isRequired, 75 | } 76 | 77 | export default ProfilePhotoGroup 78 | -------------------------------------------------------------------------------- /src/components/PromptActionButtons.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Button } from 'react-bootstrap' 4 | import 'components/styles/PromptActionButtons.scss' 5 | 6 | // Prompt Text + Action Button 7 | // eg. Have an event in mind? [Suggest an Event] 8 | const Action = (props) => ( 9 | <> 10 |

    {props.action.prompt}

    11 | 19 | 20 | ) 21 | 22 | Action.propTypes = { 23 | action: PropTypes.object.isRequired, 24 | } 25 | 26 | class PromptActionButtons extends Component { 27 | render() { 28 | return ( 29 |
    30 | {this.props.actions.map((action, index) => ( 31 | 32 | ))} 33 |
    34 | ) 35 | } 36 | } 37 | 38 | PromptActionButtons.propTypes = { 39 | actions: PropTypes.arrayOf(PropTypes.object).isRequired, 40 | } 41 | 42 | export default PromptActionButtons 43 | -------------------------------------------------------------------------------- /src/components/styles/BlogPostsGroup.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/_colors'; 2 | 3 | .blog-month { 4 | text-align: center; 5 | padding-top: 6.5rem; 6 | } 7 | 8 | .blog-row { 9 | display: grid; 10 | margin: 0; 11 | grid-template-columns: repeat(3, 1fr); 12 | grid-gap: 40px; 13 | margin-bottom: 40px; 14 | } 15 | 16 | .card { 17 | border-radius: 6px; 18 | overflow: hidden; 19 | border-width: 0px; 20 | width: 100%; 21 | height: 100%; 22 | padding: 0; 23 | margin: 0; 24 | 25 | a { 26 | text-decoration: none; 27 | height: 100%; 28 | display: flex; 29 | flex-direction: column; 30 | justify-content: center; 31 | } 32 | } 33 | 34 | .card-img-container { 35 | position: relative; 36 | } 37 | 38 | .card-img-hover { 39 | opacity: 0; 40 | position: absolute; 41 | top: 0; 42 | height: 100%; 43 | width: 100%; 44 | transition: 0.5s ease; 45 | background: rgba(0, 0, 0, 0.7); 46 | } 47 | 48 | .card-img-container:hover .card-img-hover { 49 | opacity: 1; 50 | } 51 | 52 | .card-img { 53 | padding: 0px; 54 | margin: 0px; 55 | object-fit: cover; 56 | object-position: center; 57 | max-height: 200px; 58 | width: 100%; 59 | border-radius: 0; 60 | } 61 | 62 | .card-body { 63 | padding: 10px 14px !important; 64 | margin: 0 !important; 65 | background-color: $color-eng; 66 | color: white; 67 | text-align: left; 68 | align-items: center; 69 | display: flex; 70 | font-size: 14px; 71 | line-height: 20px; 72 | height: calc(100% - height('.card-img')); 73 | } 74 | 75 | @media screen and (max-width: 991px) { 76 | .blog-row { 77 | grid-template-columns: repeat(2, 1fr); 78 | grid-gap: 30px; 79 | margin-bottom: 30px; 80 | } 81 | 82 | .card-body { 83 | font-size: 12px; 84 | } 85 | } 86 | 87 | @media screen and (max-width: 768px) { 88 | .blog-month { 89 | text-align: left; 90 | padding: 1rem 0; 91 | } 92 | 93 | .card-img { 94 | max-height: 140px; 95 | } 96 | } 97 | 98 | @media screen and (max-width: 370px) { 99 | .blog-row { 100 | grid-template-columns: 1fr; 101 | grid-gap: 20px; 102 | margin-bottom: 20px; 103 | } 104 | 105 | .card-img { 106 | max-height: 200px; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/components/styles/BlogSocialLinks.scss: -------------------------------------------------------------------------------- 1 | .social-links-container { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | width: 100%; 6 | height: 100%; 7 | 8 | a { 9 | color: white !important; 10 | } 11 | 12 | .fab, .fas { 13 | font-size: 40px; 14 | } 15 | 16 | img { 17 | max-height: 40px; 18 | width: auto; 19 | } 20 | } 21 | 22 | .social-links-grid { 23 | display: grid; 24 | grid-template-columns: auto auto; 25 | grid-gap: 20px; 26 | justify-content: center; 27 | align-items: center; 28 | } -------------------------------------------------------------------------------- /src/components/styles/EventCalendar.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/_colors'; 2 | .cal-c { 3 | margin-top: 25px; 4 | margin-bottom: 20px; 5 | } 6 | 7 | .cal-tb-btn { 8 | background-color: white; 9 | color: white; 10 | } 11 | 12 | .cal-tb-nav { 13 | width: fit-content; 14 | margin-left: auto; 15 | margin-right: auto; 16 | display: table; 17 | } 18 | 19 | .cal-date { 20 | display: table-cell; 21 | text-align: center; 22 | color: $color-eng; 23 | } 24 | 25 | .cal-tb-nav-bf { 26 | background-color: white; 27 | color: $color-eng; 28 | border-width: 0px; 29 | } 30 | 31 | .cal-tb-btn { 32 | background-color: white; 33 | color: $color-eng; 34 | border-width: 0px; 35 | } 36 | 37 | .cal-tb-btn:hover { 38 | background-color: $color-eng-lightest; 39 | color: $color-eng; 40 | border-width: 0px; 41 | } 42 | -------------------------------------------------------------------------------- /src/components/styles/EventList.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/_colors'; 2 | .event-list tr .accent { 3 | color: $color-eng; 4 | } 5 | 6 | .event { 7 | padding-bottom: 20px; 8 | } 9 | 10 | .event-title { 11 | margin-bottom: 0px; 12 | } 13 | 14 | .scroll { 15 | height: auto; 16 | max-height: 525px; 17 | padding-right: 10px; 18 | overflow-y: auto; 19 | display: block; 20 | padding-bottom: 30px; 21 | } 22 | 23 | .fade-in-bottom { 24 | position: relative; 25 | } 26 | 27 | .fade-in-bottom:after { 28 | content: ''; 29 | position: absolute; 30 | z-index: 1; 31 | bottom: 0; 32 | pointer-events: none; 33 | background-image: linear-gradient( 34 | to bottom, 35 | rgba(255, 255, 255, 0), 36 | rgba(255, 255, 255, 1) 90% 37 | ); 38 | width: 100%; 39 | height: 3em; 40 | } 41 | 42 | #empty-event-list { 43 | display: flex; 44 | height: 400px; 45 | align-items: center; 46 | } 47 | 48 | #more-events { 49 | width: 80%; 50 | } 51 | 52 | @media screen and (max-width: 991px) { 53 | #empty-event-list { 54 | justify-content: center; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/components/styles/Footer.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/_colors'; 2 | 3 | .footer { 4 | padding: 20px; 5 | text-align: center; 6 | color: white; 7 | } 8 | 9 | .link { 10 | color: white; 11 | } 12 | 13 | .theme { 14 | &-purple { 15 | background-color: $color-eng; 16 | a:hover { 17 | color: $color-math-light; 18 | } 19 | } 20 | &-pink { 21 | background-color: $color-math; 22 | a:hover { 23 | color: $color-eng; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/components/styles/Meetings.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/_colors'; 2 | .col-height { 3 | height: 400px; 4 | } 5 | 6 | .meeting-pdf { 7 | height: 100%; 8 | width: 100%; 9 | border-radius: 4px; 10 | border-color: lightgrey; 11 | border-style: solid; 12 | } 13 | 14 | .no-bottom-space { 15 | margin-bottom: 0; 16 | } 17 | 18 | .bold { 19 | font-weight: bold; 20 | } 21 | 22 | .colour { 23 | &-upcoming { 24 | color: $color-math; 25 | } 26 | &-previous { 27 | color: black; 28 | } 29 | } 30 | 31 | .archive-btn { 32 | float: right; 33 | background-color: lightgrey; 34 | border-width: 0px; 35 | margin-bottom: 3px; 36 | } 37 | 38 | .archive-btn:hover, 39 | .archive-btn:focus, 40 | .archive-btn:active { 41 | background-color: $color-math; 42 | color: white; 43 | } 44 | 45 | .archive-row { 46 | display: flex; 47 | align-items: center; 48 | } 49 | -------------------------------------------------------------------------------- /src/components/styles/NavigationBar.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/_colors'; 2 | 3 | .navbar-nav a.nav-link.active:nth-child(odd) { 4 | color: $color-eng; 5 | } 6 | 7 | .navbar-nav a.nav-link.active:nth-child(even) { 8 | color: $color-math; 9 | } 10 | -------------------------------------------------------------------------------- /src/components/styles/NewsList.scss: -------------------------------------------------------------------------------- 1 | .news-list tr:nth-child(odd) .accent { 2 | color: var(--color-eng); 3 | } 4 | 5 | .news-list tr:nth-child(even) .accent { 6 | color: var(--color-math); 7 | } 8 | -------------------------------------------------------------------------------- /src/components/styles/ProfilePhotoGroup.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/_colors'; 2 | .society-profiles { 3 | margin-top: 30px; 4 | } 5 | 6 | @media screen and (min-width: 462px) { 7 | .card { 8 | font-size: calc(14px); 9 | line-height: calc(1.1em + 0.5vw); 10 | } 11 | } 12 | 13 | .card-img { 14 | max-height: 100% !important; 15 | } 16 | 17 | @media screen and (max-width: 461px) { 18 | .card { 19 | font-size: calc(9px + 0.25vw); 20 | line-height: calc(1.1em + 0.5vw); 21 | } 22 | } 23 | 24 | .card { 25 | padding-left: 15px; 26 | border-width: 0px; 27 | width: 100%; 28 | } 29 | 30 | .card-header { 31 | padding-top: 10px; 32 | padding-bottom: 10px; 33 | background-color: $color-eng; 34 | } 35 | 36 | .card-full-width { 37 | width: 100%; 38 | } 39 | 40 | .card-text { 41 | color: white; 42 | text-align: left; 43 | } 44 | -------------------------------------------------------------------------------- /src/components/styles/PromptActionButtons.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/_colors'; 2 | 3 | .action-grid { 4 | display: grid; 5 | grid-template-columns: auto min-content; 6 | grid-gap: 20px 10px; 7 | align-items: center; 8 | } 9 | 10 | .no-bottom-space { 11 | margin-bottom: 0; 12 | } 13 | 14 | .way-btn { 15 | float: right; 16 | background-color: $color-math; 17 | border-width: 0px; 18 | } 19 | 20 | .way-btn:hover { 21 | background-color: $color-math-light; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/styles/ReactBigCalendar.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @import 'styles/_colors'; 3 | /* Component colors */ 4 | $color-dates: $color-eng; 5 | $color-dates-invalid: $color-eng-light; 6 | $color-current-day: $color-eng-lightest; 7 | $color-event: $color-math; 8 | $color-event-selected: $color-math-light; 9 | $color-date-view-grid: $color-eng-light; 10 | $color-current-time: $color-math; 11 | span { 12 | font-weight: 300; 13 | } 14 | 15 | .rbc-btn { 16 | color: inherit; 17 | font: inherit; 18 | margin: 0; 19 | } 20 | 21 | button.rbc-btn { 22 | overflow: visible; 23 | text-transform: none; 24 | -webkit-appearance: button; 25 | cursor: pointer; 26 | } 27 | 28 | button[disabled].rbc-btn { 29 | cursor: not-allowed; 30 | } 31 | 32 | button.rbc-input::-moz-focus-inner { 33 | border: 0; 34 | padding: 0; 35 | } 36 | 37 | .rbc-calendar { 38 | box-sizing: border-box; 39 | height: 100%; 40 | display: flex; 41 | flex-direction: column; 42 | align-items: stretch; 43 | } 44 | 45 | .rbc-calendar *, 46 | .rbc-calendar *:before, 47 | .rbc-calendar *:after { 48 | box-sizing: inherit; 49 | } 50 | 51 | .rbc-abs-full, 52 | .rbc-row-bg { 53 | overflow: hidden; 54 | position: absolute; 55 | top: 0; 56 | left: 0; 57 | right: 0; 58 | bottom: 0; 59 | } 60 | 61 | .rbc-ellipsis, 62 | .rbc-event-label, 63 | .rbc-row-segment .rbc-event-content, 64 | .rbc-show-more { 65 | display: block; 66 | overflow: hidden; 67 | text-overflow: ellipsis; 68 | white-space: nowrap; 69 | } 70 | 71 | .rbc-rtl { 72 | direction: rtl; 73 | } 74 | 75 | .rbc-off-range { 76 | color: $color-dates-invalid; 77 | } 78 | 79 | .rbc-off-range-bg { 80 | background: #ffffff; 81 | } 82 | 83 | .rbc-header { 84 | overflow: hidden; 85 | flex: 1 0 0%; 86 | text-overflow: ellipsis; 87 | white-space: nowrap; 88 | padding: 0 3px; 89 | text-align: left; 90 | vertical-align: middle; 91 | font-weight: bold; 92 | font-size: 90%; 93 | min-height: 0; 94 | /* border-bottom: 1px solid #DDD; */ 95 | margin-bottom: 5px; 96 | } 97 | 98 | .rbc-header + .rbc-header { 99 | /* border-left: 1px solid #DDD; */ 100 | } 101 | 102 | .rbc-rtl .rbc-header + .rbc-header { 103 | border-left-width: 0; 104 | /* border-right: 1px solid #DDD; */ 105 | } 106 | 107 | .rbc-header > a, 108 | .rbc-header > a:active, 109 | .rbc-header > a:visited { 110 | color: inherit; 111 | text-decoration: none; 112 | } 113 | 114 | .rbc-row-content { 115 | position: relative; 116 | user-select: none; 117 | -webkit-user-select: none; 118 | z-index: 4; 119 | } 120 | 121 | .rbc-today { 122 | background-color: $color-current-day; 123 | } 124 | 125 | .rbc-toolbar { 126 | display: flex; 127 | flex-wrap: wrap; 128 | justify-content: center; 129 | align-items: center; 130 | margin-bottom: 10px; 131 | font-size: 16px; 132 | } 133 | 134 | .rbc-toolbar .rbc-toolbar-label { 135 | flex-grow: 1; 136 | padding: 0 10px; 137 | text-align: center; 138 | } 139 | 140 | .rbc-toolbar button { 141 | padding: 0.375rem 1rem; 142 | margin-right: 5px; 143 | border-radius: 0px; 144 | line-height: normal; 145 | white-space: nowrap; 146 | color: #fff; 147 | background-color: #6c757d; 148 | border-color: #6c757d; 149 | user-select: none; 150 | border: 1px solid transparent; 151 | padding: 0.375rem 0.75rem; 152 | font-size: 1rem; 153 | line-height: 1.5; 154 | border-radius: 0.25rem; 155 | transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, 156 | border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; 157 | display: inline-block; 158 | font-weight: 400; 159 | text-align: center; 160 | white-space: nowrap; 161 | vertical-align: middle; 162 | } 163 | 164 | .rbc-toolbar button:active, 165 | .rbc-toolbar button.rbc-active { 166 | color: #fff; 167 | background-color: #6c757d; 168 | border-color: #6c757d; 169 | } 170 | 171 | .rbc-toolbar button:active:hover, 172 | .rbc-toolbar button:active:focus, 173 | .rbc-toolbar button.rbc-active:focus { 174 | color: #fff; 175 | background-color: #343a40; 176 | border-color: #343a40; 177 | } 178 | 179 | .rbc-toolbar button:focus { 180 | color: #fff; 181 | background-color: #343a40; 182 | border-color: #343a40; 183 | } 184 | 185 | .rbc-toolbar button:hover, 186 | .rbc-toolbar button.rbc-active:hover { 187 | color: #fff; 188 | background-color: #343a40; 189 | border-color: #343a40; 190 | } 191 | 192 | .rbc-btn-group { 193 | display: inline-block; 194 | white-space: nowrap; 195 | } 196 | 197 | .rbc-btn-group button + button { 198 | margin-left: -1px; 199 | } 200 | 201 | .rbc-rtl .rbc-btn-group button + button { 202 | margin-left: 0; 203 | margin-right: -1px; 204 | } 205 | 206 | .rbc-btn-group + .rbc-btn-group, 207 | .rbc-btn-group + button { 208 | margin-left: 10px; 209 | } 210 | 211 | .rbc-event { 212 | border: none; 213 | box-sizing: border-box; 214 | box-shadow: none; 215 | margin: 3px; 216 | padding: 2px 5px; 217 | background-color: $color-event; 218 | border-radius: 3px; 219 | color: #fff; 220 | cursor: pointer; 221 | width: 100%; 222 | text-align: left; 223 | font-size: 12px; 224 | } 225 | 226 | .rbc-slot-selecting .rbc-event { 227 | cursor: inherit; 228 | pointer-events: none; 229 | } 230 | 231 | .rbc-event.rbc-selected { 232 | background-color: $color-event-selected; 233 | } 234 | 235 | .rbc-event:focus { 236 | outline: 5px auto #3b99fc; 237 | } 238 | 239 | .rbc-event-label { 240 | font-size: 80%; 241 | } 242 | 243 | .rbc-event-overlaps { 244 | box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5); 245 | } 246 | 247 | .rbc-event-continues-prior { 248 | border-top-left-radius: 0; 249 | border-bottom-left-radius: 0; 250 | } 251 | 252 | .rbc-event-continues-after { 253 | border-top-right-radius: 0; 254 | border-bottom-right-radius: 0; 255 | } 256 | 257 | .rbc-event-continues-earlier { 258 | border-top-left-radius: 0; 259 | border-top-right-radius: 0; 260 | } 261 | 262 | .rbc-event-continues-later { 263 | border-bottom-left-radius: 0; 264 | border-bottom-right-radius: 0; 265 | } 266 | 267 | .rbc-row { 268 | display: flex; 269 | flex-direction: row; 270 | } 271 | 272 | .rbc-row-segment { 273 | padding: 0 1px 1px 1px; 274 | } 275 | 276 | .rbc-selected-cell { 277 | background-color: rgba(0, 0, 0, 0.1); 278 | } 279 | 280 | .rbc-show-more { 281 | background-color: rgba(255, 255, 255, 0.3); 282 | z-index: 4; 283 | font-weight: bold; 284 | font-size: 85%; 285 | height: auto; 286 | line-height: normal; 287 | } 288 | 289 | .rbc-month-view { 290 | position: relative; 291 | /* border: 1px solid #DDD; */ 292 | display: flex; 293 | flex-direction: column; 294 | flex: 1 0 0; 295 | width: 100%; 296 | user-select: none; 297 | -webkit-user-select: none; 298 | height: 100%; 299 | } 300 | 301 | .rbc-month-header { 302 | display: flex; 303 | flex-direction: row; 304 | } 305 | 306 | .rbc-month-row { 307 | display: flex; 308 | position: relative; 309 | flex-direction: column; 310 | flex: 1 0 0; 311 | flex-basis: 0px; 312 | overflow: hidden; 313 | height: 100%; 314 | color: $color-dates; 315 | } 316 | 317 | .rbc-month-row + .rbc-month-row { 318 | /* border-top: 1px solid #DDD; */ 319 | } 320 | 321 | .rbc-date-cell { 322 | flex: 1 1; 323 | min-width: 0; 324 | padding-left: 3px; 325 | text-align: left; 326 | font-weight: 300; 327 | } 328 | 329 | .rbc-date-cell.rbc-now { 330 | font-weight: bold; 331 | } 332 | 333 | .rbc-date-cell > a, 334 | .rbc-date-cell > a:active, 335 | .rbc-date-cell > a:visited { 336 | color: inherit; 337 | text-decoration: none; 338 | } 339 | 340 | .rbc-row-bg { 341 | display: flex; 342 | flex-direction: row; 343 | flex: 1 0; 344 | overflow: hidden; 345 | } 346 | 347 | .rbc-day-bg { 348 | flex: 1 0 0%; 349 | } 350 | 351 | .rbc-day-bg + .rbc-day-bg { 352 | /* border-left: 1px solid #DDD; */ 353 | } 354 | 355 | .rbc-rtl .rbc-day-bg + .rbc-day-bg { 356 | border-left-width: 0; 357 | /* border-right: 1px solid #DDD; */ 358 | } 359 | 360 | .rbc-overlay { 361 | position: absolute; 362 | z-index: 5; 363 | border: 1px solid #e5e5e5; 364 | background-color: #fff; 365 | box-shadow: 0 5px 15px rgba(0, 0, 0, 0.25); 366 | padding: 10px; 367 | } 368 | 369 | .rbc-overlay > * + * { 370 | margin-top: 1px; 371 | } 372 | 373 | .rbc-overlay-header { 374 | border-bottom: 1px solid #e5e5e5; 375 | margin: -10px -10px 5px -10px; 376 | padding: 2px 10px; 377 | } 378 | 379 | .rbc-agenda-view { 380 | display: flex; 381 | flex-direction: column; 382 | flex: 1 0 0; 383 | overflow: auto; 384 | } 385 | 386 | .rbc-agenda-view table.rbc-agenda-table { 387 | width: 100%; 388 | border: 1px solid #ddd; 389 | border-spacing: 0; 390 | border-collapse: collapse; 391 | } 392 | 393 | .rbc-agenda-view table.rbc-agenda-table tbody > tr > td { 394 | padding: 5px 10px; 395 | vertical-align: top; 396 | } 397 | 398 | .rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell { 399 | padding-left: 15px; 400 | padding-right: 15px; 401 | text-transform: lowercase; 402 | } 403 | 404 | .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td { 405 | border-left: 1px solid $color-date-view-grid; 406 | } 407 | 408 | .rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td { 409 | border-left-width: 0; 410 | border-right: 1px solid $color-date-view-grid; 411 | } 412 | 413 | .rbc-agenda-view table.rbc-agenda-table tbody > tr + tr { 414 | border-top: 1px solid $color-date-view-grid; 415 | } 416 | 417 | .rbc-agenda-view table.rbc-agenda-table thead > tr > th { 418 | padding: 3px 5px; 419 | text-align: left; 420 | border-bottom: 1px solid $color-date-view-grid; 421 | } 422 | 423 | .rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th { 424 | text-align: right; 425 | } 426 | 427 | .rbc-agenda-time-cell { 428 | text-transform: lowercase; 429 | } 430 | 431 | .rbc-agenda-time-cell .rbc-continues-after:after { 432 | content: ' »'; 433 | } 434 | 435 | .rbc-agenda-time-cell .rbc-continues-prior:before { 436 | content: '« '; 437 | } 438 | 439 | .rbc-agenda-date-cell, 440 | .rbc-agenda-time-cell { 441 | white-space: nowrap; 442 | } 443 | 444 | .rbc-agenda-event-cell { 445 | width: 100%; 446 | } 447 | 448 | .rbc-time-column { 449 | display: flex; 450 | flex-direction: column; 451 | min-height: 100%; 452 | } 453 | 454 | .rbc-time-column .rbc-timeslot-group { 455 | flex: 1; 456 | } 457 | 458 | .rbc-timeslot-group { 459 | border-bottom: 1px solid $color-date-view-grid; 460 | min-height: 40px; 461 | display: flex; 462 | flex-flow: column nowrap; 463 | } 464 | 465 | .rbc-time-gutter, 466 | .rbc-header-gutter { 467 | flex: none; 468 | } 469 | 470 | .rbc-label { 471 | padding: 0 5px; 472 | } 473 | 474 | .rbc-day-slot { 475 | position: relative; 476 | } 477 | 478 | .rbc-day-slot .rbc-events-container { 479 | bottom: 0; 480 | left: 0; 481 | position: absolute; 482 | right: 0; 483 | margin-right: 10px; 484 | top: 0; 485 | } 486 | 487 | .rbc-day-slot .rbc-events-container.rbc-rtl { 488 | left: 10px; 489 | right: 0; 490 | } 491 | 492 | .rbc-day-slot .rbc-event { 493 | border: 0px solid $color-event; 494 | display: flex; 495 | max-height: 100%; 496 | min-height: 20px; 497 | flex-flow: column wrap; 498 | align-items: flex-start; 499 | overflow: hidden; 500 | position: absolute; 501 | } 502 | 503 | .rbc-day-slot .rbc-event-label { 504 | flex: none; 505 | padding-right: 5px; 506 | width: auto; 507 | } 508 | 509 | .rbc-day-slot .rbc-event-content { 510 | width: 100%; 511 | flex: 1 1 0; 512 | word-wrap: break-word; 513 | line-height: 1; 514 | height: 100%; 515 | min-height: 1em; 516 | } 517 | 518 | .rbc-day-slot .rbc-time-slot { 519 | border-top: 0px solid #f7f7f7; 520 | } 521 | 522 | .rbc-time-view-resources .rbc-time-gutter, 523 | .rbc-time-view-resources .rbc-time-header-gutter { 524 | position: sticky; 525 | left: 0; 526 | background-color: white; 527 | border-right: 1px solid $color-date-view-grid; 528 | z-index: 10; 529 | margin-right: -1px; 530 | } 531 | 532 | .rbc-time-view-resources .rbc-time-header { 533 | overflow: hidden; 534 | } 535 | 536 | .rbc-time-view-resources .rbc-time-header-content { 537 | min-width: auto; 538 | flex: 1 0 0; 539 | flex-basis: 0px; 540 | } 541 | 542 | .rbc-time-view-resources .rbc-time-header-cell-single-day { 543 | display: none; 544 | } 545 | 546 | .rbc-time-view-resources .rbc-day-slot { 547 | min-width: 140px; 548 | } 549 | 550 | .rbc-time-view-resources .rbc-header, 551 | .rbc-time-view-resources .rbc-day-bg { 552 | width: 140px; 553 | flex: 1 1 0; 554 | flex-basis: 0 px; 555 | } 556 | 557 | .rbc-time-header-content + .rbc-time-header-content { 558 | margin-left: -1px; 559 | } 560 | 561 | .rbc-time-slot { 562 | flex: 1 0 0; 563 | } 564 | 565 | .rbc-time-slot.rbc-now { 566 | font-weight: bold; 567 | } 568 | 569 | .rbc-day-header { 570 | text-align: center; 571 | } 572 | 573 | .rbc-slot-selection { 574 | z-index: 10; 575 | position: absolute; 576 | background-color: rgba(0, 0, 0, 0.5); 577 | color: white; 578 | font-size: 75%; 579 | width: 100%; 580 | padding: 3px; 581 | } 582 | 583 | .rbc-slot-selecting { 584 | cursor: move; 585 | } 586 | 587 | .rbc-time-view { 588 | display: flex; 589 | flex-direction: column; 590 | flex: 1; 591 | width: 100%; 592 | border: 0px solid #ddd; 593 | min-height: 0; 594 | } 595 | 596 | .rbc-time-view .rbc-time-gutter { 597 | white-space: nowrap; 598 | } 599 | 600 | .rbc-time-view .rbc-allday-cell { 601 | box-sizing: content-box; 602 | width: 100%; 603 | height: 100%; 604 | position: relative; 605 | } 606 | 607 | .rbc-time-view .rbc-allday-cell + .rbc-allday-cell { 608 | border-left: 1px solid #ddd; 609 | } 610 | 611 | .rbc-time-view .rbc-allday-events { 612 | position: relative; 613 | z-index: 4; 614 | } 615 | 616 | .rbc-time-view .rbc-row { 617 | box-sizing: border-box; 618 | min-height: 20px; 619 | } 620 | 621 | .rbc-time-header { 622 | display: flex; 623 | flex: 0 0 auto; 624 | flex-direction: row; 625 | } 626 | 627 | .rbc-time-header.rbc-overflowing { 628 | border-right: 0px solid #ddd; 629 | } 630 | 631 | .rbc-rtl .rbc-time-header.rbc-overflowing { 632 | border-right-width: 0; 633 | border-left: 1px solid #ddd; 634 | } 635 | 636 | .rbc-time-header > .rbc-row:first-child { 637 | border-bottom: 1px solid #ddd; 638 | } 639 | 640 | .rbc-time-header > .rbc-row.rbc-row-resource { 641 | border-bottom: 1px solid #ddd; 642 | } 643 | 644 | .rbc-time-header-cell-single-day { 645 | display: none; 646 | } 647 | 648 | .rbc-time-header-content { 649 | flex: 1; 650 | display: flex; 651 | min-width: 0; 652 | flex-direction: column; 653 | border-left: 1px solid $color-date-view-grid; 654 | } 655 | 656 | .rbc-rtl .rbc-time-header-content { 657 | border-left-width: 0; 658 | border-right: 1px solid $color-date-view-grid; 659 | } 660 | 661 | .rbc-time-header-content > .rbc-row.rbc-row-resource { 662 | border-bottom: 1px solid $color-date-view-grid; 663 | flex-shrink: 0; 664 | } 665 | 666 | .rbc-time-content { 667 | display: flex; 668 | flex: 1 0 0%; 669 | align-items: flex-start; 670 | width: 100%; 671 | border-top: 2px solid $color-date-view-grid; 672 | overflow-y: auto; 673 | position: relative; 674 | } 675 | 676 | .rbc-time-content > .rbc-time-gutter { 677 | flex: none; 678 | } 679 | 680 | .rbc-time-content > * + * > * { 681 | border-left: 1px solid $color-date-view-grid; 682 | } 683 | 684 | .rbc-rtl .rbc-time-content > * + * > * { 685 | border-left-width: 0; 686 | border-right: 1px solid $color-date-view-grid; 687 | } 688 | 689 | .rbc-time-content > .rbc-day-slot { 690 | width: 100%; 691 | user-select: none; 692 | -webkit-user-select: none; 693 | } 694 | 695 | .rbc-current-time-indicator { 696 | position: absolute; 697 | z-index: 3; 698 | left: 0; 699 | right: 0; 700 | height: 1px; 701 | background-color: $color-current-time; 702 | pointer-events: none; 703 | } 704 | -------------------------------------------------------------------------------- /src/containers/About.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Container } from 'react-bootstrap' 3 | import ProfilePhotoGroup from 'components/ProfilePhotoGroup' 4 | import Footer from 'components/Footer' 5 | import url from 'url' 6 | 7 | const profileImage = (name) => 8 | url.resolve(process.env.PUBLIC_URL, `/profiles/${name}.jpg`) 9 | 10 | class About extends Component { 11 | render() { 12 | return ( 13 |
    14 | 15 | 16 |

    What is SE Soc?

    17 |

    18 | Software Engineering Society (SE Soc) is a council that runs 19 | community initiatives within the SE program. Through class and 20 | program-wide events, such as game nights, online events, virtual 21 | dinners and coffee chats, we hope you get to meet all the other 22 | brilliant people in SE! We also run resume critiques and interview 23 | prep sessions, hosted by upper years, to help you get a better 24 | shot at the jobs you want. You can listen to a highlight of the 25 | cool stuff that everyone in SE is up to through our podcast, 26 | Sessions by SE. 27 |

    28 | 29 |

    Meet The Team

    30 |

    31 | A-Soc represents the even years (SE2022, SE2024, SE2026) and 32 | B-Soc represents the odd years (SE2023, SE2025). We’re a 33 | friendly bunch, feel free to say hi if we ever bump into each 34 | other online or on campus! 35 |

    36 | 67 | 92 |
    93 |
    94 | 95 |
    96 |
    97 | ) 98 | } 99 | } 100 | 101 | export default About 102 | -------------------------------------------------------------------------------- /src/containers/Blog.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Container } from 'react-bootstrap' 3 | import Moment from 'moment' 4 | import groupBy from 'lodash/groupBy' 5 | import map from 'lodash/map' 6 | import flow from 'lodash/flow' 7 | import partialRight from 'lodash/partialRight' 8 | import orderBy from 'lodash/orderBy' 9 | 10 | import Footer from 'components/Footer' 11 | import BlogPostsGroup from 'components/BlogPostsGroup' 12 | import { blogPosts } from 'content/BlogContent.js' 13 | import 'App.scss' 14 | 15 | const getDate = (date, dateFn = (date) => date) => { 16 | return dateFn(Moment.unix(date)) 17 | } 18 | 19 | const formatPostsByDate = (blogPosts, dateFn, sortOrder) => 20 | flow([ 21 | partialRight(groupBy, (post) => getDate(post.date, dateFn)), 22 | partialRight(map, (posts, key) => [key, posts]), 23 | partialRight(orderBy, 0, sortOrder), 24 | ])(blogPosts) 25 | 26 | class Blog extends Component { 27 | renderBlogPosts(yearlyPosts) { 28 | const monthlyPosts = formatPostsByDate( 29 | yearlyPosts, 30 | // 1. The Moment library has the audacity to return months (& dates) zero-indexed (0=Jan, 11=Dec) 31 | // we don't need to worry about dates because we just sort with them (and never display them). 32 | (date) => date.month() + 1, 33 | 'desc', 34 | ) 35 | return map(monthlyPosts, ([month, posts], index) => { 36 | const orderedPosts = orderBy(posts, 'date', 'desc') 37 | return ( 38 | 44 | ) 45 | }) 46 | } 47 | 48 | renderMonthlyPosts() { 49 | const yearlyPosts = formatPostsByDate( 50 | blogPosts, 51 | (date) => date.year(), 52 | 'desc', 53 | ) 54 | return map(yearlyPosts, ([year, posts]) => ( 55 |
    56 |

    {year}

    57 | {this.renderBlogPosts(posts)} 58 |
    59 | )) 60 | } 61 | 62 | render() { 63 | return ( 64 |
    65 | 66 | 67 |

    Blog

    68 | {this.renderMonthlyPosts()} 69 |
    70 | 71 |
    72 |
    73 | ) 74 | } 75 | } 76 | 77 | export default Blog 78 | -------------------------------------------------------------------------------- /src/containers/Events.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import EventList from 'components/EventList' 3 | import EventCalendar from 'components/EventCalendar' 4 | import Footer from 'components/Footer' 5 | import { Container, Row, Col, Button } from 'react-bootstrap' 6 | import { getEvents, filterUpcomingEvents, CALENDARS } from 'modules/gcal' 7 | import 'App.scss' 8 | import 'containers/styles/Events.scss' 9 | 10 | const Events = () => { 11 | const [events, setEvents] = useState([]) 12 | 13 | useEffect(() => { 14 | async function getAllEvents() { 15 | setEvents(await getEvents(CALENDARS.SESOC)) 16 | } 17 | getAllEvents() 18 | }, []) 19 | 20 | return ( 21 |
    22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
    30 | 31 |
    32 |
    33 | 41 |
    42 | 43 |
    44 |
    45 | 46 |
    47 |
    48 | ) 49 | } 50 | 51 | export default Events 52 | -------------------------------------------------------------------------------- /src/containers/GetInvolved.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Container, Row, Col } from 'react-bootstrap' 3 | import PromptActionButtons from 'components/PromptActionButtons' 4 | import Meetings from 'components/Meetings' 5 | import url from 'url' 6 | import Footer from 'components/Footer' 7 | import 'containers/styles/GetInvolved.scss' 8 | 9 | const getInvolved = url.resolve( 10 | process.env.PUBLIC_URL, 11 | '/illustrations/get-involved.png', 12 | ) 13 | 14 | class GetInvolved extends Component { 15 | render() { 16 | return ( 17 |
    18 | 19 | 20 | 21 | 22 |

    Get Involved

    23 | 42 | 43 | 44 | Get Involved with SE Soc Illustration 49 | 50 |
    51 | 52 | 53 |

    Meetings

    54 | 76 | 77 |
    78 |
    79 | 80 |
    81 |
    82 | ) 83 | } 84 | } 85 | 86 | export default GetInvolved 87 | -------------------------------------------------------------------------------- /src/containers/Home.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react' 2 | import { Container, Jumbotron, Row, Col } from 'react-bootstrap' 3 | import { Link } from 'react-router-dom' 4 | import url from 'url' 5 | import PropTypes from 'prop-types' 6 | import Footer from '../components/Footer' 7 | import { getEvents, CALENDARS, filterUpcomingEvents } from '../modules/gcal' 8 | import 'containers/styles/Home.scss' 9 | 10 | const heroImage = url.resolve(process.env.PUBLIC_URL, '/illustrations/hero.png') 11 | 12 | const eventCal = url.resolve( 13 | process.env.PUBLIC_URL, 14 | '/illustrations/calendar.png', 15 | ) 16 | 17 | const coffeeChat = url.resolve( 18 | process.env.PUBLIC_URL, 19 | '/illustrations/coffee-chat.png', 20 | ) 21 | 22 | const Hero = () => ( 23 | 24 | Hero 25 | 26 | 27 | 28 |

    29 | Software Engineering Society brings the SE student community 30 | together. 31 |

    32 | 33 |
    34 |
    35 |
    36 | ) 37 | 38 | const Content = (props) => { 39 | var upcomingEvent 40 | if (props.events[0]) { 41 | upcomingEvent = props.events[0] 42 | } 43 | 44 | return ( 45 | 46 | 47 | 51 | {upcomingEvent ? ( 52 | <> 53 |

    Missed us last time? Catch us at:

    54 |

    55 | 60 | {upcomingEvent.title} 61 | 62 | . Or, check out all upcoming events. 63 |

    64 | 65 | ) : ( 66 | <> 67 |

    More events are coming soon!

    68 |

    69 | Check out all of our past events. 70 |

    71 | 72 | )} 73 | 74 | 75 | Calendar Illustration 80 | 81 |
    82 | 83 | 84 |
    85 |

    Want to stay connected?

    86 |

    87 | Join our{' '} 88 | 89 | UW Software Engineering Discord 90 | 91 | . 92 |

    93 |
    94 | 95 | 99 | Coffee Chat Illustration 104 | 105 |
    106 |
    107 | ) 108 | } 109 | 110 | Content.propTypes = { 111 | events: PropTypes.arrayOf(PropTypes.object).isRequired, 112 | } 113 | 114 | const Home = () => { 115 | const [events, setEvents] = useState([]) 116 | 117 | useEffect(() => { 118 | async function getAllEvents() { 119 | setEvents(await getEvents(CALENDARS.SESOC)) 120 | } 121 | getAllEvents() 122 | }, []) 123 | 124 | return ( 125 |
    126 | 127 | 128 | 129 | 130 |
    131 |
    132 | ) 133 | } 134 | 135 | export default Home 136 | -------------------------------------------------------------------------------- /src/containers/Sponsors.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import ComingSoon from 'components/ComingSoon' 3 | 4 | class Sponsors extends Component { 5 | render() { 6 | return 7 | } 8 | } 9 | 10 | export default Sponsors 11 | -------------------------------------------------------------------------------- /src/containers/Wise.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import { Container, Row, Col, Button, Accordion, Card } from 'react-bootstrap' 3 | import url from 'url' 4 | import PropTypes from 'prop-types' 5 | import Footer from 'components/Footer' 6 | import PromptActionButtons from 'components/PromptActionButtons' 7 | import EventCalendar from 'components/EventCalendar' 8 | import { getEvents, CALENDARS } from 'modules/gcal' 9 | import 'containers/styles/Wise.scss' 10 | 11 | const SLACK_LINK = 'https://join.slack.com/t/uw-wise/signup' 12 | const MAILING_LIST_LINK = 13 | 'https://lists.uwaterloo.ca/mailman/listinfo/women-in-se' 14 | const FACEBOOK_LINK = 'https://forms.gle/piWhPZ85zyRVCNa77' 15 | const FEEDBACK_FORM_LINK = 'https://forms.gle/rvzrQ7X4kStmKDYh9' 16 | const CALENDAR_LINK = 17 | 'https://calendar.google.com/calendar/b/7?cid=dXdhdGVybG9vd2lzZUBnbWFpbC5jb20' 18 | 19 | const girlsImage = url.resolve( 20 | process.env.PUBLIC_URL, 21 | '/illustrations/wise-girls.png', 22 | ) 23 | const computerImage = url.resolve( 24 | process.env.PUBLIC_URL, 25 | '/illustrations/computer.png', 26 | ) 27 | const wiseLogo = url.resolve(process.env.PUBLIC_URL, '/logos/wise-logo.png') 28 | 29 | // TODO: use ExternalLink component on rest of site 30 | const ExternalLink = ({ href, children, ...restProps }) => ( 31 | 32 | {children} 33 | 34 | ) 35 | ExternalLink.propTypes = { 36 | href: PropTypes.string.isRequired, 37 | children: PropTypes.node.isRequired, 38 | } 39 | 40 | const FAQS = [ 41 | { 42 | question: 'Who does WiSE support?', 43 | answer: ( 44 |

    45 | WiSE recognizes women, as well as those whose gender identity is neither 46 | male nor female, including gender-fluid, non-binary, agender and more. 47 | WiSE advocates for representation of all genders in software 48 | engineering, and welcomes people with under-represented gender 49 | identities to all of our events. Additionally, some of WiSE’s events are 50 | open to all genders. 51 |

    52 | ), 53 | }, 54 | { 55 | question: 'What does “women-only” mean?', 56 | answer: ( 57 |

    58 | Our women only events are open to cis and trans women, and those whose 59 | gender identity is neither male nor female, including gender-fluid, 60 | non-binary, agender and more. We welcome people with under-represented 61 | gender identities to our women-only events. 62 |

    63 | ), 64 | }, 65 | { 66 | question: 'What events do you run each term?', 67 | answer: ( 68 |

    69 | Events vary from term to term, but in the past we have run a brunch, 70 | various mentoring activities, several casual board game nights, and a 71 | “How to get an awesome co-op” workshop. Check our our{' '} 72 | WiSE events calendar below for more 73 | information about our upcoming events! 74 |

    75 | ), 76 | }, 77 | { 78 | question: 'Why do you hold women-only events?', 79 | answer: ( 80 |
    81 |

    82 | Currently, women and those with gender identities that are neither 83 | male nor female are under-represented in software engineering. Some 84 | women do not feel comfortable attending events where they know that 85 | the majority of attendants will be male. We hold women-only events to 86 | lessen this issue. 87 |

    88 |

    89 | Following in the footsteps of{' '} 90 | WiCS, we 91 | hold women-only technical events to reduce the feeling of{' '} 92 | 93 | letting the side down 94 | 95 | . These women-only opportunities allow women to participate without 96 | the fear or making mistakes that will be interpreted as evidence that 97 | women are inferior at computing. 98 |

    99 |
    100 | ), 101 | }, 102 | { 103 | question: 'Where can I give my feedback about WiSE?', 104 | answer: ( 105 |

    106 | We love to hear feedback! You can give your feedback on our slack, or 107 | for an anonymous option - fill out our{' '} 108 | feedback form. 109 |

    110 | ), 111 | }, 112 | { 113 | question: 114 | 'Can you accommodate my food sensitivity at events where food is provided?', 115 | answer: ( 116 |

    117 | Yes! Please try to notify us at least a week in advance of the event. 118 |

    119 | ), 120 | }, 121 | { 122 | question: 'How can I get involved?', 123 | answer: ( 124 |

    125 | Join our slack! There you 126 | can chat with other WiSE, make event suggestions and volunteer to help 127 | run events. You can also attend our planning meeting that is held at the 128 | beginning of each term. 129 |

    130 | ), 131 | }, 132 | ] 133 | 134 | const Name = () => ( 135 | 136 | 137 | WiSE logo 138 | 139 | 140 |

    141 | Women in 142 |
    143 | Software Engineering 144 |

    145 | 146 |
    147 | ) 148 | 149 | const WhoWeAre = () => ( 150 | 151 | 152 |

    Who We Are

    153 |

    154 | Women in Software Engineering (WiSE) is a student-run organization that 155 | exists to encourage, support and advocate for women and non-binary* 156 | individuals who are studying Software Engineering at the University of 157 | Waterloo. 158 |

    159 |

    160 | We strive to build an inclusive and diverse environment which supports 161 | women, non-binary, and minoritized individuals in Software Engineering. 162 | WiSE holds events each term to build a supportive community and provide 163 | a variety of resources to empower women in tech. 164 |

    165 |

    *all gender identities are welcome and supported

    166 |
    167 | 175 |
    176 | 177 | 178 | girls 179 | 180 |
    181 | ) 182 | 183 | const Faqs = ({ faqs }) => { 184 | const defaultActiveKey = '0' 185 | const [activeFaq, setActiveFaq] = useState(defaultActiveKey) 186 | return ( 187 | <> 188 |

    FAQ

    189 | 190 | {faqs.map(({ question, answer }, index) => { 191 | const stringIndex = index.toString() 192 | const isActiveFaq = activeFaq === stringIndex 193 | return ( 194 | 195 | 198 | setActiveFaq(stringIndex)} 203 | > 204 | 205 | {isActiveFaq ? ( 206 | 207 | ) : ( 208 | 209 | )} 210 |
    {question}
    211 |
    212 |
    213 |
    214 | 215 | {answer} 216 | 217 |
    218 | ) 219 | })} 220 |
    221 | 222 | ) 223 | } 224 | 225 | Faqs.propTypes = { 226 | faqs: PropTypes.arrayOf( 227 | PropTypes.shape({ 228 | question: PropTypes.string.isRequired, 229 | answer: PropTypes.node.isRequired, 230 | }), 231 | ).isRequired, 232 | } 233 | 234 | const WiseEvents = ({ events }) => ( 235 |
    236 |

    Events

    237 |
    238 | 239 |
    240 |
    241 | 249 |
    250 |
    251 | ) 252 | 253 | WiseEvents.propTypes = { 254 | events: PropTypes.arrayOf(PropTypes.object).isRequired, 255 | } 256 | 257 | const Resources = () => ( 258 | <> 259 |

    Resources

    260 |

    261 | For more information on events or scholarship opportunities please 262 | checkout our{' '} 263 | 269 | resource hub 270 | 271 | . 272 |

    273 | 274 | ) 275 | 276 | const GetInvolved = () => ( 277 |
    278 |

    Get Involved

    279 | 304 |
    305 | ) 306 | 307 | const ImageSection = ({ children }) => ( 308 | 309 | 310 | {children} 311 | 312 | 317 | computer 322 | 323 | 324 | ) 325 | 326 | const Videos = () => ( 327 | <> 328 |

    Videos

    329 |

    WiSE Upper Year Panel: Fall 2020

    330 |
    331 |