Skip to content

Commit eedaa8f

Browse files
committed
Implement note sharing
* Make DELETE request and "Remove" button for removing access; update UI * Make POST request and "Share" button for adding access; update UI * Make search case-insensitive using .toLocaleLowerCase() * Remove outline from search because it looks bad for mouse users * Implement ShareMenu and ShareList components * Implement useEscapeAlerter() hook - closes Jotting when user presses escape * Split columns up more for home to add more width to share menu * Add alt and title attributes to *OptionsBar components for accessibility
1 parent f413a83 commit eedaa8f

18 files changed

Lines changed: 314 additions & 132 deletions

components/AccountBanner/accountBanner.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.accountBanner {
22
grid-row: 1 / 3;
3-
grid-column-end: 7;
3+
grid-column-end: -1;
44
align-self: stretch;
55
margin-left: 10px;
66
}

components/Jotting/JottingOptionsBar.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ export default function JottingOptionsBar(props) {
1919
return (
2020
<div className={jotting.jottingOptionsBar}>
2121
<button onClick={handleDeleteClick}>
22-
<Image height={32} width={32} src="/images/trash.png" />
22+
<Image height={32} width={32} src="/images/trash.png" alt="Delete icon" title="Delete jotting" />
2323
</button>
2424
<button onClick={handlePinClick}>
25-
<Image height={32} width={32} src="/images/pin.png" />
25+
<Image height={32} width={32} src="/images/pin.png" alt="Pin icon" title="Pin jotting" />
2626
</button>
2727
{props.children}
2828
</div>

components/Jotting/jotting.module.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@
4242
display: flex;
4343
flex-direction: row;
4444
justify-content: center;
45+
align-items: center;
4546
height: 100px;
4647
}
4748

4849
.jottingOptionsBar button {
4950
background: none;
5051
border: none;
5152
margin: 0 1em;
53+
padding: 1em;
5254
}
5355

5456
.jottingOptionsBar button:hover {

components/Jotting/jottingTitle.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { updateJottingTitle } from "../../libs/Datastore/requests";
77
* @param props.id The id of the jotting
88
* @param props.originalTitle The title passed as a prop to this component
99
*/
10-
export default function JottingTitle({ id, originalTitle, jotType }) {
10+
export default function JottingTitle({ id, originalTitle = "", jotType }) {
1111
const [title, setTitle] = useState(originalTitle);
1212

1313
const ref = useRef(null);
@@ -40,6 +40,7 @@ export default function JottingTitle({ id, originalTitle, jotType }) {
4040
<input
4141
ref={ref}
4242
type="text"
43+
name="title"
4344
className={jottingStyleMod.title}
4445
value={title}
4546
onChange={handleTitleChange}

components/Jotting/noteOptionsBar.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default function NoteOptionsBar(props) {
1414
return (
1515
<JottingOptionsBar {...props}>
1616
<button onClick={handleShareClick}>
17-
<Image height={35} width={55} src="/images/share.png" />
17+
<Image height={35} width={55} src="/images/share.png" alt="share icon" title="Share jotting" />
1818
</button>
1919
</JottingOptionsBar>
2020
);

components/JottingList/noteList.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ export default function NoteList({ notes }) {
99
noteList = notes
1010
.filter((item) => {
1111
const urlParser = new URLSearchParams(location.search);
12-
return !urlParser.has("q") || item.title.includes(urlParser.get("q"));
12+
return (
13+
!urlParser.has("q") ||
14+
item.title.toLocaleLowerCase().includes(urlParser.get("q").toLocaleLowerCase())
15+
);
1316
})
1417
.map((item) => (
1518
<li key={item.id}>

components/JottingList/taskList.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default function TaskList({ tasks }) {
1111
const urlParser = new URLSearchParams(location.search);
1212
return (
1313
!urlParser.has("q") ||
14-
item.title.includes(urlParser.get("q"))
14+
item.title.toLocaleLowerCase().includes(urlParser.get("q").toLocaleLowerCase())
1515
);
1616
})
1717
.map((item) => (

components/SearchBar/searchBar.js

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@ import { useRouter } from "next/router";
33
import UrlService from "../../libs/UrlService";
44

55
export default function SearchBar() {
6-
const router = useRouter();
7-
const urlService = new UrlService(router);
6+
const router = useRouter();
7+
const urlService = new UrlService(router);
88

9-
const handleSearch = e => {
10-
urlService.changeQuery({q: e.target.value});
11-
};
9+
const handleSearch = (e) => {
10+
urlService.changeQuery({ q: e.target.value });
11+
};
1212

13-
return (
14-
<div className={searchBar.container}>
15-
<button className={searchBar.searchBarIcon}>
16-
<img
17-
className={searchBar.greyCircle}
18-
src="https://cdn.jsdelivr.net/gh/Borumer/Borum@v1.2.0/staticassets/images/search-bar-icon.png"
19-
id="search-bar-icon-img"
20-
/>
21-
</button>
22-
<input
23-
className={searchBar.searchBar}
24-
type="text"
25-
onChange={handleSearch}
26-
placeholder="Search your Jottings"
27-
/>
28-
</div>
29-
);
13+
return (
14+
<div className={searchBar.container}>
15+
<button className={searchBar.searchBarIcon}>
16+
<img
17+
className={searchBar.greyCircle}
18+
src="https://cdn.jsdelivr.net/gh/Borumer/Borum@v1.2.0/staticassets/images/search-bar-icon.png"
19+
id="search-bar-icon-img"
20+
/>
21+
</button>
22+
<input
23+
className={searchBar.searchBar}
24+
type="text"
25+
onChange={handleSearch}
26+
placeholder="Search your Jottings"
27+
/>
28+
</div>
29+
);
3030
}

components/SearchBar/searchBar.module.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
display: none;
3333
height: 40px;
3434
width: 90%;
35+
outline: none;
3536
}
3637

3738
@media only screen and (min-width: 511px) {

components/ShareMenu/shareMenu.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import shareMenu from "./shareMenu.module.css";
2+
import { useRef, useState, useEffect } from "react";
3+
import { useRouter } from "next/router";
4+
import { shareNote, getNoteSharees } from "../../libs/Datastore/requests";
5+
import ShareeList from "../ShareeList/shareeList";
6+
import { useCancelableRequest } from "../../libs/Datastore/responseHelpers";
7+
8+
export default function ShareMenu() {
9+
const [noteSharees, setNoteSharees] = useState(null);
10+
const [recipientEmail, setRecipientEmail] = useState("");
11+
12+
const ref = useRef(null);
13+
const router = useRouter();
14+
15+
const abortController = new AbortController();
16+
17+
const handleShareClick = (e) => {
18+
shareNote(router.query.id, recipientEmail, abortController)
19+
setRecipientEmail("");
20+
setNoteSharees([...noteSharees, {
21+
email: recipientEmail,
22+
user_id: 0
23+
}]);
24+
};
25+
26+
const handleRecipientEmailChange = (e) => setRecipientEmail(e.target.value);
27+
28+
useEffect(() => {
29+
ref.current.focus();
30+
}, []);
31+
32+
useCancelableRequest(getNoteSharees, setNoteSharees, [router.query.id], []);
33+
34+
return (
35+
<div className={shareMenu.shareMenu}>
36+
<h1>Share</h1>
37+
<ShareeList noteSharees={noteSharees} setNoteSharees={setNoteSharees} />
38+
<input
39+
type="text"
40+
ref={ref}
41+
value={recipientEmail}
42+
onChange={handleRecipientEmailChange}
43+
placeholder="Recipient's email"
44+
aria-placeholder="Recipient's email"
45+
/>
46+
<button onClick={handleShareClick}>Share</button>
47+
</div>
48+
);
49+
}

0 commit comments

Comments
 (0)