From bbb55b5a94861d3924f250b8b0f0e90b240ab428 Mon Sep 17 00:00:00 2001 From: Owen Lester Date: Sun, 17 Mar 2024 20:13:49 -0400 Subject: [PATCH 1/7] finished changes --- frontend/pages/admin/[[...slug]].tsx | 1 - frontend/pages/settings.tsx | 41 ++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/frontend/pages/admin/[[...slug]].tsx b/frontend/pages/admin/[[...slug]].tsx index 919bb27e4..556638796 100644 --- a/frontend/pages/admin/[[...slug]].tsx +++ b/frontend/pages/admin/[[...slug]].tsx @@ -30,7 +30,6 @@ function AdminPage({ } const router = useRouter() - const tabs = [ { name: 'bulk', diff --git a/frontend/pages/settings.tsx b/frontend/pages/settings.tsx index f6ae75049..d3f4541a9 100644 --- a/frontend/pages/settings.tsx +++ b/frontend/pages/settings.tsx @@ -5,15 +5,19 @@ import FavoritesTab from 'components/Settings/FavoritesTab' import MembershipRequestsTab from 'components/Settings/MembershipRequestsTab' import ProfileTab from 'components/Settings/ProfileTab' import HashTabView from 'components/TabView' +import { NextPageContext } from 'next' import React, { ReactNode } from 'react' import { toast, TypeOptions } from 'react-toastify' import renderPage from 'renderPage' import styled from 'styled-components' -import { UserInfo } from 'types' +import { ApplicationSubmission, UserInfo } from 'types' import { OBJECT_NAME_TITLE, SHOW_MEMBERSHIP_REQUEST } from 'utils/branding' +import ApplicationsPage from '~/components/Applications' +import SubmissionsPage from '~/components/Submissions' import { BG_GRADIENT, CLUBS_BLUE, WHITE } from '~/constants/colors' import { BORDER_RADIUS } from '~/constants/measurements' +import { doBulkLookup } from '~/utils' const Notification = styled.span` border-radius: ${BORDER_RADIUS}; @@ -34,7 +38,12 @@ type SettingsProps = { authenticated: boolean | null } -const Settings = ({ userInfo, authenticated }: SettingsProps) => { +const Settings = ({ + userInfo, + authenticated, + whartonapplications, + submissions, +}) => { /** * Display the message to the user in the form of a toast. * @param The message to show to the user. @@ -78,6 +87,18 @@ const Settings = ({ userInfo, authenticated }: SettingsProps) => { icon: 'user', content: , }, + { + name: 'applications', + label: 'Applications', + content: () => ( + + ), + }, + { + name: 'submissions', + label: 'Submissions', + content: () => , + }, ] return ( @@ -97,4 +118,20 @@ const Settings = ({ userInfo, authenticated }: SettingsProps) => { ) } +type BulkResp = { + whartonapplications: any + submissions: Array +} + +Settings.getInitialProps = async (ctx: NextPageContext) => { + const data: BulkResp = (await doBulkLookup( + ['whartonapplications', ['submissions', '/submissions/?format=json']], + ctx, + )) as BulkResp + return { + ...data, + fair: ctx.query.fair != null ? parseInt(ctx.query.fair as string) : null, + } +} + export default renderPage(Settings) From f0ad4cb6869cb8998d115ee78abdd44936409dda Mon Sep 17 00:00:00 2001 From: Avi Upadhyayula <69180850+aviupadhyayula@users.noreply.github.com> Date: Tue, 19 Mar 2024 22:28:05 -0400 Subject: [PATCH 2/7] Remove Wharton applications from user profile (and update branch) (#641) * Update main.ts * Update frontend dependencies (#616) Upgrade from Node 14 to Node 20 and bump frontend dependency versions to current. --------- Co-authored-by: Julian Weng * Update README.md * Update README backend instructions and intro blurb * Fix admin page access on frontend. (#626) Add frontend check for existing pre-loaded permissions on /admin. * Removed deprecated QuestionResponse model and duplicate line (#625) * Remove deprecated QuestionResponse model * remove duplicate line: 'rank field in Club' * made migrations after deleting QuestionResponse * Streamline django storages config (#618) * Add staticfiles * Fix AWS bucket routing for boto * Try setting credentials through env vars * Try renaming env vars? * Set AWS region * add back staticfiles * Remove region and signature version * Move credentials to new API * Use env variables and remove staticfiles * Add back staticfiles * Make code look pretty --------- Co-authored-by: Rohan Moniz <60864468+rm03@users.noreply.github.com> * Add hour to displayed application deadline (#628) * Add hour for application due dates * Make linter happy * Specify Eastern time zone * Display username if name is empty (#637) * finished changes * Remove Wharton applications from user profile * Fix weird artifacts from merge --------- Co-authored-by: Joy Liu <34288846+joyliu-q@users.noreply.github.com> Co-authored-by: Julian Weng Co-authored-by: Rohan Moniz <60864468+rm03@users.noreply.github.com> Co-authored-by: Thomas Ngulube <47449914+Porcupine1@users.noreply.github.com> Co-authored-by: Owen Lester --- .github/workflows/build-and-deploy.yaml | 1 + README.md | 18 +- .../0096_delete_questionresponse.py | 16 + backend/clubs/models.py | 12 - backend/clubs/views.py | 2 +- backend/pennclubs/settings/production.py | 12 +- frontend/.babelrc | 24 +- frontend/.eslintrc.json | 1 + frontend/.prettierrc | 12 +- frontend/.storybook/.babelrc | 10 +- frontend/.storybook/main.js | 8 +- frontend/.storybook/preview-head.html | 4 +- frontend/.vscode/settings.json | 38 +- frontend/Dockerfile | 2 +- frontend/components/Applications.tsx | 49 +- frontend/components/ClubCard.tsx | 73 +- frontend/components/ClubEditPage.tsx | 3 +- .../components/ClubEditPage/AnalyticsCard.tsx | 13 - .../ClubEditPage/ApplicationsCard.tsx | 16 +- .../ClubEditPage/ApplicationsPage.tsx | 28 +- .../components/ClubEditPage/ClubEditCard.tsx | 58 +- .../components/ClubEditPage/ClubFairCard.tsx | 1 + .../ClubEditPage/ClubManagementCard.tsx | 10 +- .../ClubEditPage/FormProgressIndicator.tsx | 10 +- .../components/ClubEditPage/QRCodeCard.tsx | 6 +- .../components/ClubEditPage/RenewCard.tsx | 6 +- frontend/components/ClubList.tsx | 2 +- frontend/components/ClubPage/Actions.tsx | 12 +- frontend/components/ClubPage/AdvisorList.tsx | 2 +- .../ClubPage/ClubApprovalDialog.tsx | 33 +- frontend/components/ClubPage/Events.tsx | 4 +- .../components/ClubPage/ListRenewalDialog.tsx | 10 +- .../components/ClubPage/LiveEventsDialog.tsx | 5 +- frontend/components/ClubPage/MemberCard.tsx | 4 +- .../ClubPage/RenewalRequestDialog.tsx | 6 +- frontend/components/ClubTableRow.tsx | 32 +- frontend/components/DisplayButtons.tsx | 16 +- frontend/components/DropdownFilter.tsx | 6 +- .../components/EventPage/DateInterval.tsx | 4 +- frontend/components/EventPage/EventCard.tsx | 2 +- frontend/components/EventPage/EventModal.tsx | 6 +- frontend/components/FilterSearch.tsx | 22 +- frontend/components/FormComponents.tsx | 86 +- frontend/components/Header/Feedback.tsx | 10 +- frontend/components/Header/Head.tsx | 23 +- frontend/components/Header/Links.tsx | 11 +- frontend/components/Header/index.tsx | 10 +- frontend/components/ModelForm.tsx | 6 +- frontend/components/OrderInput.tsx | 7 +- frontend/components/ResourceCreationPage.tsx | 20 +- frontend/components/RouteProgressBar.tsx | 28 +- frontend/components/SearchBar.tsx | 6 +- frontend/components/Settings/ClubTab.tsx | 5 +- frontend/components/Settings/ClubTabCard.tsx | 8 +- frontend/components/Settings/ClubTabTable.tsx | 12 +- .../components/Settings/FairEventsTab.tsx | 22 +- frontend/components/Settings/FairsTab.tsx | 1 + frontend/components/Settings/FavoritesTab.tsx | 5 +- .../Settings/MembershipRequestsTab.tsx | 6 +- frontend/components/Settings/ProfileForm.tsx | 1 + frontend/components/Settings/QueueTab.tsx | 4 +- frontend/components/Settings/RenewTab.tsx | 4 +- .../components/Settings/RenewTabTable.tsx | 3 +- frontend/components/Settings/ReportsTab.tsx | 7 +- frontend/components/Settings/ScriptsTab.tsx | 4 +- .../Settings/WhartonApplicationStatus.tsx | 6 +- .../Settings/WhartonApplicationTab.tsx | 1 + frontend/components/Submissions.tsx | 6 +- .../components/common/AuthPrompt.stories.tsx | 7 +- frontend/components/common/BookmarkIcon.tsx | 24 +- frontend/components/common/Card.tsx | 16 +- frontend/components/common/Checkbox.tsx | 6 +- frontend/components/common/Container.tsx | 10 +- frontend/components/common/Icon.tsx | 11 +- frontend/components/common/Loading.tsx | 6 +- frontend/components/common/Metadata.tsx | 24 +- frontend/components/common/Modal.tsx | 26 +- frontend/components/common/ProfilePic.tsx | 39 +- frontend/components/common/Shade.tsx | 10 +- frontend/components/common/SubscribeIcon.tsx | 24 +- frontend/components/reports/ReportForm.tsx | 42 +- frontend/cypress/integration/authed_spec.js | 5 +- frontend/cypress/integration/invite_spec.js | 13 +- frontend/cypress/integration/request_spec.js | 23 +- .../cypress/integration/superuser_spec.js | 202 +- frontend/cypress/support/commands.js | 8 +- frontend/cypress/support/console.js | 14 +- frontend/cypress/tsconfig.json | 25 +- frontend/markdown/fileupload.md | 6 +- frontend/markdown/media.md | 8 +- frontend/next-env.d.ts | 5 +- frontend/package.json | 154 +- frontend/pages/_document.tsx | 38 +- frontend/pages/_error.tsx | 4 +- frontend/pages/admin/[[...slug]].tsx | 11 +- frontend/pages/club/[club]/alumni.tsx | 21 +- .../application/[application]/index.tsx | 8 +- frontend/pages/club/[club]/apply.tsx | 18 +- frontend/pages/club/[club]/fair.tsx | 8 +- frontend/pages/club/[club]/index.tsx | 21 +- frontend/pages/club/[club]/org.tsx | 31 +- frontend/pages/club/[club]/renew.tsx | 18 +- frontend/pages/constitutions.tsx | 6 +- frontend/pages/events.tsx | 31 +- frontend/pages/fair.tsx | 61 +- frontend/pages/faq.tsx | 9 +- frontend/pages/guides.tsx | 2 +- frontend/pages/guides/[page]/index.tsx | 2 +- frontend/pages/index.tsx | 7 +- .../invite/[club]/[invite]/[token]/index.tsx | 2 +- frontend/pages/settings.tsx | 30 +- frontend/pages/user/[user]/index.tsx | 7 +- frontend/pages/welcome.tsx | 1 + frontend/pages/zoom.tsx | 16 +- frontend/public/static/css/devices.min.css | 2532 ++- frontend/public/static/maintenance.html | 50 +- frontend/renderPage.tsx | 6 +- frontend/tsconfig.json | 23 +- frontend/utils.tsx | 8 +- frontend/utils/branding.tsx | 508 +- frontend/yarn.lock | 14804 ++++++---------- k8s/main.ts | 4 +- 122 files changed, 9540 insertions(+), 10356 deletions(-) create mode 100644 backend/clubs/migrations/0096_delete_questionresponse.py diff --git a/.github/workflows/build-and-deploy.yaml b/.github/workflows/build-and-deploy.yaml index 83b55762f..278214958 100644 --- a/.github/workflows/build-and-deploy.yaml +++ b/.github/workflows/build-and-deploy.yaml @@ -23,6 +23,7 @@ jobs: uses: pennlabs/shared-actions/.github/workflows/react-check.yaml@v0.1 with: path: frontend + nodeVersion: 20.11.1 build-backend: name: Build backend diff --git a/README.md b/README.md index ff2f12a9b..19e743da4 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,18 @@ [![Build and Deploy](https://github.com/pennlabs/penn-clubs/workflows/Build%20and%20Deploy/badge.svg)](https://github.com/pennlabs/penn-clubs/actions) [![Coverage Status](https://codecov.io/gh/pennlabs/penn-clubs/branch/master/graph/badge.svg)](https://codecov.io/gh/pennlabs/penn-clubs) -Official React-based website for Penn Labs' club directory and events listings. -The REST API written in Django for Penn Clubs infrastructure. +Official platform for club discovery, recruitment, and events at Penn. +React/Next.js frontend and Django-based REST API. ## Installation -You will need to start both the backend and the frontend to do Penn Clubs development. +You will need to start both the backend and the frontend to develop on Penn Clubs. Clubs supports Mac and Linux/WSL development. -Questions? Check out our [extended guide](https://github.com/pennlabs/penn-clubs/wiki/Development-Guide#windows-development) for FAQs for both Mac and Windows. +Questions? Check out our [extended guide](https://github.com/pennlabs/penn-clubs/wiki/Development-Guide) for FAQs. ### Backend -Running the backend requires [Python 3](https://www.python.org/downloads/). +Running the backend requires [Python 3.11](https://www.python.org/downloads/) and [Pipenv](https://pipenv.pypa.io/en/latest/). In production, you will need to set the following environment variables: @@ -42,13 +42,13 @@ dependencies, you can revisit later if not) - `$ echo 'export PATH="/usr/local/opt/openssl@3/bin:$PATH"' >> ~/.zshrc` - `$ export LDFLAGS="-L/usr/local/opt/openssl@3/lib"` - `$ export CPPFLAGS="-I/usr/local/opt/openssl@3/include"` -- Windows +- Linux/WSL - `$ apt-get install gcc python3-dev libpq-dev` Now, you can run - `$ pipenv install` to install Python dependencies. This may take a few - minutes. Optionally include the `--dev` argument if you are installing locally + minutes. Include the `--dev` argument if you are installing locally for development. If you skipped installing `psycopg2` earlier, you might see an error with locking -- this is expected! - `$ pipenv shell` @@ -63,8 +63,8 @@ Now, you can run Running the frontend requires [Node.js](https://nodejs.org/en/) and [Yarn](https://yarnpkg.com/getting-started/install). -**Please ensure you are using Node 14**. Our codebase does not support other -versions of Node (v14.21.3 is stable). +**Please ensure you are using Node 20**. Our codebase does not support other +versions of Node (v20.11.1 is stable). You will need to set the following environment variables on the frontend: diff --git a/backend/clubs/migrations/0096_delete_questionresponse.py b/backend/clubs/migrations/0096_delete_questionresponse.py new file mode 100644 index 000000000..eb383eff9 --- /dev/null +++ b/backend/clubs/migrations/0096_delete_questionresponse.py @@ -0,0 +1,16 @@ +# Generated by Django 5.0.2 on 2024-03-06 01:23 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("clubs", "0095_rm_field_add_count"), + ] + + operations = [ + migrations.DeleteModel( + name="QuestionResponse", + ), + ] diff --git a/backend/clubs/models.py b/backend/clubs/models.py index dcb6083f7..47c983c7a 100644 --- a/backend/clubs/models.py +++ b/backend/clubs/models.py @@ -329,9 +329,6 @@ class Club(models.Model): # cache club rankings rank = models.IntegerField(default=0) - # cache club rankings - rank = models.IntegerField(default=0) - created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) @@ -1776,15 +1773,6 @@ class Meta: unique_together = (("question", "submission"),) -class QuestionResponse(models.Model): - """ - Represents a response to a question on a custom application - """ - - question = models.ForeignKey(ApplicationQuestion, on_delete=models.CASCADE) - response = models.TextField(blank=True) - - @receiver(models.signals.pre_delete, sender=Asset) def asset_delete_cleanup(sender, instance, **kwargs): if instance.file: diff --git a/backend/clubs/views.py b/backend/clubs/views.py index a06567da8..ab4e79d67 100644 --- a/backend/clubs/views.py +++ b/backend/clubs/views.py @@ -1663,7 +1663,7 @@ def directory(self, request, *args, **kwargs): @action(detail=False, methods=["get"]) def constitutions(self, request, *args, **kwargs): """ - A special endpoint for SAC affilaited clubs to check if + A special endpoint for SAC affiliated clubs to check if they have uploaded a club constitution. --- operationId: List Club Constitutions diff --git a/backend/pennclubs/settings/production.py b/backend/pennclubs/settings/production.py index 494555e2f..2be4f552d 100644 --- a/backend/pennclubs/settings/production.py +++ b/backend/pennclubs/settings/production.py @@ -40,16 +40,12 @@ # Upload file storage AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID") AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY") +AWS_STORAGE_BUCKET_NAME = os.getenv("AWS_STORAGE_BUCKET_NAME") +AWS_DEFAULT_ACL = "public-read" +AWS_QUERYSTRING_AUTH = False STORAGES = { - "default": { - "BACKEND": "storages.backends.s3boto3.S3Boto3Storage", - "OPTIONS": { - "bucket_name": os.getenv("AWS_STORAGE_BUCKET_NAME"), - "default_acl": "public-read", - "querystring_auth": False, - }, - }, + "default": {"BACKEND": "storages.backends.s3boto3.S3Boto3Storage"}, "staticfiles": {"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"}, } diff --git a/frontend/.babelrc b/frontend/.babelrc index 8449cba0e..2781700cf 100644 --- a/frontend/.babelrc +++ b/frontend/.babelrc @@ -1,18 +1,12 @@ { - "presets": [ - "next/babel" - ], - "plugins": [ - "istanbul" - ], - "env": { - "production": { - "plugins": [["styled-components", { "ssr": true }]] - }, - "development": { - "plugins": [ - "babel-plugin-styled-components" - ] - } + "presets": ["next/babel"], + "plugins": ["istanbul"], + "env": { + "production": { + "plugins": [["styled-components", { "ssr": true }]] + }, + "development": { + "plugins": ["babel-plugin-styled-components"] } + } } diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index ef4a729be..7f9a831c3 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -33,6 +33,7 @@ } ], "no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unused-vars": "off", "unused-imports/no-unused-imports-ts": "error", "camelcase": ["warn", { "ignoreDestructuring": true }], diff --git a/frontend/.prettierrc b/frontend/.prettierrc index 786ff459d..d62b1a6c5 100644 --- a/frontend/.prettierrc +++ b/frontend/.prettierrc @@ -1,8 +1,8 @@ { - "endOfLine": "lf", - "semi": false, - "singleQuote": true, - "tabWidth": 2, - "useTabs": false, - "trailingComma": "all" + "endOfLine": "lf", + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "all" } diff --git a/frontend/.storybook/.babelrc b/frontend/.storybook/.babelrc index 93ee888f0..34abf3fff 100644 --- a/frontend/.storybook/.babelrc +++ b/frontend/.storybook/.babelrc @@ -1,8 +1,4 @@ { - "presets": [ - "next/babel" - ], - "plugins": [ - "styled-components" - ] -} \ No newline at end of file + "presets": ["next/babel"], + "plugins": ["styled-components"] +} diff --git a/frontend/.storybook/main.js b/frontend/.storybook/main.js index 6d190590f..70c7380f8 100644 --- a/frontend/.storybook/main.js +++ b/frontend/.storybook/main.js @@ -1,4 +1,8 @@ module.exports = { - stories: ['../components/**/*.stories.@(js|ts|mdx|tsx)'], - addons: ['@storybook/addon-actions/register', '@storybook/addon-links/register', '@storybook/addon-docs'], + stories: ['../components/**/*.stories.@(js|ts|mdx|tsx)'], + addons: [ + '@storybook/addon-actions/register', + '@storybook/addon-links/register', + '@storybook/addon-docs', + ], } diff --git a/frontend/.storybook/preview-head.html b/frontend/.storybook/preview-head.html index a8ed7e89c..2b01f9601 100644 --- a/frontend/.storybook/preview-head.html +++ b/frontend/.storybook/preview-head.html @@ -2,7 +2,7 @@ rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.0/css/bulma.min.css" integrity="sha256-aPeK/N8IHpHsvPBCf49iVKMdusfobKo2oxF8lRruWJg=" - crossOrigin="anonymous" + crossorigin="anonymous" /> \ No newline at end of file + diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json index eb0487fe9..68a18e6a4 100644 --- a/frontend/.vscode/settings.json +++ b/frontend/.vscode/settings.json @@ -1,21 +1,21 @@ { - "editor.tabSize": 2, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": true - }, - "files.exclude": { - "**/.git": true, - "**/.svn": true, - "**/.hg": true, - "**/CVS": true, - "**/.DS_Store": true, - "**/.next": true, - "**/.nyc_output": true - }, - "search.exclude": { - "**/node_modules": true, - "**/bower_components": true, - "**/*.code-search": true, - "**/coverage": true - } + "editor.tabSize": 2, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "files.exclude": { + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.DS_Store": true, + "**/.next": true, + "**/.nyc_output": true + }, + "search.exclude": { + "**/node_modules": true, + "**/bower_components": true, + "**/*.code-search": true, + "**/coverage": true + } } diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 6a09d2f60..46b0581b1 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,4 +1,4 @@ -FROM node:14.14.0-buster-slim +FROM node:20.11.1-buster-slim LABEL maintainer="Penn Labs" diff --git a/frontend/components/Applications.tsx b/frontend/components/Applications.tsx index 0bc7a4b39..b8d2a79f0 100644 --- a/frontend/components/Applications.tsx +++ b/frontend/components/Applications.tsx @@ -53,7 +53,7 @@ const MainInfo = styled.div` flex-direction: row; ` type CardProps = { - readonly hovering?: boolean + readonly $hovering?: boolean className?: string } @@ -63,7 +63,7 @@ const Card = styled.div` transition: all ${ANIMATION_DURATION}ms ease; border-radius: ${BORDER_RADIUS}; box-shadow: 0 0 0 ${WHITE}; - background-color: ${({ hovering }) => (hovering ? HOVER_GRAY : WHITE)}; + background-color: ${({ $hovering }) => ($hovering ? HOVER_GRAY : WHITE)}; border: 1px solid ${ALLBIRDS_GRAY}; justify-content: space-between; height: auto; @@ -105,35 +105,34 @@ function ApplicationsPage({ whartonapplications }): ReactElement { {whartonapplications != null && whartonapplications.length > 0 ? ( whartonapplications.map((application) => ( - - - - -
- {application.name} - -
-
- {application.club_image_url != null && - application.club_image_url !== '' && ( - - - - )} -
-
- {application.description && application.description.length && ( + + + +
+ {application.name} + +
+
+ {application.club_image_url != null && + application.club_image_url !== '' && ( + + + + )} +
+
+ {application.description && + application.description.length && ( )} -
-
+
)) diff --git a/frontend/components/ClubCard.tsx b/frontend/components/ClubCard.tsx index 7734f35c9..85541a845 100644 --- a/frontend/components/ClubCard.tsx +++ b/frontend/components/ClubCard.tsx @@ -36,7 +36,7 @@ const Description = styled.p` ` type CardProps = { - readonly hovering?: boolean + readonly $hovering?: boolean className?: string } @@ -46,7 +46,7 @@ const Card = styled.div` transition: all ${ANIMATION_DURATION}ms ease; border-radius: ${BORDER_RADIUS}; box-shadow: 0 0 0 ${WHITE}; - background-color: ${({ hovering }) => (hovering ? HOVER_GRAY : WHITE)}; + background-color: ${({ $hovering }) => ($hovering ? HOVER_GRAY : WHITE)}; border: 1px solid ${ALLBIRDS_GRAY}; justify-content: space-between; height: auto; @@ -97,55 +97,46 @@ type ClubCardProps = { } const ClubCard = ({ club, fullWidth }: ClubCardProps): ReactElement => { - const { - name, - active, - approved, - subtitle, - tags, - enables_subscription, - code, - } = club + const { name, active, approved, subtitle, tags, enables_subscription, code } = + club const img = club.image_url const textDescription = shorten(subtitle || 'This club has no description.') return ( - - - -
-
-
- - {name} - -
- {!active && ( - Inactive - )} - {approved === null && ( - - Pending Approval - - )} - {approved === false && ( - Rejected - )} - + + +
+
+
+ + {name} +
- {img && ( - - {`${name} - + {!active && ( + Inactive )} + {approved === null && ( + + Pending Approval + + )} + {approved === false && ( + Rejected + )} +
+ {img && ( + + {`${name} + + )} +
- {textDescription} + {textDescription} - -
-
+ + ) diff --git a/frontend/components/ClubEditPage.tsx b/frontend/components/ClubEditPage.tsx index be79184dc..231fe3cd8 100644 --- a/frontend/components/ClubEditPage.tsx +++ b/frontend/components/ClubEditPage.tsx @@ -386,6 +386,7 @@ const ClubForm = ({ {showInactiveTag && } { @@ -410,7 +411,7 @@ const ClubForm = ({ Before creating your {OBJECT_NAME_SINGULAR}, please check to{' '} see if it already exists on the{' '} - directory page + directory page . If your {OBJECT_NAME_SINGULAR} already exists, please email{' '} to gain access instead of filling out this form. diff --git a/frontend/components/ClubEditPage/AnalyticsCard.tsx b/frontend/components/ClubEditPage/AnalyticsCard.tsx index 2503f774f..f5158159d 100644 --- a/frontend/components/ClubEditPage/AnalyticsCard.tsx +++ b/frontend/components/ClubEditPage/AnalyticsCard.tsx @@ -1,5 +1,4 @@ import moment from 'moment' -import Head from 'next/head' import { ReactElement, useEffect, useState } from 'react' import DatePicker from 'react-datepicker' import Select from 'react-select' @@ -242,18 +241,6 @@ export default function AnalyticsCard({ return ( <> - - - - Analyze the traffic that your {OBJECT_NAME_SINGULAR} has received on a diff --git a/frontend/components/ClubEditPage/ApplicationsCard.tsx b/frontend/components/ClubEditPage/ApplicationsCard.tsx index 1702c39a5..729ecc911 100644 --- a/frontend/components/ClubEditPage/ApplicationsCard.tsx +++ b/frontend/components/ClubEditPage/ApplicationsCard.tsx @@ -64,16 +64,12 @@ const ApplicationModal = (props: { committeeChoices, } = props // TODO: I'm positive that this is something that Formik should do for me - const [ - questionType, - setQuestionType, - ] = useState() - const [multipleChoices, setMultipleChoices] = useState< - [{ label: string; value: string }] - >() - const [committees, setCommittees] = useState< - [{ label: string; value: string }] - >() + const [questionType, setQuestionType] = + useState() + const [multipleChoices, setMultipleChoices] = + useState<[{ label: string; value: string }]>() + const [committees, setCommittees] = + useState<[{ label: string; value: string }]>() const [committeeQuestion, setCommitteeQuestion] = useState() const validateWordCount = (value) => { diff --git a/frontend/components/ClubEditPage/ApplicationsPage.tsx b/frontend/components/ClubEditPage/ApplicationsPage.tsx index af987ab01..3b242cc1b 100644 --- a/frontend/components/ClubEditPage/ApplicationsPage.tsx +++ b/frontend/components/ClubEditPage/ApplicationsPage.tsx @@ -393,20 +393,16 @@ export default function ApplicationsPage({ club: Club }): ReactElement { const [applications, setApplications] = useState>([]) - const [ - currentApplication, - setCurrentApplication, - ] = useState(null) + const [currentApplication, setCurrentApplication] = + useState(null) const [submissions, setSubmissions] = useState<{ [key: number]: Array }>([]) const [showModal, setShowModal] = useState(false) const [showNotifModal, setShowNotifModal] = useState(false) const [showReasonModal, setShowReasonModal] = useState(false) - const [ - currentSubmission, - setCurrentSubmission, - ] = useState(null) + const [currentSubmission, setCurrentSubmission] = + useState(null) const [pageIndex, setPageIndex] = useState(0) const [statusToggle, setStatusToggle] = useState(false) const [categoriesSelectAll, setCategoriesSelectAll] = useState>( @@ -640,9 +636,8 @@ export default function ApplicationsPage({ categoriesSelectAll.includes(statusLabel) if (deselecting) { - const newCategoriesSelectAll = categoriesSelectAll.filter( - (e) => e !== statusLabel, - ) + const newCategoriesSelectAll = + categoriesSelectAll.filter((e) => e !== statusLabel) setCategoriesSelectAll(newCategoriesSelectAll) } else { const newCategoriesSelectAll = categoriesSelectAll @@ -705,12 +700,11 @@ export default function ApplicationsPage({ - item.pk - ? { ...item, id: item.pk } - : { ...item, id: index }, + data={submissions[currentApplication.id].map( + (item, index) => + item.pk + ? { ...item, id: item.pk } + : { ...item, id: index }, )} columns={responseTableFields} searchableColumns={['name']} diff --git a/frontend/components/ClubEditPage/ClubEditCard.tsx b/frontend/components/ClubEditPage/ClubEditCard.tsx index e00607d5a..3b1061226 100644 --- a/frontend/components/ClubEditPage/ClubEditCard.tsx +++ b/frontend/components/ClubEditPage/ClubEditCard.tsx @@ -195,29 +195,25 @@ export default function ClubEditCard({ ), ) - const [ - showSchoolYearProgramming, - setSchoolYearProgramming, - ] = useState( - !!( - club.target_majors?.length || - club.target_schools?.length || - club.target_years?.length || - club.student_types?.length - ), - ) + const [showSchoolYearProgramming, setSchoolYearProgramming] = + useState( + !!( + club.target_majors?.length || + club.target_schools?.length || + club.target_years?.length || + club.student_types?.length + ), + ) - const [ - showStudentTypeProgramming, - setStudentTypeProgramming, - ] = useState( - !!( - club.target_majors?.length || - club.target_schools?.length || - club.target_years?.length || - club.student_types?.length - ), - ) + const [showStudentTypeProgramming, setStudentTypeProgramming] = + useState( + !!( + club.target_majors?.length || + club.target_schools?.length || + club.target_years?.length || + club.student_types?.length + ), + ) const [showSchoolProgramming, setSchoolProgramming] = useState( !!( @@ -243,10 +239,10 @@ export default function ClubEditCard({ ) // sorry ts - const exclusives = (categorizeFilter( + const exclusives = categorizeFilter( exclusiveEntries, ([key]) => key.match(/^exclusive:(.+?):(.+?)$/)?.[1] ?? 'unknown', - ) as unknown) as { + ) as unknown as { year: Array<[string, { checked?: boolean; detail?: string }]> // major: Array<[string, { checked?: boolean; detail?: string }]> student_type: Array<[string, { checked?: boolean; detail?: string }]> @@ -496,8 +492,7 @@ export default function ClubEditCard({ label: 'Location', required: false, type: 'location', - help: - 'Remember, this will be available to the public. Please only include information you feel comfortable sharing.', + help: 'Remember, this will be available to the public. Please only include information you feel comfortable sharing.', }, { name: 'email', @@ -556,11 +551,8 @@ export default function ClubEditCard({ description: SHOW_RANK_ALGORITHM ? ( Some of these fields will be used to adjust {OBJECT_NAME_SINGULAR}{' '} - ordering on the home page. Click{' '} - - here - {' '} - for more details. + ordering on the home page. Click here for + more details. ) : ( @@ -858,6 +850,7 @@ export default function ClubEditCard({ key={i} as={ { + text: TextField, checkbox: CheckboxField, html: RichTextField, multiselect: SelectField, @@ -865,7 +858,8 @@ export default function ClubEditCard({ image: FileField, address: FormikAddressField, checkboxText: CheckboxTextField, - creatableMultiSelect: CreatableMultipleSelectField, + creatableMultiSelect: + CreatableMultipleSelectField, }[props.type] ?? TextField } {...other} diff --git a/frontend/components/ClubEditPage/ClubFairCard.tsx b/frontend/components/ClubEditPage/ClubFairCard.tsx index 9e738429c..c7853d821 100644 --- a/frontend/components/ClubEditPage/ClubFairCard.tsx +++ b/frontend/components/ClubEditPage/ClubFairCard.tsx @@ -228,6 +228,7 @@ const ClubFairCard = ({
{item.club.name} (
{club.name}{' '} - - - - + +
{!isSummer() && ( - - - - Add {OBJECT_NAME_TITLE_SINGULAR} - + + + Add {OBJECT_NAME_TITLE_SINGULAR} )} diff --git a/frontend/components/DropdownFilter.tsx b/frontend/components/DropdownFilter.tsx index 3492a0845..3805f3089 100644 --- a/frontend/components/DropdownFilter.tsx +++ b/frontend/components/DropdownFilter.tsx @@ -38,7 +38,7 @@ const DropdownHeader = styled.div` } ` -const CheckboxRow = styled.div<{ color?: string }>` +const CheckboxRow = styled.div<{ $color?: string }>` padding-top: 3px; & label { @@ -46,7 +46,9 @@ const CheckboxRow = styled.div<{ color?: string }>` } & span { - color: ${({ color }) => color ?? CLUBS_GREY}; + color: ${({ $color }) => + $color ?? + CLUBS_GREY}; // Using the prop with a $ prefix and providing a fallback value } & span[role='checkbox'] { diff --git a/frontend/components/EventPage/DateInterval.tsx b/frontend/components/EventPage/DateInterval.tsx index 9709ad380..38094efb4 100644 --- a/frontend/components/EventPage/DateInterval.tsx +++ b/frontend/components/EventPage/DateInterval.tsx @@ -41,7 +41,9 @@ const DateInterval = ({ end: Date className?: string }): ReactElement => ( -

{dateIntervalString(start, end)}

+

+ {dateIntervalString(start, end)}{' '} +

) export default styled(DateInterval)` diff --git a/frontend/components/EventPage/EventCard.tsx b/frontend/components/EventPage/EventCard.tsx index 8233d8426..d9aa723bd 100644 --- a/frontend/components/EventPage/EventCard.tsx +++ b/frontend/components/EventPage/EventCard.tsx @@ -62,7 +62,7 @@ const EventCard = (props: { return ( - +
{club != null && } - + { diff --git a/frontend/components/FilterSearch.tsx b/frontend/components/FilterSearch.tsx index 93fb56dfe..d48adaaf6 100644 --- a/frontend/components/FilterSearch.tsx +++ b/frontend/components/FilterSearch.tsx @@ -1,6 +1,6 @@ import Fuse from 'fuse.js' import { ReactElement, useEffect, useState } from 'react' -import { OptionsType, Styles } from 'react-select' +import { Options, StylesConfig } from 'react-select' import Select from 'react-select/async' import styled from 'styled-components' @@ -39,7 +39,7 @@ const SubLabel = styled.div` } ` -const ColorPreview = styled.div<{ color: string }>` +const ColorPreview = styled.div<{ $color: string }>` display: inline-block; width: 1em; height: 1em; @@ -93,7 +93,7 @@ const Search = ({ clearTags, }: SearchProps): ReactElement => { // Custom styles for the react-select - const styles: Styles = { + const styles: StylesConfig = { control: ({ background, ...base }, { isFocused }) => { const isEmphasized = isFocused return { @@ -148,10 +148,7 @@ const Search = ({ ) }, MultiValueLabel: ({ data: { label } }) => label, - MultiValueRemove: ({ - data, - innerProps: { onClick, onTouchEnd, onMouseDown }, - }) => { + MultiValueRemove: ({ data, innerProps }) => { const removeGenerator = (func) => { return (e) => { func(e) @@ -160,10 +157,11 @@ const Search = ({ } return (