From 98fe5f5647203e77ec8ab7c67a17dc0f96ee0c1d Mon Sep 17 00:00:00 2001 From: Adam Oliver Date: Thu, 9 Oct 2025 13:40:34 -0500 Subject: [PATCH] coding challenge submission including: SOLUTION_README.md file explaining approaches and deliverables. functional widget mobile first layout unit testing standards compliant --- septa-fare-calculator/.gitignore | 26 + septa-fare-calculator/README.md | 81 +- septa-fare-calculator/SOLUTION_README.md | 848 ++++++++++++++++++ septa-fare-calculator/eslint.config.js | 23 + septa-fare-calculator/index.html | 21 +- septa-fare-calculator/jest.config.js | 42 + septa-fare-calculator/package.json | 46 + septa-fare-calculator/{ => public}/fares.json | 0 septa-fare-calculator/public/index.html | 12 + .../public/septa-favicon.png | Bin 0 -> 1461 bytes septa-fare-calculator/src/App.css | 17 + septa-fare-calculator/src/App.test.tsx | 143 +++ septa-fare-calculator/src/App.tsx | 18 + .../src/__mocks__/fileMock.js | 8 + septa-fare-calculator/src/assets/fares.json | 155 ++++ .../src/assets/img/septa-logo-light.png | Bin 0 -> 3498 bytes .../src/assets/img/septa-logo-light.svg | 41 + .../{ => src/assets}/img/widget.png | Bin .../{ => src/assets}/img/zone-map.jpg | Bin .../src/components/ErrorComponent.module.scss | 42 + .../src/components/ErrorComponent.test.tsx | 83 ++ .../src/components/ErrorComponent.tsx | 22 + .../src/components/FareCalculator.module.scss | 226 +++++ .../src/components/FareCalculator.test.tsx | 289 ++++++ .../src/components/FareCalculator.tsx | 323 +++++++ .../components/HeaderComponent.module.scss | 82 ++ .../src/components/HeaderComponent.test.tsx | 186 ++++ .../src/components/HeaderComponent.tsx | 25 + septa-fare-calculator/src/index.css | 68 ++ septa-fare-calculator/src/main.tsx | 10 + septa-fare-calculator/src/scss-modules.d.ts | 24 + .../src/styles/_settings.mixins.scss | 37 + .../src/styles/_settings.variables.scss | 31 + septa-fare-calculator/src/test-setup.ts | 40 + septa-fare-calculator/src/test-types.d.ts | 22 + septa-fare-calculator/tsconfig.app.json | 29 + septa-fare-calculator/tsconfig.json | 7 + septa-fare-calculator/tsconfig.node.json | 26 + septa-fare-calculator/vite.config.ts | 7 + 39 files changed, 3049 insertions(+), 11 deletions(-) create mode 100644 septa-fare-calculator/.gitignore create mode 100644 septa-fare-calculator/SOLUTION_README.md create mode 100644 septa-fare-calculator/eslint.config.js create mode 100644 septa-fare-calculator/jest.config.js create mode 100644 septa-fare-calculator/package.json rename septa-fare-calculator/{ => public}/fares.json (100%) create mode 100644 septa-fare-calculator/public/index.html create mode 100644 septa-fare-calculator/public/septa-favicon.png create mode 100644 septa-fare-calculator/src/App.css create mode 100644 septa-fare-calculator/src/App.test.tsx create mode 100644 septa-fare-calculator/src/App.tsx create mode 100644 septa-fare-calculator/src/__mocks__/fileMock.js create mode 100644 septa-fare-calculator/src/assets/fares.json create mode 100644 septa-fare-calculator/src/assets/img/septa-logo-light.png create mode 100644 septa-fare-calculator/src/assets/img/septa-logo-light.svg rename septa-fare-calculator/{ => src/assets}/img/widget.png (100%) rename septa-fare-calculator/{ => src/assets}/img/zone-map.jpg (100%) create mode 100644 septa-fare-calculator/src/components/ErrorComponent.module.scss create mode 100644 septa-fare-calculator/src/components/ErrorComponent.test.tsx create mode 100644 septa-fare-calculator/src/components/ErrorComponent.tsx create mode 100644 septa-fare-calculator/src/components/FareCalculator.module.scss create mode 100644 septa-fare-calculator/src/components/FareCalculator.test.tsx create mode 100644 septa-fare-calculator/src/components/FareCalculator.tsx create mode 100644 septa-fare-calculator/src/components/HeaderComponent.module.scss create mode 100644 septa-fare-calculator/src/components/HeaderComponent.test.tsx create mode 100644 septa-fare-calculator/src/components/HeaderComponent.tsx create mode 100644 septa-fare-calculator/src/index.css create mode 100644 septa-fare-calculator/src/main.tsx create mode 100644 septa-fare-calculator/src/scss-modules.d.ts create mode 100644 septa-fare-calculator/src/styles/_settings.mixins.scss create mode 100644 septa-fare-calculator/src/styles/_settings.variables.scss create mode 100644 septa-fare-calculator/src/test-setup.ts create mode 100644 septa-fare-calculator/src/test-types.d.ts create mode 100644 septa-fare-calculator/tsconfig.app.json create mode 100644 septa-fare-calculator/tsconfig.json create mode 100644 septa-fare-calculator/tsconfig.node.json create mode 100644 septa-fare-calculator/vite.config.ts diff --git a/septa-fare-calculator/.gitignore b/septa-fare-calculator/.gitignore new file mode 100644 index 000000000..2e704807e --- /dev/null +++ b/septa-fare-calculator/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + + +node_modules +coverage +dist +dist-ssr +*.local +package-lock.json +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/septa-fare-calculator/README.md b/septa-fare-calculator/README.md index 5b0bd5ee6..773873984 100644 --- a/septa-fare-calculator/README.md +++ b/septa-fare-calculator/README.md @@ -1,3 +1,5 @@ +#Please view the Solution_README.md file to see the solution. I have left this README.md file intact to reflect the requirements. + # SEPTA Rail Fare Calculator Challenge Hello, hopeful Think Company development team member! @@ -6,11 +8,11 @@ Thank you for taking time to help us assess your front-end development skills. P Your challenge is to create an interactive widget for calculating SEPTA Regional Rail fare prices. (In case you're not familiar with Philadelphia's preeminent mass transit agency, here are all the railroads in map form.) -![SEPTA Zone Map](img/zone-map.jpg) +![SEPTA Zone Map](assets/img/zone-map.jpg) When you take regional rail in and out of the city, the fare price is affected by where you purchase the ticket, when you ride, and how far you travel. You can learn more about the details on [SEPTA's website](http://www.septa.org/fares/ticket/index.html) -- or trust that we've correctly compiled this information into this [JSON file](fares.json). We'd like you to make this information easier to understand by making an interactive fare purchase widget, illustrated in the screenshot below. -![Widget mockup](img/widget.png) +![Widget mockup](assets/img/widget.png) ## Instructions * Visit our [careers page](https://www.thinkcompany.com/careers/) and apply for one of our open positions so we have your contact information along with your pull request. @@ -31,3 +33,78 @@ When you take regional rail in and out of the city, the fare price is affected b * [Think Company Development Standards](https://standards.thinkcompany.dev/) * [SEPTA Fares](http://www.septa.org/fares/ticket/index.html) * [SEPTA Logo (SVG)](https://commons.wikimedia.org/wiki/File:SEPTA.svg) + + +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## React Compiler + +The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + + // Remove tseslint.configs.recommended and replace with this + tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + tseslint.configs.stylisticTypeChecked, + + // Other configs... + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + // Enable lint rules for React + reactX.configs['recommended-typescript'], + // Enable lint rules for React DOM + reactDom.configs.recommended, + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]) +``` diff --git a/septa-fare-calculator/SOLUTION_README.md b/septa-fare-calculator/SOLUTION_README.md new file mode 100644 index 000000000..f1e9de3d1 --- /dev/null +++ b/septa-fare-calculator/SOLUTION_README.md @@ -0,0 +1,848 @@ + + +# Solution to the Septa-Fare-Calculator, by Adam Oliver +Email: adam.carle.oliver@gmail.com + +## Solution: React with Typescript, Vite, Jest and Jest-axe for testing +I opted to use the Vite engine for React as it offerred better control and out of the box capability over other solutions like the CreateReactApp CLI. + +## running the code +1. Clone the branch/code base +2. Navigate to the septa-fare-calculator folder +3. Install dependencies (npm install) +4. Run applicaiton + +To run tests: +1. Clone the branch/code base +2. Navigate to the septa-fare-calculator folder +3. install dependencies (npm install) +4. In the console, run `npm run test` +5. To examine test coverage, use the terminal and enter `npm run test:coverage` + + +## The coding approach: +- Determine the functional requirements +- Establish baseline UI (HTML/CSS) with dummy text +- Determine what tests are useful for the functional logic +- Write code that passes the unit tests +- Use AI to review code according to company standards (.curor/rules files available upon request) +- Total time spent: 3.5 hours (The extra time was spent conforming to standards of ThinkCompany) + +## Result +- 59 tests +- 93% test coverage +- Functional requirements met +- UI requirements met +- Accessibility requirements met +- Conforming to the ThinkCompany standards + +## Npm packages for production: +- react 19.1.1 +- react-dom: 19.1.1 +- sass": 1.93.2 + +### Now the fun part... and where I spent the most time +Prior to writing the widget code, I realized there was no way for me to digest and incorporate all the standards that are requested in the short period of time I was to spend writing the widget. I opted to take a 'clean-up' approach to complying with the standards, i.e. after writing the widget, I would go and incorporate the standards of ThinkCompany into the code. I was surprised by how closely my coding style matched the requirements, actually. + +In order to be as fully compliant as possible in the time available to me, I opted to do the following at the end of my time and refactor accordingly: +1. Determine context and rules for AI assistant (20-30 minutes) + - Use ChatGPT and Claude to distill the standards into several 'rules' files for my CursorAI agent - available upon request +2. Ask the AI Agent "Does the app conform to the instructions located in the folder @.cursor/_Rule_Name_?" + - Went rule-by-rule to ensure I understood any deltas between my code and the standards +3. Asked the AI Agent to review my tests to ensure functional coverage +4. Asked the AI Agent for a full compliance report with the rules I had set up based on the company standards + +### Compliance Report +For fun, I asked the AI Agent to create a compliance report based on my rules files and the ThinkCompany standards. I opted not to fix the minor issues just becuase of time constraints, but left them in the compliance report. + +Here are the result: + +# SEPTA Fare Calculator - ThinkCompany Coding Standards Compliance Report +## Complete Review Against All Cursor Rules + +**Date:** 8 Oct, 2025 +**Project:** SEPTA Regional Rail Fare Calculator +**Reviewed Against:** All rules in `.cursor/rules/` folder + +--- + +## 🎯 Executive Summary + +**Overall Compliance Score: 97.3%** ✅ + +**Status:** ✅ **PRODUCTION READY - EXCEEDS STANDARDS** + +``` +Test Results: ✅ 59/59 passing (100%) +Code Coverage: ✅ 93.42% (exceeds 90% target) +Build Status: ✅ Success in 1.50s +Bundle Size: ✅ 205.27 kB JS (66.69 kB gzipped) +Linter Errors: ✅ 0 +Warnings: ✅ 0 +``` + +--- + +## 📊 Compliance by Rule Category + +| Rule File | Compliance | Grade | Status | +|-----------|-----------|-------|--------| +| **accessibility_rules.mdc** | 100% | A+ | ✅ Perfect | +| **sass_rules.mdc** | 100% | A+ | ✅ Perfect | +| **css_rules.mdc** | 100% | A+ | ✅ Perfect | +| **react_typescript_rules.mdc** | 98% | A+ | ✅ Excellent | +| **javascript_rules.mdc** | 98% | A+ | ✅ Excellent | +| **html_rules.mdc** | 96% | A+ | ✅ Excellent | +| **performance_rules.mdc** | 95% | A | ✅ Very Good | +| **Overall** | **97.3%** | **A+** | **✅ Exceptional** | + +--- + +## Detailed Compliance Analysis + +### 1. Accessibility Rules ✅ **100%** (Perfect) + +#### ✅ All Requirements Met + +**Document Structure & Semantics:** +- ✅ `` specified +- ✅ Semantic HTML5 elements (`
`, `
`, `
`, ``, ``) +- ✅ One `

` per component +- ✅ Logical heading hierarchy maintained +- ✅ Viewport meta without `maximum-scale` or `user-scalable=no` + +**Keyboard Accessibility:** +- ✅ All interactive elements keyboard accessible +- ✅ Visible focus states with `:focus-visible` +- ✅ Tab order follows logical visual order +- ✅ No positive tabindex values + +**Forms:** +- ✅ All form fields have associated `