diff --git a/.vscode/course-schedulizer.code-workspace b/.vscode/course-schedulizer.code-workspace index d6422fa9..e8926e48 100644 --- a/.vscode/course-schedulizer.code-workspace +++ b/.vscode/course-schedulizer.code-workspace @@ -8,9 +8,9 @@ "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, - "source.organizeImports": true, - "source.fixAll": true + "source.fixAll.eslint": "explicit", + "source.organizeImports": "explicit", + "source.fixAll": "explicit" }, "eslint.workingDirectories": [ { diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md deleted file mode 100644 index 8c14d11f..00000000 --- a/DOCUMENTATION.md +++ /dev/null @@ -1,60 +0,0 @@ -Course Schedulizer: DOCUMENTATION - - - - - -- How to run the `develop` branch locally for developers: - - `git clone`: clone the repo to local computer and `cd` into the folder - - `git checkout develop`: switch to `develop` branch - - `cd client-course-schedulizer`: `cd` into the client folder - - `pnpm install`: install all packages in package.json - - Current requirement: pnpm 8.6.0 or above, node 18 or above - - `pnpm start`: run the website on localhost:3000 -- Develop Branch - For development, deployed on [Course Schedulizer (sharp-babbage-a45ee2.netlify.app)](https://sharp-babbage-a45ee2.netlify.app/#/) -- .github/workflows: the github auto-test and auto-deploy scripts - - ci.yml: automatically test the latest update - - Trigger: push to all branches, PR to `develop` and `production` - - Work environment: ./client-course-schedulizer - - Steps: - - Set up actions for pnpm and node - - Update pnpm version - - Install pnpm dependencies - - Run pnpm test on the latest push or PR - - deploy.yml: auto-deploy - - This script is not updated to use pnpm yet, must be updated before pushing to `production` or error will occur -- Important files: client-course-schedulizer/csv - - This folder contains sample course schedules in .csv and .xlsx formats - - Not compatible with latest Workday format, might be replaced in later versions -- Important files: client-course-schedulizer/src -  - - Folder `assets` - Contains images utilized by the application - - Folder `components` - Contains important elements of the program interface (to be discussed in further detail later) - - Folder `data` - Features constraints on times within which classes may start - - May need to run some outside R command to get the correct data - - Ask Prof. Pruim for more information about how this folder works - - Folder `styles` - Establishes colors and fonts used in the application - - Folder `types` - Establishes objects used in the application (best not to alter this) - - Folder `utilities` - Various functions and objects to help the application function (to be discussed in further detail later) - - Other files - Handle server operations -- Important Files - src/components - - App Folder - Features navigational components, and tests to run - - App/App.tsx - Provides navigational info - - Footer Folder - Handles display of the bottom of the page - - Header Folder - Handles display of the top of the page, including navigational buttons - - Tabs Folder - Handles tabs that appear in the Schedulizer window - - Toolbar Folder - Handles functions in toolbars that appear in the Schedulizer window - - Pages Folder - Handles the pages that are accessible by way of the header - - SchedulizerPage - Implements the Tabs found in the components/Tabs folder - - AboutPage - Contains some information regarding the Schedulizer, and the developers working on it - - AboutPage/TeamMemberProfile - Handles team members as objects to display uniformly - - HelpPage - Displays information that will help new users learn to use the application - - HarmonyPage - Highly Experimental - A system meant to create an ideal schedule based on constraints, currently nonfunctional and not under active development NOT IN USE NOW - - Reusables Folder - Handles object-classes that are used in various parts of the app -- Important Files - src/utilities - - Contexts - Establish the global state of the app - - Helpers - Provide various helpful functions for development use - - Hooks - Provide hooks for interacting with the schedule - - Interfaces - Define the app interfaces and data interfaces - - Reducers - Provide a function to perform multiple setState updates at once that depend on each other. - - Services - Provide services for eg: detecting conflict, calculate faculty load, etc. - diff --git a/README.md b/README.md index ffe01e15..75fc93b8 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,42 @@ -#

Course Schedulizer

+

Course Schedulizer

