Skip to content

Commit b5ff4c5

Browse files
committed
Clicking outside closes Add year & course popovers
1 parent 2b697d8 commit b5ff4c5

File tree

2 files changed

+111
-117
lines changed

2 files changed

+111
-117
lines changed

site/src/pages/RoadmapPage/AddYearPopup.tsx

+82-86
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import React, { FC, useState, useRef, useEffect } from 'react';
1+
import React, { FC, useState, useEffect } from 'react';
22
import './AddYearPopup.scss';
33
import { PlusCircleFill } from 'react-bootstrap-icons';
4-
import { Button, Form, Popover, Overlay } from 'react-bootstrap';
4+
import { Button, Form, Popover, OverlayTrigger } from 'react-bootstrap';
55
import { addYear } from '../../store/slices/roadmapSlice';
66
import { useAppDispatch } from '../../store/hooks';
77

@@ -16,99 +16,95 @@ const AddYearPopup: FC<AddYearPopupProps> = ({ placeholderName, placeholderYear
1616
const [year, setYear] = useState(placeholderYear);
1717
const [validated, setValidated] = useState(false);
1818
const [show, setShow] = useState(false);
19-
const target = useRef(null);
2019

2120
useEffect(() => {
2221
setYear(placeholderYear);
2322
setName(placeholderName);
2423
}, [placeholderYear, placeholderName]);
2524

26-
const handleClick = () => {
27-
setShow(!show);
28-
};
25+
const overlay = <Popover id="add-year-popover">
26+
<Popover.Content>
27+
<Form noValidate validated={validated}>
28+
<Form.Group>
29+
<Form.Label className="add-year-form-label">Name</Form.Label>
30+
<Form.Control
31+
required
32+
type="text"
33+
name="name"
34+
value={name}
35+
onChange={(e) => {
36+
setName(e.target.value);
37+
}}
38+
onKeyDown={(e: React.KeyboardEvent) => {
39+
// prevent submitting form (reloads the page)
40+
if (e.key === 'Enter') {
41+
e.preventDefault();
42+
}
43+
}}
44+
maxLength={35}
45+
placeholder={placeholderName}
46+
></Form.Control>
47+
</Form.Group>
48+
<Form.Group>
49+
<Form.Label className="add-year-form-label">Start Year</Form.Label>
50+
<Form.Control
51+
required
52+
type="number"
53+
name="year"
54+
value={year}
55+
onChange={(e) => {
56+
setYear(parseInt(e.target.value));
57+
}}
58+
onKeyDown={(e: React.KeyboardEvent) => {
59+
// prevent submitting form (reloads the page)
60+
if (e.key === 'Enter') {
61+
e.preventDefault();
62+
}
63+
}}
64+
min={1000}
65+
max={9999}
66+
placeholder={placeholderYear.toString()}
67+
></Form.Control>
68+
</Form.Group>
69+
<Button
70+
className="popup-btn"
71+
onClick={() => {
72+
if (name === '' || year < 1000 || year > 9999 || Number.isNaN(year)) {
73+
setValidated(true);
74+
return;
75+
}
76+
77+
setValidated(false);
78+
setShow(!show);
79+
dispatch(
80+
addYear({
81+
yearData: {
82+
startYear: year,
83+
name: name.trim(),
84+
quarters: ['fall', 'winter', 'spring'].map((quarter) => {
85+
return { name: quarter, courses: [] };
86+
}),
87+
},
88+
}),
89+
);
90+
setYear(placeholderYear);
91+
setName(placeholderName);
92+
}}
93+
>
94+
Add Year
95+
</Button>
96+
</Form>
97+
</Popover.Content>
98+
</Popover>
2999

30100
return (
31101
<div>
32-
<Button variant="light" ref={target} className="add-year-btn" onClick={handleClick}>
33-
<PlusCircleFill className="add-year-icon" />
34-
<div className="add-year-text">Add year</div>
35-
</Button>
36-
<Overlay show={show} target={target} placement="top">
37-
<Popover id="">
38-
<Popover.Content>
39-
<Form noValidate validated={validated}>
40-
<Form.Group>
41-
<Form.Label className="add-year-form-label">Name</Form.Label>
42-
<Form.Control
43-
required
44-
type="text"
45-
name="name"
46-
value={name}
47-
onChange={(e) => {
48-
setName(e.target.value);
49-
}}
50-
onKeyDown={(e: React.KeyboardEvent) => {
51-
// prevent submitting form (reloads the page)
52-
if (e.key === 'Enter') {
53-
e.preventDefault();
54-
}
55-
}}
56-
maxLength={35}
57-
placeholder={placeholderName}
58-
></Form.Control>
59-
</Form.Group>
60-
<Form.Group>
61-
<Form.Label className="add-year-form-label">Start Year</Form.Label>
62-
<Form.Control
63-
required
64-
type="number"
65-
name="year"
66-
value={year}
67-
onChange={(e) => {
68-
setYear(parseInt(e.target.value));
69-
}}
70-
onKeyDown={(e: React.KeyboardEvent) => {
71-
// prevent submitting form (reloads the page)
72-
if (e.key === 'Enter') {
73-
e.preventDefault();
74-
}
75-
}}
76-
min={1000}
77-
max={9999}
78-
placeholder={placeholderYear.toString()}
79-
></Form.Control>
80-
</Form.Group>
81-
<Button
82-
className="popup-btn"
83-
onClick={() => {
84-
if (name === '' || year < 1000 || year > 9999 || Number.isNaN(year)) {
85-
setValidated(true);
86-
return;
87-
}
88-
89-
setValidated(false);
90-
setShow(!show);
91-
dispatch(
92-
addYear({
93-
yearData: {
94-
startYear: year,
95-
name: name.trim(),
96-
quarters: ['fall', 'winter', 'spring'].map((quarter) => {
97-
return { name: quarter, courses: [] };
98-
}),
99-
},
100-
}),
101-
);
102-
setYear(placeholderYear);
103-
setName(placeholderName);
104-
}}
105-
>
106-
Add Year
107-
</Button>
108-
</Form>
109-
</Popover.Content>
110-
</Popover>
111-
</Overlay>
102+
<OverlayTrigger placement="top" overlay={overlay} trigger={['click']} rootClose>
103+
<Button variant="light" className="add-year-btn">
104+
<PlusCircleFill className="add-year-icon" />
105+
<div className="add-year-text">Add year</div>
106+
</Button>
107+
</OverlayTrigger>
112108
</div>
113109
);
114110
};

site/src/pages/RoadmapPage/Quarter.tsx

+29-31
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Course from './Course';
66
import { useAppDispatch, useAppSelector } from '../../store/hooks';
77
import { deleteQuarter, clearQuarter, deleteCourse } from '../../store/slices/roadmapSlice';
88
import { PlannerQuarterData } from '../../types/types';
9-
import { Button, Overlay, Popover } from 'react-bootstrap';
9+
import { Button, OverlayTrigger, Popover } from 'react-bootstrap';
1010
import { ThreeDots } from 'react-bootstrap-icons';
1111
import { StrictModeDroppable } from './StrictModeDroppable';
1212

@@ -23,11 +23,8 @@ const Quarter: FC<QuarterProps> = ({ year, yearIndex, quarterIndex, data }) => {
2323
const invalidCourses = useAppSelector((state) => state.roadmap.invalidCourses);
2424

2525
const [showQuarterMenu, setShowQuarterMenu] = useState(false);
26-
const [threeDotMenuTarget, setThreeDotMenuTarget] = useState<HTMLElement | null>(null);
27-
28-
const handleQuarterMenuClick = (event: React.MouseEvent) => {
26+
const handleQuarterMenuClick = () => {
2927
setShowQuarterMenu(!showQuarterMenu);
30-
setThreeDotMenuTarget(event.target as HTMLElement);
3128
};
3229

3330
const calculateQuarterStats = () => {
@@ -90,38 +87,39 @@ const Quarter: FC<QuarterProps> = ({ year, yearIndex, quarterIndex, data }) => {
9087
});
9188
};
9289

90+
const popover = <Popover id={`quarter-menu-${yearIndex}-${quarterIndex}`}>
91+
<Popover.Content>
92+
<div>
93+
<Button
94+
variant="light"
95+
className="quarter-menu-btn red-menu-btn"
96+
onClick={() => dispatch(clearQuarter({ yearIndex: yearIndex, quarterIndex: quarterIndex }))}
97+
>
98+
Clear
99+
</Button>
100+
<Button
101+
variant="light"
102+
className="quarter-menu-btn red-menu-btn"
103+
onClick={() => {
104+
dispatch(deleteQuarter({ yearIndex: yearIndex, quarterIndex: quarterIndex }));
105+
setShowQuarterMenu(false);
106+
}}
107+
>
108+
Delete
109+
</Button>
110+
</div>
111+
</Popover.Content>
112+
</Popover>
113+
93114
return (
94115
<div className="quarter">
95116
<span className="quarter-header">
96117
<h2 className="quarter-title">
97118
{quarterTitle} {year}
98119
</h2>
99-
<ThreeDots onClick={handleQuarterMenuClick} className="edit-btn" />
100-
<Overlay show={showQuarterMenu} target={threeDotMenuTarget} placement="bottom">
101-
<Popover id={`quarter-menu-${yearIndex}-${quarterIndex}`}>
102-
<Popover.Content>
103-
<div>
104-
<Button
105-
variant="light"
106-
className="quarter-menu-btn red-menu-btn"
107-
onClick={() => dispatch(clearQuarter({ yearIndex: yearIndex, quarterIndex: quarterIndex }))}
108-
>
109-
Clear
110-
</Button>
111-
<Button
112-
variant="light"
113-
className="quarter-menu-btn red-menu-btn"
114-
onClick={() => {
115-
dispatch(deleteQuarter({ yearIndex: yearIndex, quarterIndex: quarterIndex }));
116-
setShowQuarterMenu(false);
117-
}}
118-
>
119-
Delete
120-
</Button>
121-
</div>
122-
</Popover.Content>
123-
</Popover>
124-
</Overlay>
120+
<OverlayTrigger trigger="click" overlay={popover} rootClose onToggle={setShowQuarterMenu} show={showQuarterMenu}>
121+
<ThreeDots onClick={handleQuarterMenuClick} className="edit-btn" />
122+
</OverlayTrigger>
125123
</span>
126124
<div className="quarter-units">
127125
{unitCount} {unitCount === 1 ? 'unit' : 'units'}

0 commit comments

Comments
 (0)