-
Notifications
You must be signed in to change notification settings - Fork 4
Add ability to select multiple needs for the Add / Edit Student Modal #503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
dc576f1
a6c9f30
684e450
599a1e2
c9dc92f
fda37b3
01c1798
8248657
817b71a
a7ceeef
4c634a6
ccf39b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| .dropdown-wrapper { | ||
| position: relative; | ||
| } | ||
|
|
||
| .dropdown-header { | ||
| background-color: rgb(255, 255, 255); | ||
| border: 1px solid #000000; | ||
| padding: 8px; | ||
| cursor: pointer; | ||
| max-width: 200px; /* Adjust width as needed */ | ||
| height: 31px; | ||
| border-radius: 0.25rem; | ||
| } | ||
|
|
||
| .dropdown-list { | ||
| position: absolute; | ||
| top: calc(100% + 5px); | ||
| left: 0; | ||
| background-color: rgba(234, 233, 233); /* Grey color with 30% opacity */ | ||
| border: 1px solid #ccc; | ||
| padding: 12px; | ||
| max-height: 400px; /* Adjust max-height as needed */ | ||
| overflow-y: auto; | ||
| z-index: 1000; | ||
| border-radius: 12px; | ||
| box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* Adding drop shadow */ | ||
| } | ||
|
|
||
| .dropdown-list-item { | ||
| display: flex; | ||
| align-items: center; | ||
| margin-bottom: 5px; | ||
| cursor: pointer; | ||
| } | ||
|
|
||
| .item-checkbox { | ||
| width: 12px; | ||
| height: 12px; | ||
| border: 1.5px solid #ccc; | ||
| margin-right: 5px; | ||
| border-radius: 3px; | ||
| position: relative; | ||
| background-color: white; | ||
| } | ||
|
|
||
| .item-checkbox-selected::after { | ||
|
||
| content: '✔'; | ||
| font-size: xx-small; | ||
| position: absolute; | ||
| top: 50%; | ||
| left: 50%; | ||
| transform: translate(-50%, -50%); | ||
| color: white; | ||
| } | ||
|
|
||
| .item-checkbox-selected { | ||
| background-color: rgba(3, 117, 251); | ||
| } | ||
|
|
||
| .item-name { | ||
| font-size: small; | ||
| } | ||
| .dropdown-list-confirm { | ||
| height: 30px; | ||
| width: 60px; | ||
| border-radius: 20px; | ||
| border: 2px solid rgba(158, 158, 158); | ||
| margin-left: 50%; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| import React, { useState } from 'react'; | ||
| import './DropdownBox.css'; | ||
|
|
||
| type DropdownBoxProps = { | ||
| placeHolderText: string; | ||
| dataSource: Array<string>; | ||
| isOpen: boolean; | ||
| confirmText: string; | ||
| }; | ||
|
|
||
| const DropdownBox = ({ | ||
| placeHolderText, | ||
| dataSource, | ||
| isOpen, | ||
| confirmText, | ||
| }: DropdownBoxProps) => { | ||
| const [isDropdownBoxOpen, setIsDropdownBoxOpen] = useState(isOpen); | ||
| const [selectedItems, setSelectedItems] = useState(new Set<string>()); | ||
|
|
||
| const toggleDropdownBox = () => { | ||
| setIsDropdownBoxOpen(!isDropdownBoxOpen); | ||
| }; | ||
|
|
||
| const toggleSelectItem = (itemName: string) => { | ||
| const newSelectedItems = new Set(selectedItems); | ||
| if (newSelectedItems.has(itemName)) { | ||
| newSelectedItems.delete(itemName); | ||
| } else { | ||
| newSelectedItems.add(itemName); | ||
| } | ||
| setSelectedItems(newSelectedItems); | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="dropdown-wrapper"> | ||
| <button | ||
| type="button" | ||
| className="dropdown-header" | ||
| onClick={toggleDropdownBox} | ||
| > | ||
| <div className="dropdown-header-contents"> | ||
| {placeHolderText} | ||
| {' '} | ||
|
||
| {isDropdownBoxOpen ? '⇈' : '⇊'} | ||
|
||
| </div> | ||
| </button> | ||
|
|
||
| {isDropdownBoxOpen && ( | ||
| <> | ||
| <div className="dropdown-list"> | ||
|
||
| {dataSource.map((itemName) => ( | ||
| <div | ||
| key={itemName} | ||
| className={`dropdown-list-item ${ | ||
| selectedItems.has(itemName) ? 'item-selected' : '' | ||
| }`} | ||
| onClick={() => toggleSelectItem(itemName)} | ||
| > | ||
| <div | ||
| className={`item-checkbox ${ | ||
| selectedItems.has(itemName) ? 'item-checkbox-selected' : '' | ||
| }`} | ||
| /> | ||
| <div className="item-name">{itemName}</div> | ||
| </div> | ||
| ))} | ||
| <button | ||
| type="button" | ||
| className="dropdown-list-confirm" | ||
| onClick={toggleDropdownBox} | ||
| > | ||
| {confirmText} | ||
| </button> | ||
| </div> | ||
| </> | ||
| )} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default DropdownBox; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,8 @@ import cn from 'classnames'; | |
| import { Button, Input, Label } from '../FormElements/FormElements'; | ||
| import styles from './ridermodal.module.css'; | ||
| import { ObjectType, Accessibility, Rider } from '../../types/index'; | ||
| import { useState } from 'react'; | ||
| import DropdownBox from '../DropdownBox/DropdownBox'; | ||
|
|
||
| type ModalFormProps = { | ||
| onSubmit: (data: ObjectType) => void; | ||
|
|
@@ -63,7 +65,6 @@ const RiderModalInfo = ({ | |
| const localUserType = localStorage.getItem('userType'); | ||
| const isEditing = rider !== undefined; | ||
| const isStudentEditing = isEditing && localUserType === 'Rider'; | ||
|
|
||
| return ( | ||
| <form onSubmit={handleSubmit(beforeSubmit)} className={styles.form}> | ||
| <div className={cn(styles.inputContainer, styles.rideTime)}> | ||
|
|
@@ -131,22 +132,15 @@ const RiderModalInfo = ({ | |
| )} | ||
| </div> | ||
| <div className={cn(styles.gridR2, styles.gridCBig1)}> | ||
| <Label className={styles.label} htmlFor="needs"> | ||
| Needs:{' '} | ||
| </Label> | ||
| <select | ||
| name="needs" | ||
| aria-required="true" | ||
| ref={register({ required: true })} | ||
| > | ||
| {Object.values(Accessibility).map((value, index) => { | ||
| return ( | ||
| <option key={index} value={value}> | ||
| {value} | ||
| </option> | ||
| ); | ||
| })} | ||
| </select> | ||
| Needs: | ||
|
||
| <DropdownBox | ||
| placeHolderText="Select Your Needs" | ||
| dataSource={Object.values(Accessibility) | ||
| .splice(1) | ||
|
||
| .map((value, _) => value.toString())} | ||
| isOpen={false} | ||
| confirmText="Next" | ||
| /> | ||
| {errors.needs?.type === 'validate' && ( | ||
| <p className={styles.error}> | ||
| Invalid needs. You can enter 'Assistant', 'Crutches', or | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed there's quite a few hardcoded CSS px values. Its usually a more accessible choice and better for responsivity to consider using relative sizing like
rem,emetc for windows, columns, fonts. Pixel values are best for borders and things that are not guaranteed to change.Your margins, heights and widths should not use hardcoded pixel values. Its still mostly opinion based but my suggestion is if you stick to px values then you should add media-queries for the different device sizes
https://stackoverflow.com/questions/11799236/should-i-use-px-or-rem-value-units-in-my-css
https://wpengine.com/resources/choose-css-unit-create-better-site-layouts-how-to/#Absolute_CSS_Units