-📝 **Create semester schedules without stress.** This is the monorepository for the [`senior-knights/course-schedulizer`](https://github.com/senior-knights/course-schedulizer) project. For more information about the application, please view the [About Page](https://senior-knights.github.io/course-schedulizer/#/about) on our website. For help using the application, visit our [Help Page](https://senior-knights.github.io/course-schedulizer/#/help) (once we make it). +[![calvin knights](https://img.shields.io/badge/calvin_knights-8C2131?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAB8lBMVEUAAAB4eHgZUUa+lp2ShYdOT1EvLS7/2ewfHh4oJif///9ISU8uLCzQwpcICAUxLzBGREU7OTpxbm5tbGsACgZvbm0rXlRRT1BSUFD//9IeHiBTUVF1dHJXamRoZmUBBDC3spvw26AJCQxFTnBubW4CBTS/t5r//8IVFht/gYCacniaWWOqeICvlZp9cnQAAAB1c3OgjI+dZW+ZPk6cgYd9fn6ri5DCrYkpOVcuLCxPT0+Be3yZWGTryWmhl30hICCAfn+ylZm5nXgAAENWVVWhl5mkhY3ewX2yholxc3QAAAAAAEHIsXGxhoxzdHMYWktUZGmQjILszHWzlXoAAD5JTk2XhYiqfH6teHvNlnSjl39ESkmci4/Rq3/FrYhxcm8WPlGdmILUunH2ylLTu3ZRWnVtcYG5qX7pxF3rwmCqn34AF2SZk4TUuG7XumxeZn9xc320poOimIGeRFSgR1K7gIiYOEmpVlXkuIXwyX/wxnSlTVLu0KL/+Nz//e//7rOhTl3Tn4P//Or9+/rv2sTZqIHPkFz22aHJmJ+7en+7fIe7e4btw3W9gIy5eoW+g429gIrz05rfwL3LnajFh3D0w1z/3nn/773u0Y7uuVbIhFytX2HGhGTntmzOmHznr1O0Z1ieRFXTl2L5x0nlrlr3ykssme+IAAAAc3RSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACax+vrLLAJBfcz+hDrYvw0DCjTc808NgeSiAzOgrOrcHQIFnt4eAQ9j+Z8DEXfN6/5wDoLuzCIDQ8L9vg8WhOz6XgNEwsgUG5lvA/jZ2AAAAI1JREFUCNc9y8FHQwEAx/Hf5xIREzNj0mGKmTEdslT2GJP+3yfR28syKdJhpEP/RsQuO7yt48fXV4Rz8GUjBwMoqNf+5NBQAZX1r6MRprDwSWu8E08+HLtoVirvkvblP18lnavdXXuR7i3cYFmTXtGAZ5XkZLavHiU5NefaygNJkv4dkzflT8Ocuaf0vQXX3B/iTs/DcAAAAABJRU5ErkJggg==)](https://www.calvin.edu) +[![calvin computer science](https://img.shields.io/badge/calvin_cs-F3CD00?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAB8lBMVEUAAAB4eHgZUUa+lp2ShYdOT1EvLS7/2ewfHh4oJif///9ISU8uLCzQwpcICAUxLzBGREU7OTpxbm5tbGsACgZvbm0rXlRRT1BSUFD//9IeHiBTUVF1dHJXamRoZmUBBDC3spvw26AJCQxFTnBubW4CBTS/t5r//8IVFht/gYCacniaWWOqeICvlZp9cnQAAAB1c3OgjI+dZW+ZPk6cgYd9fn6ri5DCrYkpOVcuLCxPT0+Be3yZWGTryWmhl30hICCAfn+ylZm5nXgAAENWVVWhl5mkhY3ewX2yholxc3QAAAAAAEHIsXGxhoxzdHMYWktUZGmQjILszHWzlXoAAD5JTk2XhYiqfH6teHvNlnSjl39ESkmci4/Rq3/FrYhxcm8WPlGdmILUunH2ylLTu3ZRWnVtcYG5qX7pxF3rwmCqn34AF2SZk4TUuG7XumxeZn9xc320poOimIGeRFSgR1K7gIiYOEmpVlXkuIXwyX/wxnSlTVLu0KL/+Nz//e//7rOhTl3Tn4P//Or9+/rv2sTZqIHPkFz22aHJmJ+7en+7fIe7e4btw3W9gIy5eoW+g429gIrz05rfwL3LnajFh3D0w1z/3nn/773u0Y7uuVbIhFytX2HGhGTntmzOmHznr1O0Z1ieRFXTl2L5x0nlrlr3ykssme+IAAAAc3RSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACax+vrLLAJBfcz+hDrYvw0DCjTc808NgeSiAzOgrOrcHQIFnt4eAQ9j+Z8DEXfN6/5wDoLuzCIDQ8L9vg8WhOz6XgNEwsgUG5lvA/jZ2AAAAI1JREFUCNc9y8FHQwEAx/Hf5xIREzNj0mGKmTEdslT2GJP+3yfR28syKdJhpEP/RsQuO7yt48fXV4Rz8GUjBwMoqNf+5NBQAZX1r6MRprDwSWu8E08+HLtoVirvkvblP18lnavdXXuR7i3cYFmTXtGAZ5XkZLavHiU5NefaygNJkv4dkzflT8Ocuaf0vQXX3B/iTs/DcAAAAABJRU5ErkJggg==)](https://computing.calvin.edu) +[![schedulizer production server](https://img.shields.io/badge/schedulizer-blue?logo=github&logoColor=black)](https://senior-knights.github.io/course-schedulizer/) +[![schedulizer github repo deployment status](https://img.shields.io/github/actions/workflow/status/senior-knights/course-schedulizer/deploy.yml?branch=production&logo=github)](https://github.com/senior-knights/course-schedulizer) +[![schedulizer development server](https://img.shields.io/badge/develop-blue?logo=netlify&logoColor=black)](https://sharp-babbage-a45ee2.netlify.app/) +[![github creation time](https://img.shields.io/github/created-at/senior-knights/course-schedulizer?logo=github)](https://github.com/senior-knights/course-schedulizer) +[![github contributors](https://img.shields.io/github/contributors/senior-knights/course-schedulizer?logo=github)](https://github.com/senior-knights/course-schedulizer) +[![github license](https://img.shields.io/github/license/senior-knights/course-schedulizer)](https://github.com/senior-knights/course-schedulizer) -prod build -deployment status -https://senior-knights.github.io/course-schedulizer/ -dev build +_Create academic course schedules without stress._ -> Created by current students at [Calvin University](https://calvin.edu/) for their [computer science senior project](https://cs.calvin.edu/courses/cs/396/). -> Find DOCUMENTATION at our [documentation page](https://docs.google.com/document/d/1lzlC1wNSYjhr5y5d4IxUpMyLuw5_kaxHmdN8W6C4j00/edit?usp=sharing). +This is the repository for the Course Schedulizer project created by students at [Calvin University](https://calvin.edu/) for the [Computer Science senior project](https://cs.calvin.edu/courses/cs/396/). For more information: -## Built with - -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ - -## Background - -Every year, all department chairs at Calvin must develop a schedule for their department’s classes based on a spreadsheet provided to them by the Registrar. The schedule must contain the times, professors, and rooms for every class section in the department and the schedule must satisfy many constraints, for example: only one section can be in a room at a time, a professor can only teach one section at a time, among others. These constraints make it extremely difficult for the department chair to create a schedule without a tool to help them. We propose building a web application, named the Course Schedulizer, that will allow department chairs to visualize and manipulate their department course schedules. It will provide: the ability to upload and export department schedules via CSV, integration with the spreadsheets provided and required by the Registrar, two views to visualize the schedule data (by location and by instructor), schedule conflict detection and resolution suggestions (for the honors portion), and many other features. - -For more information, please visit the [About Page](https://senior-knights.github.io/course-schedulizer/#/about). - -## How to use - -Detailed information can be found on our [Help Page](https://senior-knights.github.io/course-schedulizer/#/help) (once we make it). Access our production website and upload a CSV following the prescribed specifications (items marked with * are optional and ignored, but were required in older versions of the app) - -- Department: string (like `Mathematics`) -- *Term: [0-9][0-9]/(FA | SP | IN) (like `21/SP` for Spring 2021) -- TermStart: mm/dd/yyyy (like `3/29/2021` or `12/1/2022`) -- *AcademicYear: yyyy (like `2021`) -- *SectionName: SubjectCode-CourseNum-SectionCode (like `MATH-252-B`) -- SubjectCode: string (like `MATH`) -- CourseNum: string (like `252` or `252L` for a lab) -- SectionCode: string (like `B`) -- CourseLevelCode: pos num (like `200` for a 200 level course) -- MinimumCredits: pos num (like `3` or `3.5`) -- FacultyLoad: pos num (like `4` or `4.5`) -- *Used: pos num (like `20`) -- *Day10Used: pos num (like `22`) -- *LocalMax: pos num (like `25`) -- *GlobalMax: pos num (like `30`) -- *RoomCapacity: pos num (like `32`) -- BuildingAndRoom: string (like `HH 345`) -- MeetingDays: M?T?W?(TH)?F? (like `MWTHF`) -- MeetingTime: xx:xx(AM | PM) - xx:xx(AM | PM) (like `9:00AM - 9:50AM`) -- SectionStartDate: mm/dd/yyyy (like `3/29/2021` or `12/1/2022`) -- SectionEndDate: mm/dd/yyyy (like `3/29/2021` or `12/1/2022`) -- *Building: string (like `HH`) -- *RoomNumber: string (like `345`) -- MeetingStart: xx:xx(AM | PM) (like `2:30PM`) -- *MeetingStartInternal: xx:xx:xx 24-hour (like `14:30:00`) -- MeetingEnd: xx:xx(AM | PM) (like `3:20PM`) -- *MeetingEndInternal: xx:xx:xx 24-hour (like `13:20:00`) -- *Monday: `M` or empty -- *Tuesday: `T` or empty -- *Wednesday: `W` or empty -- *Thursday: `TH` or empty -- *Friday: `F` or empty -- ShortTitle: string (like `Number Theory`) -- Faculty: string (first and last) (like `Paul Erdos`) -- *SectionStatus: string (like `Active`) -- InstructionalMethod: `LEC`, `CPI`, `IND`, `TUT`, or `SEM` -- DeliveryMode: `In-person`, `Online (synchronous)`, `Online (asynchronous)`, `Hybrid` - -## Development - -### Basic Introduction - -This is a mono repository for the Course Schedulizer project. It is best used with [VS Code](https://code.visualstudio.com/). To begin editing, open the [workspace file](.vscode/course-schedulizer.code-workspace), located in `.vscode/`, with VS Code. Opening the workspace in VS Code will prompt to install extensions; please do so. - -This provides information about the root repository, for the client app information, please view the [`client-course-schedulizer/README.md`](./client-course-schedulizer/README.md). +- on the purpose of the application, see the [About page](https://senior-knights.github.io/course-schedulizer/#/about). +- on how to use the application, see the [Help page](https://senior-knights.github.io/course-schedulizer/#/help). +- on system development, see the [Course Schedulizer Client](client-course-schedulizer/README.md). ### Development Philosophy -`production` branch is a persistent branch that contains the most stable version of the Course Schedulizer. It requires two reviews to merge PRs to this branch. +We generally follow the [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) collaboration model, with production, development, and feature branches. -`develop` branch is a persistent branch that contains the cutting edge version of the Course Schedulizer. It requires one review to merge PRs to this branch. Each PR is ideally around 100-200 LOC. +- The `production` branch is a persistent branch that contains the most stable version of the Course Schedulizer. It requires two reviews to merge PRs to this branch. +- The `develop` branch is a persistent branch that contains the cutting edge version of the Course Schedulizer. It requires one review to merge PRs to this branch. Each PR is ideally around 100-200 LOC. +- Feature branches are cloned from `develop` and are used for developing new features. They are merged back into `develop` when the feature is complete. Code reviews are done on every PR merged into the two persistent branches. A PR is made with a branch following the naming convention of `/`. `` are things like `feature`, `docs`, `chore`, `fix`, etc. ### Repository Configuration +The repo is a [monorepository](https://en.wikipedia.org/wiki/Monorepo), to spite the fact that it comprises only one application, stored in `./client-course-schedulizer`. This historical artifact leaves open the possibility of adding applications in the future. + Because the application is open source, we use free minutes of GitHub actions to perform CI/CD. `ci.yml` tests on any push or PR against `develop` or `production`. -`.vscode/` contains the directory settings. It most notably uses Prettier to format code on save. Formatting will fix ESLint issues, organize imports, and then fix Editor Config and Prettier issues. `.editorconfig` and `.prettierrc.js` are located in the root, and `.eslint.js` is specific to each application. For example, the client config is located inside the client folder. +The directory settings, stored in `.vscode/.`, specify the use of: + +- [EditorConfig](https://editorconfig.org/), which specifies shared editor configuration parameters (see `.editorconfig`) +- [Prettier](https://prettier.io/), which formats code and organizes imports (see `.prettierrc.js`) +- [ESLint](https://eslint.org/), which specifies formatting rules (see `client-course-schedulizer/.prettierrc.js`). + +You can add your own user-specific VS Code extensions, but be sure to use these recommended, shared settings and extensions. diff --git a/client-course-schedulizer/README.md b/client-course-schedulizer/README.md index d63f98eb..00397ed5 100644 --- a/client-course-schedulizer/README.md +++ b/client-course-schedulizer/README.md @@ -1,47 +1,71 @@ -# Client Course Schedulizer +# Course Schedulizer Client -📝 **Create semester schedules without stress.** This is the client folder for the [`senior-knights/course-schedulizer`](https://github.com/senior-knights/course-schedulizer) project. For more information about the application, please view the [About Page](https://senior-knights.github.io/course-schedulizer/#/about) on our website. For help using the application, visit our [Help Page](https://senior-knights.github.io/course-schedulizer/#/help) (once we make it). +The Course Schedulizer is a single-page application that allows users to view and interact with course schedules. The client is built with a focus on user experience and accessibility. See the [Calvin Knights root](../README.md) for general information on this project. -prod build -deployment status -https://senior-knights.github.io/course-schedulizer/ -dev build +[![node js](https://img.shields.io/badge/node_js-000?logo=node.js)](https://nodejs.org) +[![pnpm](https://img.shields.io/badge/pnpm-000?logo=pnpm)](https://pnpm.io/) +[![react js](https://img.shields.io/badge/react_js-000?logo=react)](https://react.dev/) +[![create react app](https://img.shields.io/badge/create_react_app-000?logo=createreactapp)](https://create-react-app.dev/) +[![typescript](https://img.shields.io/badge/typescript-000?logo=typescript)](https://www.typescriptlang.org/) +[![github](https://img.shields.io/badge/github-121013?logo=github&logoColor=white)](https://github.com/) +[![github pages](https://img.shields.io/badge/github_pages-121013?logo=github&logoColor=white)](https://pages.github.com/) +[![netlify](https://img.shields.io/badge/netlify-000?logo=netlify)](https://www.netlify.com/) +[![vscode](https://img.shields.io/badge/vscode-000?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAE+SURBVHgBjVJNToNAFP5moInpiiPIDdqauDY9gh6g1BO4s9EFYceqqRcQepEat02UjXvaE8hGtBHmOdMiZQAjb8FLePP9vB+GLuG+Adn3BJS5YKaHHM/whxvWEeiA8kAvsIDv801k/QluBaogh+PuxUU/j2UOGiT30aQdeAgOkW9lthQT+lmE2+i0Agxr7xPN+P47WzvgvFCgDQhLMOYeHVIMRlcgPpeIi9+/x4FpBFpEEMYlTnpb7L5WVTAvn/jnIUgsNRhJF6kxVmtpIS1sN9dBZQ3SsjDH7cpN4DsE8woCxWGDZyt8pIO6Mj9cTgFUgxHGCP6ZByGuKwZt9PirVB3oYMpsObdY9hvi0xyV/akZCDGtiVnNntVxLIYJ2mK2nsotPLZUqNtt79I6QSIn8vQ/WCeYS8EHpOZCOf0BmnSexRUGtfwAAAAASUVORK5CYII=)](https://code.visualstudio.com/) -> Created by current students at [Calvin University](https://calvin.edu/) for their [computer science senior project](https://cs.calvin.edu/courses/cs/396/). +## Development -## Built with +Development is best done using [VS Code](https://code.visualstudio.com/) and the pre-defined project [workspace](https://code.visualstudio.com/docs/editor/workspaces). To begin editing, open the [workspace file](.vscode/course-schedulizer.code-workspace) with VS Code. This will configure VS Code [settings](https://code.visualstudio.com/docs/getstarted/settings) and prompt you to install the recommended VS Code [extensions](https://code.visualstudio.com/docs/editor/extension-marketplace), which helps maintain the consistency and quality of the project codebase. -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ -https://senior-knights.github.io/course-schedulizer/ +## Workflows -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). +To work with this GitHub codebase, `git clone` this repo and `cd` into the new repo sub-directory. -## How to use +**To run the Schedulizer locally:** -`csv/` contains test files for the application. +1. `git checkout` the branch you want to work on (e.g., your dedicated feature branch). +1. `cd client-course-schedulizer` to move into the monorepo’s client application sub-directory. +1. `pnpm install` to install the required NodeJS packages as specified in `package.json`. +1. `pnpm start` to run the website on [localhost:3000](http://localhost:3000). -`public/` contains files import when deploying the application. +Edits you make to the code will automatically update the website in your browser. -`src/` contains all source files that build the client application. For development techniques, see below. +**To deploy the Schedulizer to the development server:** -`.eslintrc.js` is a specific ESLint config. `.env` allows for overriding the Create React App ESLint config. +1. Create a pull request to merge your fully-implemented-and-tested feature branch into the `develop` branch. -The `.tsconfig` has been modified to allow for barreling and absolute imports. +When the PR is approved, the development server, configured on Netlify, will auto-deploy the new version of the `develop` branch. See the: -[Husky](https://typicode.github.io/husky/#/) is used with [Lint Staged](https://github.com/okonet/lint-staged) to format all code to the ESLint rules when they are committed. This insures that changes pushed are not confused by changing syntax or code style. +- Development server dashboard at [https://app.netlify.com/sites/sharp-babbage-a45ee2](https://app.netlify.com/sites/sharp-babbage-a45ee2) +- Running application at: [https://sharp-babbage-a45ee2.netlify.app](https://sharp-babbage-a45ee2.netlify.app) -## Development +**To deploy a new production version of the Schedulizer to the production server:** + +Follow the same workflow as for the development server, but merge your feature branch into the `production` branch. The production server, configured on GitHub Pages, will auto-deploy the new version of the `production` branch. See the: + +- Running application at [https://senior-knights.github.io/course-schedulizer](https://senior-knights.github.io/course-schedulizer). -This will go through the development process for the `client-course-schedulizer` application. +MUST DOCUMENT THE CI AND DEPLOY STUFF. + +NOT SURE WHERE TO PUT THIS YET. + +- .github/workflows: the github auto-test and auto-deploy scripts + - ci.yml: automatically test the latest update + - Trigger: push to all branches, PR to `develop` and `production` + - Work environment: ./client-course-schedulizer + - Steps: + - Set up actions for pnpm and node + - Update pnpm version + - Install pnpm dependencies + - Run pnpm test on the latest push or PR + - deploy.yml: auto-deploy + - This script is not updated to use pnpm yet, must be updated before pushing to `production` or error will occur ### Available Scripts In the project directory, you can run: +NEEDS TO BE FIXED... + #### `npm start` Runs the app in the development mode. @@ -63,9 +87,40 @@ Builds the app for production to the `build` folder. It correctly bundles React Used by GitHub actions to deploy the build. Will trigger `predeploy` command. +[Husky](https://typicode.github.io/husky/#/) is used with [Lint Staged](https://github.com/okonet/lint-staged) to format all code to the ESLint rules when they are committed. This insures that changes pushed are not confused by changing syntax or code style. + +## Directories + +- `csv/` contains sample course schedules in `.csv` and `.xlsx` formats. The files include new and old formats, which are not compatible. + +- `public/` contains files to import when deploying the application. + +- `src/` contains all source files that build the client application. + + - `src/assets` contains images utilized by the application + - `src/components` contains the basic components used in the UI. Note that `pages/HarmonyPage` has been removed from the UI. + - `src/data` contains constraints on times within which classes may start. These constraints are run in R. Ask Prof. Pruim for more information about how this is done. + - `src/styles` establishes colors and fonts used in the application. + - `src/types` establishes objects used in the application (it's best not to alter this). + - `src/utilities` provides various functions and objects to help the application function (to be discussed in further detail later). + - Other files handle server operations. + +- `utilities/` contains various utilities. + + - `utilities/contexts` establishes the global state of the app. + - `utilities/helpers` provides various helpful functions for development use. + - `utilities/hooks` provides hooks for interacting with the schedule. + - `utilities/interfaces` defines the app interfaces and data interfaces. + - `utilities/reducers` provides functions to perform multiple setState updates at once that depend on each other. + - `utilities/services` provides services, e.g., for detecting conflict, calculating faculty load, etc. + +- `.eslintrc.js` is a specific ESLint config. `.env` allows for overriding the Create React App ESLint config. + +- `.tsconfig` has been modified to allow for barreling and absolute imports. + ## Development Philosophy -React's functional programming is great for dealing with complex, stateful user interfaces. With React, all data is either primitives or an object (which includes functions) since the library focuses on immutability. Each React component defines how every view will behave for a given state. Generally, each view is rendered whenever the data is updated. +React’s functional programming is great for dealing with complex, stateful user interfaces. With React, all data is either primitives or an object (which includes functions) since the library focuses on immutability. Each React component defines how every view will behave for a given state. Generally, each view is rendered whenever the data is updated. ### Barrelling diff --git a/client-course-schedulizer/package.json b/client-course-schedulizer/package.json index 42df3ee9..ff6ef07d 100644 --- a/client-course-schedulizer/package.json +++ b/client-course-schedulizer/package.json @@ -5,7 +5,6 @@ "homepage": ".", "scripts": { "build": "react-scripts build", - "predeploy": "npm run build", "deploy": "gh-pages -d build", "eject": "react-scripts eject", "start": "react-scripts start", diff --git a/client-course-schedulizer/pnpm-lock.yaml b/client-course-schedulizer/pnpm-lock.yaml index d8ce7c1b..b11b5ba4 100644 --- a/client-course-schedulizer/pnpm-lock.yaml +++ b/client-course-schedulizer/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: true diff --git a/client-course-schedulizer/src/components/pages/AboutPage/AboutPage.tsx b/client-course-schedulizer/src/components/pages/AboutPage/AboutPage.tsx index 5adc99c6..78d5d57a 100644 --- a/client-course-schedulizer/src/components/pages/AboutPage/AboutPage.tsx +++ b/client-course-schedulizer/src/components/pages/AboutPage/AboutPage.tsx @@ -46,9 +46,9 @@ const AboutVision = () => {
  • Faculty teaching loads cannot be “too high” or “too low”
  • These constraints make it extremely difficult for the department chair to create a - schedule without a tool to help them. We are building and adding on to a web application, named the - Course Schedulizer, that will allow department chairs to visualize and manipulate their - department course schedules. It will provide: + schedule without a tool to help them. We are building and adding on to a web application, + named the Course Schedulizer, that will allow department chairs to visualize and + manipulate their department course schedules. It will provide:
    • The ability to upload and export department schedules via CSV
    • Integration with the spreadsheets provided and required by the Registrar
    • @@ -60,16 +60,15 @@ const AboutVision = () => {
    • An optimized user interface with an efficient use of screen space
    • An extensible interface to integrate with future systems (e.g. Workday)
    - By offering these features and developing continuous improvements on the functionality previously implemented by - Professor Pruim and Professor VanderLinden, the Course Schedulizer will allow department - chairs to easily create their schedules. + By offering these features and developing continuous improvements on the functionality + previously implemented by Professor Pruim and Professor VanderLinden, the Course + Schedulizer will allow department chairs to easily create their schedules.

    - There is also a past Honors Project completed in year 2020 by Charles. It is a second project relating to constraint - problem satisfaction alongside the Course Schedulizer. By employing constraint - satisfaction techniques, Charles has developed the ability to upload a - list of classes, professors, rooms, and times to the Course Schedulizer web application - and have the system create a schedule with no conflicts. + There was also a component developed for an Honors Project completed in year 2020 by + Charles Kornoelje. It allowed users to upload a list of classes, professors, rooms, and + times into the Schedulizer and then employed constraint satisfaction techniques to create + a schedule with no conflicts. This component has been removed. } title="Vision" @@ -157,20 +156,17 @@ const AboutCode = () => { - This website is our code built and deployed. Feel free to play around with the site. Our - code repository is{" "} +

    For details on the Schedulizer codebase and development process, see the{" "} - hosted on GitHub + GitHub code repository - . We have two persistent branches: production and develop.{" "} - production is the working, stable build of the web application and{" "} - develop is the less-stable, bleeding-edge build of our Course Schedulizer - app. Please feel free to look around the code and interact with us on the discussion board - or by posting issues. The honors constraint satisfaction package from year 2020 is also{" "} - hosted on GitHub. The - Harmoniously project code is also{" "} - hosted on GitHub. - For details on the development process, please view the respective ReadMe files on GitHub. + .
    +
    + The original release of the Schedulizer included{" "} + Harmoniously, an + honors project that automatically generated schedules using{" "} + csps, a TypeScript port + of Russell & Norvig’s constraint satisfaction algorithm. } title="Code" @@ -255,27 +251,27 @@ const AboutResources = () => {
  • Final Presentation Slides - - - 4.23.2024 + {" "} + - 4.23.2024
  • Status Report Slides - - - 12.5.2023 + {" "} + - 12.5.2023

  • Final Presentation Slides - - - 4.19.2022 + {" "} + - 4.19.2022
  • Status Report Slides - - - 12.07.2021 + {" "} + - 12.07.2021

  • diff --git a/client-course-schedulizer/src/components/pages/HelpPage/HelpPage.tsx b/client-course-schedulizer/src/components/pages/HelpPage/HelpPage.tsx index 3160e2cb..65b67dec 100644 --- a/client-course-schedulizer/src/components/pages/HelpPage/HelpPage.tsx +++ b/client-course-schedulizer/src/components/pages/HelpPage/HelpPage.tsx @@ -1,106 +1,250 @@ -import React from "react"; import { Page } from "components/reuseables"; +import React from "react"; import { TextSection } from "../AboutPage/."; export const HelpPage = () => { - return ( - - - - - - ); + return ( + + + + + + ); }; const Functionality = () => { - return ( - - Beginning from blank - Click the Calvin University logo in the upper left corner to make sure you're on the starting page, - then click "Add Section" to input a class. In the "Formatting" section on this page (below this text), you can read about some - recommended ways to format your inputs. Fill in all the values according to the class's parameters. - - Once you've created a class, your screen will change to show a calendar view. To add another class, click the "plus" (+) symbol - at the right side of the gray bar (this bar appears on the faculty schedule, room schedule, and department schedule pages). - - If you find yourself in the "Add Section" screen unintentionally, or need to back out of it for any reason, simply press your "Escape" key - on your keyboard and you will return to where you were before. -
    -
    - Importing CSV - Presently, the system allows for the import of .csv files. You can import these files by clicking the "Import CSV" button on the main page, - or by clicking the "Hamburger menu" (three lines in the upper left corner of the screen) and selecting "Import New Schedule." - - } - title="Help" - /> - ); + return ( + + To create a schedule from scratch: +
      +
    1. + Click the Calvin University logo in the upper left corner to make sure you’re on + the starting page. +
    2. +
    3. Click “Add Section” to input a class.
    4. +
    5. + In the “Formatting” section on this page (see below), you can read about + some recommended ways to format your inputs. Fill in all the values as appropriate for + the class. Once you’ve created a class, your screen will change to show a + calendar view. +
    6. +
    7. + To add another class, click the “plus” (+) symbol at the right side of the + gray bar (this bar appears on the faculty schedule, room schedule, and department + schedule pages). +
    8. +
    + If you find yourself in the “Add Section” screen unintentionally, or need to + back out of it for any reason, simply press your "Escape" key on your keyboard and you + will return to where you were before. +
    +
    + To edit an existing schedule, load a schedule CSV file by clicking: +
      +
    • The “Import CSV” button on the main page.
    • +
    • + The “Hamburger menu” (three lines in the upper left corner of the screen) + and selecting “Import New Schedule”. +
    • +
    + + } + title="Help" + /> + ); }; const FormatSegment = () => { return ( - - - This is a work in progress Help page that team 2023 is continuing to update. - - Below is provided some formatting help: -
      -
    • Department: string (like `Mathematics`)
    • -
    • *Term: (FA | SP | IN) (like `SP` for Spring)
    • -
    • TermStart: mm/dd/yyyy (like `3/29/2021` or `12/1/2022`)
    • -
    • *AcademicYear: yyyy (like `2021`)
    • -
    • *SectionName: SubjectCode-CourseNum-SectionCode (like `MATH-252-B`)
    • -
    • SubjectCode: string (like `MATH`)
    • -
    • CourseNum: string (like `252` or `252L` for a lab)
    • -
    • SectionCode: string (like `B`)
    • -
    • CourseLevelCode: pos num (like `200` for a 200 level course)
    • -
    • MinimumCredits: pos num (like `3` or `3.5`)
    • -
    • FacultyLoad: pos num (like `4` or `4.5`)
    • -
    • *Used: pos num (like `20`)
    • -
    • *Day10Used: pos num (like `22`)
    • -
    • *LocalMax: pos num (like `25`)
    • -
    • *GlobalMax: pos num (like `30`)
    • -
    • *RoomCapacity: pos num (like `32`)
    • -
    • BuildingAndRoom: string (like `HH 345`)
    • -
    • MeetingDays: M?T?W?(TH)?F? (like `MWTHF`)
    • -
    • MeetingTime: xx:xx(AM | PM) - xx:xx(AM | PM) (like `9:00AM - 9:50AM`)
    • -
    • SectionStartDate: mm/dd/yyyy (like `3/29/2021` or `12/1/2022`)
    • -
    • SectionEndDate: mm/dd/yyyy (like `3/29/2021` or `12/1/2022`)
    • -
    • *Building: string (like `HH`)
    • -
    • *RoomNumber: string (like `345`)
    • -
    • MeetingStart: xx:xx(AM | PM) (like `2:30PM`)
    • -
    • *MeetingStartInternal: xx:xx:xx 24-hour (like `14:30:00`)
    • -
    • MeetingEnd: xx:xx(AM | PM) (like `3:20PM`)
    • -
    • *MeetingEndInternal: xx:xx:xx 24-hour (like `13:20:00`)
    • -
    • *Monday: `M` or empty
    • -
    • *Tuesday: `T` or empty
    • -
    • *Wednesday: `W` or empty
    • -
    • *Thursday: `TH` or empty
    • -
    • *Friday: `F` or empty
    • -
    • ShortTitle: string (like `Number Theory`)
    • -
    • Faculty: string (first and last) (like `Paul Erdos`)
    • -
    • *SectionStatus: string (like `Active`)
    • -
    • InstructionalMethod: `LEC`, `CPI`, `IND`, `TUT`, or `SEM`
    • -
    • DeliveryMode: `In-person`, `Online (synchronous)`, `Online (asynchronous)`, `Hybrid`
    • -
    - - } - title="Formatting" - /> + + In the web app, upload a CSV following the prescribed specifications (items marked with * + are optional and ignored, but were required in older versions of the app) +
      +
    • + {" "} + Department: string (e.g., Mathematics) +
    • +
    • + {" "} + *Term: (FA | SP | IN) (e.g., SP for Spring) +
    • +
    • + {" "} + TermStart: mm/dd/yyyy (e.g., 3/29/2021 or{" "} + 12/1/2022) +
    • +
    • + {" "} + *AcademicYear: yyyy (e.g., 2021) +
    • +
    • + {" "} + *SectionName: SubjectCode-CourseNum-SectionCode (e.g.,{" "} + MATH-252-B) +
    • +
    • + {" "} + SubjectCode: string (e.g., MATH) +
    • +
    • + {" "} + CourseNum: string (e.g., 252 or 252L for a + lab) +
    • +
    • + {" "} + SectionCode: string (e.g., B) +
    • +
    • + {" "} + CourseLevelCode: pos num (e.g., 200 for a 200 level + course) +
    • +
    • + {" "} + MinimumCredits: pos num (e.g., 3 or 3.5) +
    • +
    • + {" "} + FacultyLoad: pos num (e.g., 4 or 4.5) +
    • +
    • + {" "} + *Used: pos num (e.g., 20) +
    • +
    • + {" "} + *Day10Used: pos num (e.g., 22) +
    • +
    • + {" "} + *LocalMax: pos num (e.g., 25) +
    • +
    • + {" "} + *GlobalMax: pos num (e.g., 30) +
    • +
    • + {" "} + *RoomCapacity: pos num (e.g., 32) +
    • +
    • + {" "} + BuildingAndRoom: string (e.g., HH 345) +
    • +
    • + {" "} + MeetingDays: M?T?W?(TH)?F? (e.g., MWTHF) +
    • +
    • + {" "} + MeetingTime: xx:xx(AM | PM) - xx:xx(AM | PM) (e.g.,{" "} + 9:00AM - 9:50AM) +
    • +
    • + {" "} + SectionStartDate: mm/dd/yyyy (e.g., 3/29/2021 or{" "} + 12/1/2022) +
    • +
    • + {" "} + SectionEndDate: mm/dd/yyyy (e.g., 3/29/2021 or{" "} + 12/1/2022) +
    • +
    • + {" "} + *Building: string (e.g., HH) +
    • +
    • + {" "} + *RoomNumber: string (e.g., 345) +
    • +
    • + {" "} + MeetingStart: xx:xx(AM | PM) (e.g., 2:30PM) +
    • +
    • + {" "} + *MeetingStartInternal: xx:xx:xx 24-hour (e.g., 14:30:00) +
    • +
    • + {" "} + MeetingEnd: xx:xx(AM | PM) (e.g., 3:20PM) +
    • +
    • + {" "} + *MeetingEndInternal: xx:xx:xx 24-hour (e.g., 13:20:00) +
    • +
    • + {" "} + *Monday: M or empty +
    • +
    • + {" "} + *Tuesday: T or empty +
    • +
    • + {" "} + *Wednesday: W or empty +
    • +
    • + {" "} + *Thursday: TH or empty +
    • +
    • + {" "} + *Friday: F or empty +
    • +
    • + {" "} + ShortTitle: string (e.g., Number Theory) +
    • +
    • + {" "} + Faculty: string (first and last) (e.g., Paul Erdos) +
    • +
    • + {" "} + *SectionStatus: string (e.g., Active) +
    • +
    • + {" "} + InstructionalMethod: LEC, CPI,{" "} + IND, TUT, or SEM +
    • +
    • + {" "} + DeliveryMode: In-person,{" "} + Online (synchronous), Online (asynchronous),{" "} + Hybrid +
    • +
    + + } + title="Formatting" + /> ); }; const Faq = () => { - return ( - - Frequently Asked Questions - To be developed over time - - } - title="FAQ" - /> - ); -} \ No newline at end of file + return ( + + Frequently Asked Questions + + + } + title="FAQ" + /> + ); +}; diff --git a/client-course-schedulizer/src/utilities/helpers/caseFunctions.ts b/client-course-schedulizer/src/utilities/helpers/caseFunctions.ts index a6136a7f..fc08423d 100644 --- a/client-course-schedulizer/src/utilities/helpers/caseFunctions.ts +++ b/client-course-schedulizer/src/utilities/helpers/caseFunctions.ts @@ -1,6 +1,6 @@ import { cloneDeep, forEach } from "lodash"; import moment from "moment"; -import { Case } from "runtypes"; +//import { Case } from "runtypes"; import { emptyMeeting } from "utilities/constants"; import { Course, Day, Meeting, Section, SemesterLength, Term } from "utilities/interfaces"; @@ -85,7 +85,7 @@ export const timeCallback = (value: string, params: CaseCallbackParams) => { timeParts.forEach((time) => { const startTime = time.split(" ").join("").split("-")[0]; startTimes += startTime + "\n"; - }) + }); startTimeCallback(startTimes, params); durationCallback(value, params); @@ -105,7 +105,9 @@ export const durationCallback = (value: string, params: CaseCallbackParams) => { export const locationCallback = (value: string, params: CaseCallbackParams) => { assignWithMeetings(value, params, (location, i, meetings) => { - [meetings[i].location.building, meetings[i].location.roomNumber] = locationCase(location.split("-")[0]); + [meetings[i].location.building, meetings[i].location.roomNumber] = locationCase( + location.split("-")[0], + ); }); }; @@ -140,12 +142,12 @@ export const courseCallback = (value: string, { course }: CaseCallbackParams) => course.department = value.split(" ")[0]; course.prefixes = [value.split(" ")[0]]; course.number = value.split(" ")[1]; -} +}; export const courseSectionCallback = (value: string, { course, section }: CaseCallbackParams) => { section.letter = value.split("-")[1]; course.name = value.split("-")[2]; -} +}; export const prefixCallback = (value: string, { course }: CaseCallbackParams) => { course.prefixes = value === "" ? [] : prefixCase(value); @@ -188,7 +190,7 @@ export const yearCallback = (value: string, { section }: CaseCallbackParams) => export const semesterHourCallback = (value: string, params: CaseCallbackParams) => { studentHoursCallback(value, params); facultyHoursCallback(value, params); -} +}; export const studentHoursCallback = (value: string, { section }: CaseCallbackParams) => { // Remove '$' is Excel prepended it to the student hours diff --git a/client-course-schedulizer/src/utilities/helpers/teamMembers.ts b/client-course-schedulizer/src/utilities/helpers/teamMembers.ts index fe1bad6e..10ec5743 100644 --- a/client-course-schedulizer/src/utilities/helpers/teamMembers.ts +++ b/client-course-schedulizer/src/utilities/helpers/teamMembers.ts @@ -63,7 +63,7 @@ export const team2022: TeamMember[] = [ bio: "Computer Science Student at Calvin University.", name: "Samuel Haileselassie", - photo: "https://media-exp1.licdn.com/dms/image/C5603AQH8mr-DiG2BEw/profile-displayphoto-shrink_400_400/0/1634434581718?e=1671667200&v=beta&t=RyVTx8CAqQ8RmELiQN5PBXM7Bf2pQGSGu8uO40E7v4k", + photo: "https://avatars.githubusercontent.com/u/66380716?v=4", website: "https://github.com/samuelth47", }, { diff --git a/client-course-schedulizer/src/utilities/helpers/writeFullCSV.ts b/client-course-schedulizer/src/utilities/helpers/writeFullCSV.ts index 12851009..643c75d2 100644 --- a/client-course-schedulizer/src/utilities/helpers/writeFullCSV.ts +++ b/client-course-schedulizer/src/utilities/helpers/writeFullCSV.ts @@ -4,7 +4,7 @@ import { Schedule, Section, Term } from "utilities/interfaces"; import { getLocationString } from "utilities/services"; export const scheduleToFullCSVString = (schedule: Schedule): string => { - const numericReg = RegExp("[0-9]"); + //const numericReg = RegExp("[0-9]"); // Sorts the schedule object by dept, class number, section letter, term schedule.courses = schedule.courses.sort((a, b): number => { @@ -44,17 +44,18 @@ export const scheduleToFullCSVString = (schedule: Schedule): string => { // Iterate through meetings to construct relevant strings let courseName = course.prefixes + " " + course.number + " - " + course.name; - let courseSectionName = course.prefixes + " " + course.number + "-" + section.letter + " - " + course.name; + let courseSectionName = + course.prefixes + " " + course.number + "-" + section.letter + " - " + course.name; let startMoment; let endMoment; - let meetingTimeStr = ""; + // let meetingTimeStr = ""; let meetingStartStr = ""; // let meetingStartInternalStr = ""; let meetingEndStr = ""; // let meetingEndInternalStr = ""; - let meetingDurationMinutesStr = ""; - let buildingStr = ""; - let roomNumberStr = ""; + // let meetingDurationMinutesStr = ""; + // let buildingStr = ""; + // let roomNumberStr = ""; let buildingAndRoomStr = ""; // let roomCapacityStr = ""; let daysStr = ""; @@ -67,22 +68,22 @@ export const scheduleToFullCSVString = (schedule: Schedule): string => { startMoment = moment(meeting.startTime, "h:mm A"); endMoment = startMoment.clone().add(meeting.duration, "minutes"); if (startMoment.isValid()) { - meetingTimeStr += getMeetingTimeStr(startMoment, endMoment); + // meetingTimeStr += getMeetingTimeStr(startMoment, endMoment); meetingStartStr += `${startMoment.format("h:mm A")}\n`; // meetingStartInternalStr += `${startMoment.format("H:mm:ss")}\n`; meetingEndStr += `${endMoment.format("h:mm A")}\n`; // meetingEndInternalStr += `${endMoment.format("H:mm:ss")}\n`; } else { - meetingTimeStr += "\n"; + // meetingTimeStr += "\n"; meetingStartStr += "\n"; // meetingStartInternalStr += "\n"; meetingEndStr += "\n"; // meetingEndInternalStr += "\n"; } - meetingDurationMinutesStr += `${meeting.duration}\n`; + // meetingDurationMinutesStr += `${meeting.duration}\n`; if (meeting.location && meeting.location.building) { - buildingStr += `${meeting.location.building}\n`; - roomNumberStr += `${meeting.location.roomNumber}\n`; + // buildingStr += `${meeting.location.building}\n`; + // roomNumberStr += `${meeting.location.roomNumber}\n`; buildingAndRoomStr += meeting.location.roomNumber ? `${getLocationString(meeting.location)}\n` : `${meeting.location.building}\n`; @@ -96,14 +97,14 @@ export const scheduleToFullCSVString = (schedule: Schedule): string => { // friStr += `${meeting.days.includes(Day.Friday) ? "F" : ""}\n`; }); // Remove trailing newlines - meetingTimeStr = meetingTimeStr.slice(0, -1); + //meetingTimeStr = meetingTimeStr.slice(0, -1); meetingStartStr = meetingStartStr.slice(0, -1); // meetingStartInternalStr = meetingStartInternalStr.slice(0, -1); meetingEndStr = meetingEndStr.slice(0, -1); // meetingEndInternalStr = meetingEndInternalStr.slice(0, -1); - meetingDurationMinutesStr = meetingDurationMinutesStr.slice(0, -1); - buildingStr = buildingStr.slice(0, -1); - roomNumberStr = roomNumberStr.slice(0, -1); + //meetingDurationMinutesStr = meetingDurationMinutesStr.slice(0, -1); + //buildingStr = buildingStr.slice(0, -1); + //roomNumberStr = roomNumberStr.slice(0, -1); buildingAndRoomStr = buildingAndRoomStr.slice(0, -1); // roomCapacityStr = roomCapacityStr.slice(0, -1); daysStr = daysStr.slice(0, -1); @@ -117,7 +118,7 @@ export const scheduleToFullCSVString = (schedule: Schedule): string => { // const sectionNameStr = `${course.prefixes.length ? course.prefixes[0] : ""}-${ // course.number // }-${section.letter}`; - const courseLevelCodeStr = numericReg.test(course.number[0]) ? `${course.number[0]}00` : ""; + //const courseLevelCodeStr = numericReg.test(course.number[0]) ? `${course.number[0]}00` : ""; let meetingPatterns = []; const days = daysStr.split("\n"); @@ -129,10 +130,13 @@ export const scheduleToFullCSVString = (schedule: Schedule): string => { } // Construct a row in the output CSV - csvStr += `${termStr},${courseName},${courseSectionName},${section.status - },${section.studentHours > -1 ? section.studentHours : ""},"${section.instructors.join("\n") - }","${meetingPatterns.join("\n")}",${section.startDate ?? ""},${section.endDate ?? ""},"${buildingAndRoomStr - }","${section.instructionalMethod ?? "" }","${section.comments ?? ""}","${section.timestamp ?? ""}"\n`; + csvStr += `${termStr},${courseName},${courseSectionName},${section.status},${ + section.studentHours > -1 ? section.studentHours : "" + },"${section.instructors.join("\n")}","${meetingPatterns.join("\n")}",${ + section.startDate ?? "" + },${section.endDate ?? ""},"${buildingAndRoomStr}","${section.instructionalMethod ?? ""}","${ + section.comments ?? "" + }","${section.timestamp ?? ""}"\n`; // csvStr += `"${course.department ?? ""}",${termStr // },"${course.prefixes.join("\n")}",${course.number},${section.letter @@ -140,11 +144,11 @@ export const scheduleToFullCSVString = (schedule: Schedule): string => { // },${section.studentHours > -1 ? section.studentHours : ""}, ${section.facultyHours > -1 ? section.facultyHours : ""},"${buildingAndRoomStr // }","${daysStr}","${meetingTimeStr}",${section.startDate ?? ""},${section.endDate ?? ""},${section.semesterLength ?? ""},"${buildingStr // }","${roomNumberStr}","${meetingStartStr}","${meetingDurationMinutesStr - // }","${meetingEndStr}","${ section.name ?? course.name + // }","${meetingEndStr}","${ section.name ?? course.name // }","${section.instructors.join("\n")}","${section.status ?? "" - // }","${section.instructionalMethod ?? "" - // }","${section.deliveryMode ?? "" - // }","${section.group ?? "" + // }","${section.instructionalMethod ?? "" + // }","${section.deliveryMode ?? "" + // }","${section.group ?? "" // }","${section.comments ?? ""}","${section.timestamp ?? ""}"\n`; }); });